Command reference
oko tasks sweep
Writes the ledger again for every session on this machine whose live transcript changed since its ledger was last written, or whose ledger was written before the running Oko was installed (the reader compiled into an Oko decides which turns are the operator's, so a new release re-derives every ledger once), newest first, so the shared ledger follows the transcripts, and removes from every session's stored messages the turns no operator typed.
Invocation#
oko tasks sweep [--limit N] [--json]Inputs and options#
- --limit N bounds how many sessions one run writes; without it every stale session is written. The removal always covers every session.
Output and state effect#
- Stderr says before the first write how many session ledgers the sweep will write and why: `oko tasks sweep: <n> session ledger(s) to write: <a> whose transcript changed since its ledger, <b> written before this Oko was installed at <time>; writing <k> now, <r> left for a later sweep`. The first sweep after a new Oko is installed writes every ledger the older one wrote, each in several register round trips over one pooled connection, so it can run for an hour; each ledger then gets its own line, `oko tasks sweep: <i> of <k>: <session> written in <ms> ms` or `… refused after <ms> ms: <refusal>`, and a session written again after pruning `oko tasks sweep: <session> written again after pruning in <ms> ms`. Every register request inside is announced as a wait (`czekam: <METHOD> <address>; gdzie: the shared Oko database; rodzaj: baza; …`), so a sweep that is working prints a new ledger line every few seconds, while one held on a request shows that request's `czekam` line with no `koniec czekania` after it. The JSON adds `staleBecauseOlderReader`, the `<b>` of the first line: how many stale ledgers were stale only because this Oko is newer than the one that wrote them.
- Prints `refreshed`, the number of ledgers written, `failed`, each session whose ledger could not be written with its refusal, `remaining`, the stale sessions left for the next run, and `removedTurnsNoOperatorTyped`, each declared opening with how many stored turns opening with it were removed, `nestedSessionSeparator` with how many stored turns of nested sessions were removed, `sidechain` with how many stored turns Transcript Lake recorded from a subagent's file were removed, or with `refusal`, Lake's refusal, when Lake could not be asked, and `nestedFolderRoots` with how many sessions kept in session folders were found and how many of their stored turns were removed.
- A turn is not the operator's when its harness recorded another sender: a Claude Code line flagged isMeta, isCompactSummary or isSidechain (a subagent's file, whose user turns the parent agent or Claude Code wrote), or a Transcript Lake row marked `sidechain` for the same reason, an OMP turn marked steering or synthetic without user attribution, or one OMP attributes to an agent (a parent's IRC message waking a subagent). It is not his either when it opens with a harness's wrapper (`<task-notification>`, `<subagent_notification>`, `<system-reminder>`, `<command-name>` and the other tags in rust/src/tasks/transcript/sources.json) or with the exact prompt a product types into a session as if he had: the session-recovery product's “Kontynuuj dokładnie przerwaną pracę od ostatniego spójnego punktu.” (src/core/paths.cjs), Jeden's “Active work goal for this turn: ” envelope (rust/agent/conversation/turn/prompt.rs), the stage prompts of an autonomous task run Jeden starts through pursuit (src/runtime/prompts.rs: “You are the contract-distillation stage of an autonomous task run.”, the contract critic, revision, execution, acceptance review and repair stages), Tama's hook classifiers that ask a model in a session of their own (the frustration classifier “Decide whether the user message below is expressing frustration with or correction of the ”, the substantiation gate “You are a strict gate that decides whether an AI assistant just made factual claims WITHOUT grounding them in cited evidence.”, rust/crates/tama-hook-tools, and the shared hooks' premature-stop gate “You are a strict gate that decides whether an AI assistant just stopped its turn prematurely.”), OMP's advisor “### Session update” replay, its subagent IRC wake “Your current interruptible wait was interrupted because an IRC message arrived from your parent agent” and “[budget notice] You have used ”, Codex's injected “# AGENTS.md instructions for ” project instructions, Claude Code's /compact request “Your task is to create a detailed summary of the conversation so far” and “[SUGGESTION MODE: …]” prompt, Factory Droid's “Your standard model budget is exhausted.” notice and “⎿ Interrupted” marker, and Oko's own handover, which opens with the first sentence of rust/src/tasks/control/handover.json (“Twoje otwarte zadania w tej sesji, z ksiegi Oka”). Such a turn is never read as his message, so it never waits for a task in `oko tasks unread`; a product that starts typing a new prompt is added to `productOpenings` with what writes it.
- A transcript a harness keeps inside another session's folder (an OMP subagent's or its advisor's) was stored by older readers under the parent session id, `.` (`nestedSessionSeparator` in sources.json) and the file's stem, such as `<session>.__advisor` or `<session>.stado-freshness-release`, and Transcript Lake also files it under the session id its own header names. Its user turns are the parent agent's assignments or the advisor's replay of the parent session, and the live walk never enters those folders, so every stored turn of a session so named is removed, and so is every stored turn of a session whose transcript the sweep finds in a session folder (a directory beside a transcript file of the same name) under a root `nestedFolderRoots` in sources.json declares; a session that also has a live transcript of its own is left alone.
- Transcript Lake keeps a Claude Code subagent's events under its parent's session id, marked `sidechain`, and an older reading of Lake stored their user turns as the operator's; a session whose harness file is gone is never written again. The sweep asks Lake (`transcript-lake query`, or the program `OKO_TRANSCRIPT_LAKE` names) for every second in which all of a session's user turns were so marked and removes the stored turns of that session recorded in that second; a second in which the session also has an unmarked user turn is left alone.
- A ledger derived again is numbered as the live transcript numbers the operator’s turns now: each stored message carries the number the current reader gives the same turn, and keeps its text under its harness id, so a reading kept by that identity (`oko_message_readings`) points at the same words before and after; a reading’s own `ordinal` column is the number at the time it was kept. The real test is `tests/sweep/renumbered.rs`, on sessions the operator names whose stored numbering an older reader wrote.
- The real test of the progress lines is `tests/sweep/progress.rs` (`sweep-progress`): a sweep of one ledger whose scope line, ledger lines and JSON must agree and whose every `czekam` line ends, and a refused `--limit` that writes nothing.
Refusals and safe exits#
- A --limit that is not a whole number is refused by name; the shared database refusals of `oko database check`; a declared opening or separator holding a control character is refused by name (“the declared pattern <text> holds a control character”); a handover.json with no opening line is refused (“control/handover.json declares no opening line, so a stored handover cannot be recognised”); a home directory that is not set is refused (“HOME is not set, so the folders beside session transcripts cannot be found”); and a removal whose answer is unreadable names what it was removing (“removing turns that open with <opening> answered unreadable JSON: <error>”, “removing the turns of nested sessions answered unreadable JSON: <error>”, “removing the subagent turns of session <id> answered unreadable JSON: <error>”, “removing the turns of sessions kept in session folders answered unreadable JSON: <error>”). Lake that cannot be run or refuses its query does not stop the sweep: its entry carries `refusal`, such as “transcript-lake cannot be run: <error>”, and nothing is removed for it.
- An opening-prune RPC failure names the exact opening, the function and the database cause; an invalid stored sidechain timestamp names the session and ordinal rather than silently leaving that turn in the ledger.