Oko/Docs

Command reference

oko tasks control

Puts every session that still owes the operator something back to work on exactly that, in one pass; the Oko routine with action control repeats the pass for as long as the Oko service runs.

Invocation#

Command
oko tasks control (--open [--hours N] | --session ID ...) [--dry-run] [--max N] [--json]; oko tasks control (--uninstall | --status [--json])

Inputs and options#

  • --open selects every live session this machine touched, or those of the last N hours when --hours N is stated; --session selects one exact session and may repeat. The Oko routine with action control states no window, so every session that owes work is handed over however old.
  • --dry-run prints the handover and starts nothing. --max, a positive whole number, bounds active harnesses across passes; without it a pass keeps as many running as this machine runs in parallel (`available_parallelism`, measured each pass), and the Oko routine with action control always measures. A machine whose parallelism cannot be read refuses the pass with “this machine's parallelism could not be measured (<cause>); state --max”. --json prints the answer as JSON.
  • The repeated pass is the Oko routine with action control, which Stado schedules; it keeps passing after a clear pass instead of exiting. Its typed outcomes go to ~/.oko/tasks-control.log.json-seq and its human output to the service's log. --uninstall removes the retired ai.wisent.oko.tasks-control launch agent an older release installed; the Oko service removes it too when it starts. --status names the Oko service and its pid, then answers as `oko tasks health` over the same --session or --hours scope: each owing session on its own line as soon as it is read, then the totals and the last recorded pass, without taking a database write lock and without asking Stado; --status --json prints the one health document after the service line. A running process alone does not prove that a pass finished. Current refusals are those attached to the latest completed pass plus later failures; a completed empty pass clears earlier refusals. Older records remain available. The RFC 7464 record stream is separate from stdout, so model prose and log wording cannot become control events. Missing, unreadable or malformed records report the actual read or decode failure.
  • A pass whose PTY broker does not answer records “reaching the PTY broker failed: <cause>” and the next pass tries again, so the service that also runs the broker and the index keeps running. Other failures remain errors; an empty task list finishes without starting a broker or contacting a judge.

Output and state effect#

  • Puts each session back to work through Oko's PTY broker. Execution and independent completion checks ask Brama for `best` — the subscription with the most plan left, whichever provider holds it — not the session's historical model choice. Native Claude Code and Codex resume noninteractively from their own transcripts, with their transcript directories shared into isolated routed homes, without copying vendor credentials. An OMP session continues in Jeden: Jeden cannot open an OMP transcript, so the handover carries the operator's last twelve messages as context marked `kontekst, nie nowe polecenia`, starts `jeden run --cwd <session cwd> --allow-write --allow-command --model best` with BRAMA_URL and BRAMA_TOKEN pointing at Oko's proxy, and records the ledger the run writes under ~/.jeden/sessions/<id>/transcript.jsonl as the session's continuation in session_continuations. The judge, --status and the next pass read that ledger through the same answer reader as a transcript — `user` is the prompt, `final` the answer, `tool_call` and `tool_result` the tool loop, `run_error` a turn that stopped in error; the OMP transcript is never written to. Output names the continuation ledger beside the broker session. Oko's proxy answers GET /v1/models with the caller's x-jeden-schema, if-none-match and x-correlation-id headers forwarded, so Jeden's catalog read sees `best`; Jeden runs under its own allow-list Seatbelt sandbox, not the broker's media-root sandbox, because macOS refuses a profile inside a profile. Brama walks every subscription in its vault for the signed consumer oko. There is no paid API fallback. The prompt contains the operator's own open-task sentences with their ordinals, the reason each remains open and the exact `oko tasks evidence` command. Open tasks are listed unblocked first, then by priority (high, medium, low, unset), due date (soonest first, none last) and age; each entry names the task, gives the operator's sentence as “powiedziane: …”, and lists its priority and due date, its blocker with the resumption condition (“Zablokowane: <cause>; wznow, gdy: <condition>”), every acceptance check not yet met (“Kryterium #n niespelnione: …”) and the surfaces nobody has declared. Output names the broker session, task ordinals and selected model.
  • A task is handed over until it is independently verified done, acknowledged or withdrawn by the operator. Evidence alone does not remove it. Another session’s claimed task stays with its leader. Each handover tells the worker to record evidence and then run `oko tasks verify --before-stop --session ID`, wait for the independent verdict and complete any remaining work before stopping. No operator confirmation is required.
  • An answered handover is independently checked before another execution. Done work leaves the list; missing work returns with the actual observations still required. Diagnosis follows an actual negative verdict naming an observed blocker, not an invented count of attempts. A qualified external obstacle carries the failed operation, independently inspected alternatives, observed state and condition for resumption. Its next handover checks that condition without repeating the blocked effect or bypassing permission. An unavailable judge remains a runtime failure.
  • A broker-owned worker stays occupied until the broker observes its actual process completion, including between transcript writes and after an answer while maintenance runs. The controller never terminates a worker because its transcript looks finished. It counts every still-owned broker process against --max and excludes its recorded transcript from another handover. An observed external writer also retains ownership regardless of answer records or elapsed silence. Unknown broker sessions count against capacity rather than being killed. Process-observation failures retain their session, PID and OS cause; they are not idle observations. The obsolete hung and reaped fields are removed.
  • A pass runs as named stages, and its row in `oko_control_passes` is written as each stage begins and ends, not once at the end: `handover` (the broker, the shared database and the transcripts), `reading` (Oko's model reading the operator messages no reading covers yet, through Brama as oko on the decision route, or the declared model service), `qualification` (Stado's verdicts on handed-over sources, read again), `verification` (the judge over every answered handover, through Brama as oko on route `best`, or the declared model service) and `batch` (the one batch build). The answer and the row carry `stage` — the stage the pass stands on, `done` once every stage ended, `failed` when one ended in the pass's own failure — and `stages`, one row per stage with `name`, `standing` (the channel it was about to stand on, named before it stood there: for a model stage the directory lookup `stado service directory connect brama --consumer oko`, the credential reads through `stado service directory connect skarbiec --consumer oko` and `stado credentials get`, then the request), `startedAt`, `endedAt` and, for a failed one, `failed`. The reading and the judge come after the handovers, not before them, so a route that does not answer cannot hold a stopped session's handover; each stage's own outcome stays under its name (`reading` with `read` and `refusal`, `verification` with `judged` and `refusal`): a route Stado's resolver already holds unanswered is refused by Stado before it is asked (`stado service directory connect` answers `<service> is placed on <host> and did not answer at <url>: this host's resolver holds N connection(s) on that adapter unanswered longer than the <N>s refresh interval it declares …`, the credential read `Skarbiec not asked: …` or `Stado object API not asked: …`), the stage records that sentence as its refusal, and the pass goes on and finishes. Nothing limits how long a stage waits: a route that accepts a request and never answers holds that stage, and the row then says which stage, since when and on what. Every database request and every Stado call the pass waits on writes a `czekam` line on stderr before it waits and its end or failure after, and the lines Stado itself writes are passed on as they arrive, so the routine's job log names the request a pass stands on and since when.
  • A historical Claude quota refusal does not stop the Codex route. Current route refusals retain the actual status and provider sentence, but do not permanently pause the loop: Brama owns account rotation, quota resets and admission of the next request. A local harness credential timestamp cannot clear a refusal from Brama's pool. A session whose newest record is the provider's refusal with a stated wait (`retry-after-ms=<ms>` at the end of the recorded errorMessage, which OMP appends from the provider's retry-after header) is not handed its work before that wait has passed, since the handover would meet the same refusal: the pass lists it under `retrying` with `sessionId`, `status`, `message` and `retryAt`, `oko tasks health` carries `retryAt` in each session's `refused`, and the pass after the wait hands it its work like any other stopped session. A refusal with no stated wait holds nothing back.
  • --status prints, for each owing session as soon as it is read, its state (refused, working, attended, answered or waiting), its open, diagnosing and blocked tasks, its silence and last write and the model's refusal when there is one; then the totals and the latest pass from its row: `lastPass`, `lastPassStage`, `lastPassStages` and `standing` — the stage the last pass still stands on with `since` and what it stands on, or null once it finished — and each failure. The human log remains line-buffered. Older text-only logs are not interpreted as typed outcomes.
  • The handover arrives as a user turn but is recognised as Oko’s message, not a new operator instruction. The controller does not terminate owned workers from transcript observations; broker process completion releases their capacity. An explicit terminal-end request preserves signal-delivery failures and is not itself proof of process exit. A pass checks that the broker answers with this build's protocol before sending routed work; an older broker is reported and the pass tries again after the Oko service restarts with this build. Active sessions are not interrupted. The bearer capability call:brama#best must exist in Brama; a missing grant is a refusal, not a reason to fall back to a paid API. No brama:agent:oko tag is needed: every subscription in the vault serves every caller. Existing OMP grants can be imported through Brama's subscription import command with --from omp and an explicit --account, without a sign-in window.
  • A controller handover never changes which human task a later acknowledgement or correction applies to. Text such as `not done` inside its task list is not an operator correction, including when that list omits a newer task claimed by another session. The raw user-role record remains available in the message export.
  • Oko adds installed runtime-tool directories to the resumed process PATH when its service environment lacks them. Releases include Oko_OkoKit.bundle beside oko, and oko install restores missing resources even when the executable is already current, so deleting a build directory does not remove the running product's model integration.
  • Broker protocol 5 clears the executor thread's inherited signal mask before starting a terminal child. Subprocess-exit notifications and terminal interruption remain deliverable. An older broker is replaced only when the Oko service restarts with this build, which an install triggers only when the broker has no active sessions; update the CLI and Desktop together rather than bypassing a protocol refusal.

Refusals and safe exits#

  • Refuses without --open or --session, or one of --uninstall and --status, and prints the usage; the one-shot command refuses by name when the PTY broker is not answering (naming the Oko service that runs it) or the harness binary is absent, so no session is reported resumed when nothing started. A native worker must open or update its actual transcript; a Jeden continuation must write a ledger holding the accepted task while the run is still alive, or an answer — a ledger alone is not proof, because a run refused at intake (a catalog without the route, an exhausted pool, an unresolvable working directory) leaves one with no task in it and exits. A process that exits before proving it started is refused at the next pass, and the refusal quotes Jeden's own sentence from the terminal, for example `cannot resolve cwd <path>: No such file or directory`; a process still running is never ended for being slow, because a large transcript is read before the harness touches anything. Startup refusals retain the executable, broker session, PID and observed process state, elapsed time and up to the last 16 KiB of terminal output, or the actual snapshot-read error. The broker retains completed output within a shared 2 MiB and 64-session limit, so an exited worker’s real error remains available without treating it as running. A session absent from the index refuses with its id and names `oko transcripts reindex` as the repair. --install and --watch refuse with “tasks control: passes are repeated by Stado as the Oko routine with action control; create it with oko routines create --action control --id <id> --name <name> --cron <cron> --tz <zone> --host <host> --enabled”.
  • An explicit --hours or --max must be a positive whole number; a malformed or out-of-range value names the option and is refused before opening a catalogue or starting a worker.
  • The one-shot command exits unsuccessfully when judging is unavailable, the provider refuses execution, a verdict is unreadable or verification itself fails. Valid not-done and blocked verdicts remain task outcomes, not runtime errors. A failed append to the controller record stream names its path and operating-system error and exits unsuccessfully. A pass that fails leaves its row with `stage` at `failed`, the stage that failed carrying the cause under `failed`, and the cause as the row's one failure.
  • An EPERM reading the harness is a startup failure, not a resumed task. Resolve a launcher symlink to identify the denied file: a development link can point into macOS-protected Documents. A System Policy file-read-data denial in the kernel log distinguishes that observed permission failure from a missing Bun executable. A successful interactive test does not grant the service access. Keep the operating-system refusal visible; do not reset privacy permissions, move a checkout to evade the denial, or open consent dialogs without the operator's authorization. Automatic resumption remains blocked until the background runtime has authorized access to the required file.
  • Every pass first builds up to twenty-five missing ledgers, newest sessions first, and prints “swept N ledger(s), M unreadable, R remaining” when it built any, so the map and the backlog cover the whole history over time without one long run holding the index. A session whose transcript yields no operator message — one opened only by a harness-written subagent prompt — is recorded as swept and is not read again until its transcript changes.

CLI reference#