Repository navigation
orchestrate: scope the hooks to the owning session; narrow the Stop check - #114
Merged
Merged
Conversation
…heck Orchestrate hooks now act only in the session that owns the active goal (fixes #107), the Stop hook ignores read-only commands, and only a real write to state.md counts as updating it (fixes #109). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AJKFfYT7qdSfhkZGj6syCo
…edits and the updated= marker Adds a state.md lint run from the hooks (#108), rewrites the skill's state-file rules to one row per item with dated Done lines (#110), has goal.sh write the updated= marker (#111) and adds goal.sh now/land helpers (#112). Stacked on #114. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AJKFfYT7qdSfhkZGj6syCo
coretl
approved these changes
Oct 14, 2026
…-quality orchestrate: lint the state file from the hooks, script the Now/Done edits and the updated= marker
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.
Closes #107
Closes #109
What changes
Hooks act only in the session that owns the goal (#107). The pointer
~/.claude/orchestrate/activegains asession=<session_id>line. Every hookstill requires the pointer and a cwd at or below the launch directory, and now
also requires the hook input's
session_idto equal the owner. Any othersession in the same directory gets no SessionStart block and no Stop nudge,
and its SessionEnd writes nothing.
How a session becomes the owner:
goal.shruns in the model's Bash tool and cannot see the session id, sogoal.sh startandgoal.sh resumewrite the pointer with no owner (nosession=line). While a goal has no owner, every hook is silent.goal.sh startorgoal.sh resumerecords its own
session_id. Only the command word counts(
bash <path>/goal.sh resume,"$CLAUDE_PLUGIN_ROOT/scripts/goal.sh" resume);a
greporechothat mentions it does not. Running/orchestrate resumein another session is therefore an explicit takeover, and the old owner goes quiet.
so on that turn the Stop hook gives it the same checks as
additionalContext:the crash check against the previous transcript,
Nowentries with noreport, and the scratch report. The SessionStart block and this one share
one function in
lib.sh.goal.sh resumeof the goal that is alreadyactive no longer rewrites
state.md, so this crash check still comparesagainst the last real write.
/clearstarts a new session id. The owner's SessionEnd withreason=clearwritessession=cleared:<old id>, and the SessionStart withsource=clearthat follows claims it. A fresh session (source=startup),a fork, or another session's Stop never claims a cleared goal.
/compactandclaude --resumekeep the session id./forkand--fork-sessionleave the goal with the original session. Switching awaywith
/resumeleaves it with the conversation you left. The how-to says so.The scheme uses only the documented
session_idhook input and needs nonew files. A pointer written by 0.2.0 has no
session=line: afterupgrading, run
/orchestrate resumeonce in the orchestrating session(documented in the how-to).
Stop hook: reads are not changes (#107). Bash commands are split into
simple commands (
&&,||,;,|, newline, and the(or{that opens$(...), a subshell or a group). A verb counts only as the command word ofits simple command, after any
VAR=value, a shell keyword (do,then,if, ...) or a wrapper (env,command,exec,nohup,time,timeout N). Sogrep "git commit"andecho "git checkout"are not writes,and
url=$(gh pr create --fill)is one.-C <dir>or--no-pager): commit, push, rebase, reset,checkout, switch, merge, cherry-pick, revert, restore, pull, stash,
worktree add|remove|move|prune, andbranchwith a delete, move, copy orforce flag. Not
push --dry-run/push -n,stash list|show. A flaginside a quoted argument (
commit -m "... --dry-run") is ignored.pr create|merge|edit|close|reopen|comment|review|ready|checkout,issue create|edit|close|reopen|comment|transfer|delete|lock|unlock|pin|unpin,release create|edit|delete|upload.gh apicounts only with a non-GET-X/--methodor with-f/-F/--field/--raw-field/--input.gh api graphqlcounts only for amutationanywhere in the command,including a multi-line
-f query=, or a-F query=@file.Stop hook: only a real write to state.md counts (#109). The turn counts
as recorded only for an Edit, Write or NotebookEdit of
<goal>/state.md, or agoal.shverb that writes it (start,resume, andtouch,nowandlandfrom the sibling PR). A command that only namesstate.md(cat,grep,sed -n) is a read and no longer counts. Writing a brief, the log, amap, scratch or the status file does not silence the nudge either.
Also: SKILL.md, README and docs/how-to/use-orchestrate-mode.md describe
ownership. Plugin version 0.3.0.
Tested
bash tests/orchestrate_plugin.sh: 224 passed, 0 failed (112 before this change).New cases:
goal.sh listandcommands that only mention goal.sh (
grep,echo,sed) claim nothing.goal.sh resumeandgoal.sh starteach claim the goal. The claiming turnis not nudged and gets the context block.
Edit plus an Agent call), SessionEnd(logout) and SessionEnd(clear) are all
silent. The log and the owner are unchanged. The owner still gets the nudge.
$CLAUDE_PLUGIN_ROOTformreports both the lost
Nowagent and the crash line (previous transcriptnewer than the state file). It does not inject the head. Then the goal is
taken back.
/clearhand-off: thecleared:<id>marker is ignored by astartupsession and by another session's Stop, and claimed by the
clearSessionStart, which injects the head. An exit (
logout) does not hand thegoal on.
git merge-base main HEAD(and inside$(...)),gh api repos/o/r/pulls/102/files,gh api -X GET ... -f, single- and multi-line graphql queries,git push --dry-run,git push -n,git stash show -p,grep -n "git commit",git worktree listand
git branch -a.url=$(gh pr create --fill),(git commit),{ git commit; },for ...; do git commit; done,timeout 60 git push, a multi-line graphql mutation,-F query=@file,gh api -XPATCH,--input,gh pr checkout,git -C dir commit,GIT_X=1 git commit,git --no-pager commit,git commit -m "... --dry-run",git worktree add,git revert,git branch -D,git push --dry-run && git pushand a two-line command whose second line commits.
briefs/,log.md,scratch/orstatus.mdnudges, and adding a
state.mdEdit silences it.cat,grep,sed -nandcat >>namingstate.mdall nudge.goal.sh resume|touch|now|landsilenceit, and
goal.sh listdoes not.shellcheck: no error-severity findings, and no new advisory findings.
Not tested in a live Claude Code session:
clear) runs before the SessionStart(clear) of the newsession is assumed, not observed. If the order were reversed, the cleared
session would be silent until
/orchestrate resumereclaims the goal.goal.shtool call to be in the transcript whenStop runs.
🤖 Generated with Claude Code
https://claude.ai/code/session_01AJKFfYT7qdSfhkZGj6syCo