Command reference
oko tasks list
Lists operator requests with their independent verdict and derived completion standing; a done verdict without qualified source and observed result remains an open claim.
Invocation#
oko tasks (--open [--hours N] | --session ID ...) [--read-only [--owed]] [--json] [--full]Inputs and options#
- --open selects every live session on this machine. --hours N limits that selection to transcripts modified in the last N hours; no hours means the whole history. --session selects one exact session and may repeat.
- A negative --hours is refused. --json selects structured output; --full prints each task's whole text.
- --read-only does not write the ledger; it still reads each selected live transcript and its shared-database task evidence.
- --owed (with --read-only) answers only open work: the selected sessions that hold a not-done task, without their unread messages, plus every --session named, whole. It settles only the sessions the shared database holds a task reading or a task addition for, chosen from those two tables' session keys and read each by its key; a session holding neither has no task and is not read.
Output and state effect#
- Reads each selected transcript and the shared task evidence, printing each identity, status, derived standing, cause and source. The standing counts per selected session include open, claimed, verified, withdrawn and refused. `--owed` retains claims because their status is not done. A historical done verdict missing its check is shown as claimed without changing the old verdict; later operator corrections still take precedence.
- Without `--read-only` a listing writes the ledger of each selected session only when it would differ from the one this machine last wrote: the kept settlement (~/.oko/cache/settled/<session>.json) records digests of the operator messages and of what the register held about them, with the build that wrote it, and a session whose digests are those of the reading in hand is neither reconciled nor written again. The ledgers that are written are written side by side. Rewriting every unchanged ledger, one round of reads, deletes and upserts after another, kept a writing listing of every live session running for hours. With OKO_TRACE_REQUESTS=1 the settle phase says `settle <n> sessions (<k> from kept settlements, <w> ledgers written)`. The real `tasks-unchanged-ledgers` test lists one session no agent is writing to twice (OKO_TEST_SESSION) and requires the second listing to write no ledger and answer the same tasks.
- A task is an object with its own identity: `task-` and sixteen hex digits, derived from the session and the id the harness wrote on the operator’s message, so it is the same after every reindex and in every session that names it. The number beside it is only the task’s place among that session’s operator messages and moves when the ledger is rebuilt from another copy of the transcript, so evidence and verdicts keyed by that number would point at other sentences after a renumbering. Claims, evidence, verdicts, judge outages and defects carry the identity, and a row recorded before identities existed is matched by its number until its session is refreshed. A harness that writes no message id derives the identity from the message’s time and text.
- Every task has a kind: `task` for an instruction, `defect` for a reported failure that reopens one; a defect carries `parentId`, the task it repairs. JSON output adds `id`, `kind` and `parentId` to each task.
- A task can be related to another: `duplicate-of`, `follows`, `blocked-by` or `part-of`, recorded with oko tasks relate. Every listing shows each task’s relations from its own side (`duplicated-by`, `precedes`, `blocks`, `has-part` for the other end) with the other task’s state, and its effect: a duplicate is `done` when its original is done and waits while it is open; a task that follows or is blocked by an open task waits on it (`waitingOn` in JSON, “waiting on” in the reason); a task with open parts says how many. A waiting task is not handed over by oko tasks control until what it waits on closes. The other side of a relation in another session has its state read from that session’s ledger. The other side that is a registered defect (`defect-` and its short id) has its state read from the defect register — `not done` while the defect is open, `done` once it is closed or withdrawn — and one listing reads that register once for every defect end of every session it reports, never once per relation, so a whole-register reading (`--open --read-only --owed`, the call Tama’s gates make) is not paid for by the size of the register times the number of relations; a register that cannot be read refuses the listing by its path and the parse error.
- The live harness file is looked up by name at the depth each harness writes it — ~/.omp/agent/sessions/<project>/<file>, ~/.claude/projects/<project>/<file>, ~/.codex/sessions/<year>/<month>/<day>/<file> — and never inside the artifact folder beside an OMP transcript; a harness that names a directory after the session is looked up at the file it keeps there — ~/.jeden/sessions/<session>/transcript.jsonl, and Kimi Code’s ~/.kimi-code/sessions/<workspace>/<session>/agents/main/wire.jsonl, its operator’s own conversation, never a subagent’s agent directory. A Codex session opened through `codex exec`, the non-interactive entry point its SDK and every program drive, has no operator messages, like a session Jeden spawned itself; neither has a Codex session another Codex thread spawned as its subagent (its session_meta names the parent thread), whose user turns that parent agent wrote, and the `<subagent_notification>` such a subagent reports back through is the harness’s, not the operator’s, as are the project instructions Codex injects as a session’s first user turn (`# AGENTS.md instructions for <directory>`); a Jeden turn recorded with `modelOnly` (`jeden run --model-only`, one model call a program makes as a stage of its own work, such as pursue’s contract distillation) is not his either. Cross-session acknowledgements (ok <session-prefix> #<n>) are stored in operator_acknowledgements by the same writer that replaces a session’s messages and read from there; a report costs one session, not a regex over every ledger row. An index written before that table existed is filled once by the next ledger write or oko tasks sweep, and is read the old way until then. Either walk grows with the history and would otherwise consume the whole time a Tama Stop guard has for its decision.
- Human OMP messages delivered during an ongoing turn count as operator messages when the native message carries steering=true and attribution=user. Runtime steering and unattributed steering remain metadata, not work orders. The next read rebuilds older cached ledgers that excluded human steering, including when the transcript has not grown. Task identities, statements, evidence and verdicts remain attached to their original message ids.
- Only complete JSONL records advance the saved reading position. A message still being written is read after its line completes rather than being lost between two reads.
- What each operator message is to the ledger — work of its own, a detail added to earlier work, “do it” for the previous message, a question, an acknowledgement, a standing rule, an order for this turn, a resume, a terminal paste, a defect report or a remark — is read by Oko’s model, once per message, as a typed choice on Brama’s decision route, or by the session that received it with oko tasks kind; each kind is defined in prose by what the message does, in any language, and no word list decides it. Many messages are about one piece of work: only a message read as `task` starts a task. The reading is kept in the shared `oko_message_readings` by the message’s identity, and every listing reads the kept kind without asking a model, so a Stop gate’s reading stays inside its budget. oko tasks read and every oko tasks control pass read the messages that have no reading yet; a reading a session or the operator recorded is never read again. `classifiedBy` says who read it: “read by <route> (<confidence>)”, or “read by session:<who>”.
- A message nobody has read yet is not a task: it is listed under `unread` beside the tasks as `{ ordinals, reading }`, where `reading` is what was last seen of the reading route (`oko_judge_health`: `answering`, `checked_at`, `detail`, `observed_by`), since the reading model and the judge share it. It is not nothing either: Tama's block-stop-with-open-work holds the turn on every unread message of the session, naming that state and the `oko tasks kind` command, so an instruction written while the model cannot answer is never dropped and never turned into owed work it is not. oko tasks kind records what such a message is, by the name of the session that received it or of the operator. oko tasks add records one instruction among several in a message (`--part N`), or a message as the task it is, with `classifiedBy` “added by <who>”. A later task that repeats or extends an earlier request preserves both task identities; text overlap is not an instruction to delete or merge either task.
- A message that was read and is no task, and that found no task to be written under — a detail, question, remark, rule, order, paste, acknowledgement, go-ahead or resume given before the session’s first task — is listed under `unattached` beside the tasks, as the ordinals of those messages: the text listing prints “unattached: messages #<n>, #<m> were read as no work before this session's first task and sit on none”, JSON carries `unattached` beside `unread`, and Oko Desktop’s session shape carries the same list. It is no work owed, and it is not kept on any task either, so it is named instead of vanishing: counting the unread messages alone would take it for covered. A message read as no work in a session that has a task is written under that task, labelled, and is not listed here.
- No message or acknowledgement closes a task by its words. A done verdict or operator `close` records a completion claim; Oko derives verified standing only with a commit on main, a retained Stado behavioral test report bound to that revision, and every acceptance check met with observed evidence. Missing evidence names its cause in `claim`, keeps status not done and stays in handover and stop gates. Details, resumes, rules, questions and remarks retain their normal task attachment.
- A task spanning several repositories can retain a passing behavioral receipt for each changed source. The task evidence revision must match at least one passing report; every other report names its own repository commit on main and a retained executed test. A receipt from another repository does not invalidate the task merely for having a different commit. If none tests the evidence revision, `claim.cause` names that missing binding and the task stays open.
- A resume keeps its complete words on the task it continues, below that task’s text with its source message number and the `resume` label. Re-reading reconstructs the same task text rather than appending another copy. It creates no separate task, and naming its number through oko tasks state is refused as no task at that number. CLI task maps and Oko Desktop receive the same task text. The real tasks-message-kinds journey selects an isolated stored session with OKO_TEST_RESUME_SESSION, the earlier work number with OKO_TEST_RESUME_TASK, its genuine resume number with OKO_TEST_RESUME, the resume’s complete unique text with OKO_TEST_RESUME_TEXT and the exact checkout revision with OKO_TEST_SOURCE_REVISION. It records the genuine reading, reads the map repeatedly, checks the retained words and refusal, and keeps command results under .build/tasks/resume.
- Evidence or a done verdict alone cannot close a task. A passed source-bound fleet report with real test commands and observed acceptance results qualifies it; an old self-claimed done without them is open and claimed. `oko tasks verdict <task> --outcome withdrawn --reason TEXT --by (operator | <session>)` still records that the operator took back work, not that it was completed.
- With OKO_TRACE_REQUESTS=1 each shared-database request writes `oko supabase: <method> <path> started` when it is sent and its method, path, elapsed time and outcome to stderr when it ends, so a reading that waits names the request it waits in. A phase writes `oko phase: <operation> started` before it runs and `oko phase: <operation> <ms> ms` after it finishes. Connection subphases distinguish reading the kept resolution, asking Stado for the database, reading each credential and reading the organization. If a Stop gate interrupts the read, the last started phase identifies the operation still running; an interrupted read is not an empty task list. Every failed request names itself: `<method> <path>: Supabase REST request …`. Every shared-database connection is opened with TCP keepalive, so a connection that dies without closing is probed and ended on the operating system's own keepalive schedule and the request fails with that named error instead of waiting forever; a socket that refuses keepalive fails the request with `TCP keepalive could not be turned on for <host>: <error>`.
Refusals and safe exits#
- Refuses without --open or --session, or when --hours is negative. A named session with no live transcript refuses with its id; a transcript read failure or malformed record exits unsuccessfully. Neither becomes an empty task list.
- `--open` and `--session` are alternatives outside `--owed`: both together are refused before anything is read, `oko tasks: --open settles every live session on this machine (and writes each one's ledger without --read-only), --session ID only the sessions named; give one of them, or --open --read-only --owed --session ID for open work plus the named sessions` (exit 2). A caller after one session's open work that typed both settled every live session for hours. The real test is `tests/tasks/scope/listing.rs` (`tasks-scope-listing`).
- --read-only does not create missing shared-database rows. A failed database connection or read is reported as a refusal, not as a completed ledger. An unreadable or malformed kept resolution names ~/.oko/database.json and the failed read; `oko database check` resolves afresh and attempts to replace that resolution.