Give the message verb a permission mode, so rework sessions can report - #165
Merged
Conversation
`--permission-mode` is per invocation rather than a property of the session a verb joins, so a `message` turn launched without it runs in ask mode against a stdin at /dev/null: the rework session thinks, is refused its edits and its commands, and so cannot run `voro done`. The work is done and never reported, reconcile finds the process gone, and the task lands in `stalled` — a missing flag surfacing as a dead agent, which sends the operator to liveness rather than to the launch that could not act (observed on task 307, session ece71938). The flag itself reached the built-in `claude` message template in #155. What was missing was anything holding it there. A test now asserts it over every built-in template that hands an agent a prompt — `dispatch`, `plan`, `message` — and asserts that `resume` carries neither a prompt nor a mode, so the one launch that omits it does so deliberately: it hands the operator a terminal in which the ask-mode default is answerable. DESIGN.md §8 gains the property the test encodes — a permission mode belongs to a launch, not to a verb — and the capped-recovery paragraph now refers to it rather than restating it. Verified against an isolated scratch store: a task dispatched to the built-in `claude` agent, rejected with feedback through the cockpit's `a` key, forked into `claude -p ... --permission-mode auto` (confirmed in the launch log), and that session edited the file, ran git, and reported with `voro done` — landing the task back in `review` with no permission refusal in its log. `cargo test --workspace` (835 tests) and `cargo clippy --workspace --all-targets -- -D warnings` pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Assert the permission mode every prompted launch depends on
The flag the task asked for was already there.
--permission-mode autoreachedthe built-in
claudemessagetemplate in commit88d6e30(#155'scapped-session recovery work, merged 2026-08-14 14:30), which needed it for the
same reason — the nudged turn does real work. What was missing was anything
holding it there: no test named the flag, and DESIGN.md discussed it only inside
the capped-recovery paragraph, where it reads as a property of that one feature.
So this change supplies the parts of the task that were genuinely absent.
A test.
every_builtin_claude_launch_that_prompts_carries_a_permission_modeasserts, over the built-in templates, that every verb handing an agent a prompt
—
dispatch,plan,message— carries both{prompt_file}and--permission-mode auto. Removing the flag from themessageline fails itwith the offending template printed; confirmed by doing exactly that before
restoring.
The
resumedecision, made deliberately rather than by omission.resumekeeps no permission mode, and the same test asserts it carries neither a mode
nor a prompt. That is the distinction worth encoding:
resumestarts no work ofits own, it reopens a session in the operator's own terminal, where the ask-mode
default is answerable by whoever is sitting in front of it.
DESIGN.md §8 gains a paragraph — a permission mode is a property of a
launch, not of a verb — stating the rule, naming
resumeas the deliberateexception, and, more importantly, naming the failure's signature: a session
refused its edits and its commands cannot run
voro done, so it exits havingdone real work Voro never hears about, reconcile finds the process gone, and the
task lands in
stalled. A missing launch flag therefore surfaces as a deadagent, sending the operator to liveness (#376, #390, #135 — all working) rather
than to the launch that could not act. The capped-recovery paragraph now refers
to that rule instead of restating it, and the code comment on
BUILTIN_AGENTSpicks up the same stall symptom.
Verification
cargo test --workspace(835 tests) andcargo clippy --workspace --all-targets -- -D warningsboth pass;cargo fmt --allapplied.Verified at the real surface, against an isolated scratch store and a scratch
git project, using a
target/debugbuild of this branch:claudeagent; the sessioncommitted its work and reported with
voro done, landing it inreview.akey — the path thatframes the feedback with
rework_messageand sends it. The launch logrecords the real command:
claude -p --resume 'b0625130…' --fork-session --session-id '2d28d55e…' --permission-mode auto "$(cat …)".GREETING.md, amended the commit, rangit show --stat HEAD, and ranvoro done— landing the task back inreviewwithits rework summary, and no permission refusal anywhere in its log. Each of
those three is a thing the pre-fix session on task 307 reported it could not
do.
Follow-up filed
Task #449 (
voro, discovered from this one). Verification turned up a second,independent rejection path with the same misleading symptom: the transition
menu's own
reject with feedbackentry, and thevoro rejectCLI verb, onlymove the state — they send nothing. For a supervisor-owned agent that cannot end
anywhere but
stalled, and it gets there inside the same keypress, sinceapply_and_refreshreconciles immediately afterwards and reads the finishedsession as dead. Observed live during this verification. It contradicts §8's
claim that
reviewkeeps the session open "so a reject-with-feedback returnsthe work to it", so the proposal lays out the choice rather than assuming one.