Repository navigation
orchestrate: lint the state file from the hooks, script the Now/Done edits and the updated= marker - #115
Merged
gilesknap merged 1 commit intoOct 14, 2026
Conversation
…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
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.
In a long goal, state.md drifted even though it was edited every turn. Now had stray blank lines and no
(nothing running). Done grew one line per agent return and ended up out of order. Decided collected events. Next and Queue still named merged items.updated=was typed by hand and was wrong. Nothing in the plugin checked the file's content. This PR adds that check and moves the most error-prone edits intogoal.sh. Plugin version 0.3.0 -> 0.4.0.Stacked on #114 (hook session ownership and the narrower Stop check): this branch is based on #114's branch and should merge after it.
Closes #108
Closes #110
Closes #111
Closes #112
Changes
scripts/state-lint.sh <state> [<log>] [<sidecar>](orchestrate: add a state.md lint run by the Stop and SessionStart hooks #108). Printslint: <code>: <text>and always exits 0. Codes:now-blank,now-empty,now-finished,pending-but-done,decided-events,decided-unattributed,done-order,size,done-long,head-long,marker-stale,section-stale.done-ordercompares theYYYY-MM-DD HH:MMZstamps, date and time, so a goal can run over several days. Unstamped entries are placed by their label's time in log.md.section-staleskips empty or placeholder-only sections, and after it reports a section it counts again from zero.section-stalekeeps section hashes in the goal's.lintsidecar, so the orchestrator is still the only writer of state.md.STATE_LINT_*environment variables..lint-last. Counts and times are masked for that comparison;#Nis kept. Any nudge goes out in the same message. Thestop_hook_activeguard is unchanged.goal_contextin lib.sh (from orchestrate: scope the hooks to the owning session; narrow the Stop check #114), so the Stop turn that claims a goal withgoal.sh start|resumeshows them too.sizeflags a file over 10 KB; the pre-trim file was 98 lines but 14.7 KB.head-longflags a head over the injection cap (40 lines / 4000 bytes). The "under 150 lines" rule is gone.goal.sh touch(orchestrate: the model types the state.mdupdated=marker and gets it wrong #111). Setsupdated=, and so donowandland. The skill and the Stop nudge no longer ask the model to type a time.goal.sh now '<entry>'andgoal.sh land <label> ['<done line>'](orchestrate: optional goal.sh helpers for the Now/Done moves (now, land) #112).nowadds a Now entry in place of(nothing running).landdrops the entry whose text contains-> <label> ->and restores(nothing running)when Now empties. Given a done line, it appends- YYYY-MM-DD HH:MMZ <text>after the last Done entry.land - '<text>'is for an item no agent ran.landalso drops an entry that starts with the label, sonow 'foreground: <item>'pairs withland foreground. Both keep the file's mode and fold newlines in their arguments into spaces.goal.sh, which is already the orchestrator's own tool, so the single-writer rule holds.docs/how-to/use-orchestrate-mode.mdgains a "The state file" section covering the format,goal.sh touch/now/landand the lint.now/land.(<who>, <date>).## Decidedand fix what it contradicts.<YYYY-MM-DD HH:MMZ>prefix, and Decided's example ends(<who>, <YYYY-MM-DD>).The lint, the skill and the helpers use one format: Now holds one line per entry or
- (nothing running); Done is last,- YYYY-MM-DD HH:MMZ <text>; Decided entries end with(<who>, YYYY-MM-DD).Testing
bash tests/orchestrate_plugin.sh: 284 passed / 0 failed, on top of orchestrate: scope the hooks to the owning session; narrow the Stop check #114's 224. New tests:tests/fixtures/orchestrate/) yields each code.goal.sh starttemplate yields no findings.goal.sh touchsetsupdated=to the current minute.now/landwork with an empty Now and a non-empty Now, an absent label,-, and repeated calls. The resulting file passes the lint.stop_hook_active, and does not run after a read-only turn.Merge order: stacked on #114; merge it first.
🤖 Generated with Claude Code
https://claude.ai/code/session_01AJKFfYT7qdSfhkZGj6syCo