Repository navigation
feat(hooks): stop control on every host; once-per-session raw-git nudges - #258
Merged
Merged
Conversation
…every host A core stop policy (hooks/stop.ts) reads ledger and local git facts only: an unpushed commit with endpoint pr|green|merged, an open PR whose recorded checks are failing or pending under green|merged, and a delivered head with no non-author verdict. Claude Code and Codex Stop render decision block, Cursor stop renders followup_message (loop_count guard, loop_limit 1), Pi continues from agent_end with sendMessage triggerTurn, and OpenCode resumes from session.idle with session.synthetic. Never in a subagent, never after a continuation, never when the last message asks a question; any failure allows the stop. Raw-git nudges show once per kind per session (the skill-nudge marker) and never on a command that runs workit. Claude Code worktree-isolated subagents are told to run git as plain commands. Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f-w-stop-control Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n every host Stop control tests drive the core obligations through Claude Code, Codex and Cursor payloads, Pi's agent_end and OpenCode's idle controller. Pi tests cover the before_agent_start skill nudge (first turn, no-change turn, changed context) and the untrusted guard. Raw-git nudges are checked once per kind per session and never on a command that runs workit; relayed agent messages never trigger a skill nudge. The packed Codex launcher runs with a scratch HOME and CODEX_HOME. Cursor's stop stays unregistered until the installer's canonical event list adds it; the docs record it as missing. Host parity rows for stop control and per-turn context are updated, and design.md no longer cites the removed CLAUDE_PLUGIN_DATA cache. Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f-w-stop-control Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d agents at it The Host parity matrix gains the session-trailer row from the trailer-hook slice, and the worktree-isolated SubagentStart guidance mentions that `workit doctor --fix` can install the commit-msg hook that adds it. Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f-w-stop-control Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The installer's canonical Cursor event list now carries `stop` with `loop_limit: 1`, so a local install rewrites its launcher path and the doctor flags a stop entry that could continue a turn more than once. The shipped hooks-cursor.json registers it and the Cursor descriptor marks stop native. Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f-w-stop-control Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ntrol `workit pr status` and each `workit ci wait` poll append a CLI-observed pr.status row (pr, branch, head, checks: passing|failing|pending) when the summary changed since the newest row for that PR, so polling never floods the ledger. The stop policy fires the CI obligation from the newest row for the branch's open PR at the current head, and also finds a PR it only observed through these rows. Docs record Cursor stop control as native. Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f-w-stop-control Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f-w-stop-control Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the install test Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f
Review mv0g209t. A CLI pr.merged row for HEAD, or for a head that already
holds this session's commits, ends every obligation: a squash merge with a
deleted or pruned remote branch no longer asks for a push that would
re-create it, and an --unverified merge no longer asks for a verdict. The
push obligation counts only commits this session recorded.
Pi skips agent_end when the run was aborted (Esc) or errored, or will be
retried; OpenCode resumes only a session whose outcome is succeeded. A
question now includes offers ("want me to", "let me know"), [y/N] prompts,
the Arabic and full-width question marks and a question followed by an
option list, read from the last paragraphs. The verdict message says to
start a verifier only if none is running. Relayed-message markers match
only at the start of a prompt, and Codex's Stop hook has a 10 s timeout.
Tests kill the surviving mutants: the protected-branch, merged-PR,
stale-head, pending, failing-verdict and endpoint guards, OpenCode's child,
checkout and outcome checks with commit rows present, and recordPrStatus's
closed-PR and fail-open paths.
Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f-w-stop-control
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stop freely Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f-w-stop-control Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review mv0gw9vt. `workit pr status` and `workit ci wait` now also record a PR's merged or closed state as a pr.status row (once per change), and the stop policy reads a forge-reported merge like a `workit pr merge` row. With no merge recorded, a branch whose upstream is gone after a prune counts as landed, so a UI merge with auto-delete never asks for a push that would re-create the branch. A PR closed unmerged still owes its verdict, and no longer counts as open for the checks obligation. After a branch is reused post-merge, only commits outside every recorded merged head are owed. Pi drops the willRetry check: agent_end never carries it. Tests kill the mutants on the CLI-observer filter, the two-paragraph question tail and the unclosed code fence. Workit-Session: fb894a62-61b7-4f32-a4d0-f47c2e5e300f-w-stop-control Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
🎉 This PR is included in version 8.8.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
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.
Why
Host parity audit gap 3: no host blocked an agent from stopping with work provably unfinished. The user chose option A (ledger decision mv097wco): nudge once.
What
Stop control on all five hosts, from one core policy (
hooks/stop.ts).Stop→decision: block(stop_hook_active).stop→followup_message, registered withloop_limit: 1.agent_endplussendMessage({triggerTurn}).session.idleplussession.synthetic({resume}). This is partial, as recorded in hosts.md.Obligation (b) data:
workit pr statusandworkit ci waitappend a CLI-observedpr.statusrow (pr, head, checks) when the state changes.ledger listsummarizes it.Fixes from the ui-kit session audit and earlier reviews:
workit git. Claude Code's isolation checks refuse that and can't be turned off. They're also pointed atworkit doctor --fixfor the session trailer.Hook bundle budget: 675 → 682 KB (Cursor is 678,173 B).
Verification
workit check lint,typecheckandtestpass after the rebase.bun run knipis clean.bun run build && bun scripts/test.ts packaging: 245 pass.decision:blocknaming the verifier; Cursor returnsfollowup_message;stop_hook_active, or when the last message is a question, the result is{}.ci waitsees pending, writes 1pr.statusrow, and a stop undergreenblocks once namingworkit ci wait --pr 12. Oncepr statussees passing, the stop is allowed.🤖 Generated with Claude Code