Docs/Reference

Reference

Work outside the task

block-off-task-work refuses a change to a repository the session never said the operator's current instruction touches. It runs on the tools that change or publish a file — write, edit, refactor, apply_patch, and a git commit or git push in bash. Reads are never refused.

block-off-task-work refuses a change to a repository the session never said the operator's current instruction touches. It runs on the tools that change or publish a file — write, edit, refactor, apply_patch, and a git commit or git push in bash. Reads are never refused.

#Why it exists

A session asked for one thing can deliver it and then spend an hour repairing installers, gateways, credential pools and sign-ins, and starting fleet builds, none of which anybody asked for. Each of those things may really be broken, which is what makes the drift invisible from inside: the work looks like work. The operator asked for a mechanism that blocks every action unrelated to the task.

Relatedness is not guessed. A gate that guessed it would be wrong in both directions — refusing a repair the instruction plainly needs, and waving through an hour of unrelated work because it looked useful. So it is declared, once per instruction, and checked mechanically.

#Declaring what the instruction touches

tama task scope set --session <SESSION> --repository tama --repository tama-landing --defect <DEFECT>
tama task scope set --session <SESSION> --repository oko --task task-0d468fb998d4df51
tama task scope set --session <SESSION> --task task-0d468fb998d4df51
tama task scope show --session <SESSION> [--json]
tama task scope clear --session <SESSION>

set binds the declaration to Tama's capture of the latest prompt, so a later turn cannot silently reuse a stale scope. For --defect, it copies that prompt's words. For --task, it takes the task's original operator words from Oko, even when the task predates a smaller instruction. An open earlier task remains available after the smaller instruction is served: the agent can run tama task scope set --session <SESSION> --task <EARLIER TASK ID> itself, without asking the operator to say “continue”. show then names the earlier task and reports whether the declaration is bound to the latest turn. It does not claim that Oko has independently marked the smaller task done.

A session whose prompt Tama never captured still declares its scope. A launcher can hand a session its first prompt at spawn, and OMP raises its input event only for a prompt typed or sent over RPC, so record-current-assignment records nothing for it. set then reads the session's transcript and records its newest message from the operator's side (a user-role message the harness does not attribute to the agent) as the instruction, saying on stderr session <SESSION> had no captured instruction …; its newest operator message in the transcript is recorded as the instruction, and binds the scope to it. A transcript that cannot be read, or holds no such message, refuses with no operator instruction is recorded for session <SESSION>, and its transcript cannot give one: <cause> or … holds no message from the operator's side; the gate's refusal never names a remedy that itself cannot run. The real journey tests/task-scope/transcript.rs runs the built tama task scope set and show with a home of its own and a defect recorded through the installed Oko: a transcript whose newest operator message follows an earlier one and precedes a harness continuation binds the scope to that message, a transcript of harness messages only is refused and declares nothing, and a session with no transcript is refused naming the session.

The open-work Stop refusal includes each open Oko task's identifier and the scope command. After recording evidence for a later defect, the agent reads the ledger, selects an earlier open task and continues it in the same session. Oko's pending independent verdict remains pending; selection is not a completion claim.

Every scope names an entry in Oko's register. An unknown task, a task already done, an unknown defect, or a defect closed by a revision is refused. The agent must select an open task whose work it is actually doing, not declare unrelated work under a convenient repository name.

Another session's --defect declaration does not lock the defect. Sessions work on one piece of code together, so set declares the scope and, when another live session declared the same defect, prints on stderr: defect <ID> is also declared by session <SESSION>; work on it together: read its notes (`oko defects show <ID>`) and the uncommitted changes it holds, then build on them with anchored edits. The exit status is still 0.

A task's scope lives in its Oko contract, not in the session. With --task and no --repository, set takes the repositories the contract lists (oko tasks show <task> --json, field current.contract.terms.scope). Given repositories that differ from the contract's are written back into it with oko tasks state <task> --scope <repo>… --by <SESSION>, so the next session handed the same task declares the same scope, and the change appears in the contract's history. If Oko refuses that write, set fails with Oko's sentence and declares nothing. A scope with no repository — none given and none in the contract — is refused: work that touches nothing changes nothing.

#What is refused

SituationWhat the session is told
Nothing declared for the current instruction The change is refused until the session says which defect or task the instruction is and which repositories it touches. It costs one command, and it makes the answer to "what are you working on" something the machine holds rather than something a model remembers.
A scope that names no defect and no task Refused. A repository is not a subject: until an entry in Oko's registers stands for the work, nothing says the change is part of anything.
A repository outside the declaration The refusal names the instruction being served and the repositories it was declared to touch. Something really being broken is not the same as being asked to fix it: record it with oko defects record and say so in the answer.
A scope declared for an earlier instruction Refused as undeclared. The operator has spoken since, and that is exactly where a session drifts — one reasonable step at a time, under a scope nobody granted for the new prompt.
A completed or unknown earlier task Refused by set. Resume an open registered task; do not relabel the latest prompt as its work.
A whole-file write over a file another session has uncommitted changes in Refused, naming the file and the session that wrote it. Every file a session writes is logged under ~/.tama/session-writes/<session>.log; a whole-file write would replace that session's unfinished change. An anchored edit of the same file is allowed: it applies to the file as it is, that session's change included, and the file then counts as this session's too, so it may commit it.
A broad git add (-A, --all, . or a directory) over an untracked file another session wrote, unless that session is known to have stopped Refused, naming the file and the writing session: a session's unfinished work stays its own until it ends. Stage this session's own changes with tama stage --session <session>. A file whose writer is a recorded session whose process no longer runs may be staged: that session's unfinished work is taken over. The commit gates admit it only when the staged bytes are what that session's recorded edits made of the file and its transcript is found; a file changed after its writer stopped is refused at the commit. A writer that still runs, or that no session record names, keeps the refusal; when the stopped sessions cannot be read, the add is refused as unreadable.
A git commit from a repository outside the declaration Refused like any other change there. What a commit takes is judged by pre-bash's commit guard: a commit naming paths, or taking every tracked change (-a), --include or a pathspec file, is refused, because it would stage whole files rather than this session's recorded changes; the index a commit takes must hold exactly the changes the session's edit receipts record, staged with tama stage --session <session> --repo <checkout> and committed with git commit -m <message> in a separate invocation. A push carries commits already made and is judged when they were made.
Any change or commit in a repository by a session whose Oko role is supervisor Refused whatever its scope, naming the executors recorded under it (oko sessions role) to hand the change to, or that none is recorded yet, with the commands that hand it over: oko defects record, oko defects assign <id> --owner <executor> and oko sessions send <executor> --defect <id>. Reads, Oko's registers and sends pass: a supervisor reads, records, assigns and sends. A role register that cannot be read refuses with its cause.

#What passes

Every read. Every change inside the declared repositories. Everything outside ~/Documents/CodingProjects/Wisent — an installed program, the operator's own state, a build directory — which is other gates' subject: one-off repairs owns those.

#Where the refusal comes from

Source: rust/crates/tama-hook-tools/src/ports/block_off_task_work/mod.rs; the declaration CLI: rust/crates/tama-hook-tools/src/ports/block_off_task_work/scope_cli/mod.rs; program: rust/crates/tama-hook-tools/src/programs/block/ownership/block_off_task_work.rs; the declaration: hook-declarations/block-off-task-work.json. Declared with DEVICE_HOOK_EDIT_APPROVED=1 tama hooks declare --file <declaration> and installed with DEVICE_HOOK_EDIT_APPROVED=1 tama hooks release; which hooks this machine runs is decided by tama enforcement only <hook-id>…, which has to be run outside an agent session.

The real journey tests/task-scope/gate.rs runs the built prompt hook, the gate and tama task scope set and show with a home and workspace of its own and a defect recorded through the installed Oko: a change to a workspace repository is refused while no scope is declared for the current prompt and a read is not; once the scope names the defect and tama, a change in tama passes and one in oko is refused naming the defect and the declared repositories; a new prompt leaves the scope serving nothing and the next change is refused again.