This release makes /orchestrate observable and interrupt-safe: a new /orchestrate status board, a continuous mid-run milestone heartbeat, and a durable cross-session restart guard — alongside a batch of orchestrate integrity fixes (landing verification, marker attribution, and test-fixture git isolation).
Added
/orchestratenow emits a continuous, out-of-band per-issue milestone heartbeat over a multi-hour run (#48, ADR-0006). Between #49's terminallanded/opened-PRmarker there was no within-ticket signal: an issue churning in fix round 3 for two hours was indistinguishable from steady progress, and a parked/failed issue left no durable marker at all — and the only in-flight view was the in-session progress tree, the exact place peeking has repeatedly killed the background run. Now a mechanical-tierreportersub-agent posts a durable, machine-readable milestone comment on the issue at each lifecycle boundary the engine reaches —orchestrate: started #<n>, run <runId>,implementation green,verification cleared,fix round <k>(only when one runs), andparked #<n> (<reason>)when the issue dies — extending #49's single-source-of-truth grammar (format_started_marker/format_implementation_green_marker/format_verification_cleared_marker/format_fix_round_marker/format_parked_markerand the widenedMarkerverb domain +parse_landed_markerinscripts/orchestrate.py). The reporter is the second authorized outward writer, but strictly weaker than integrate: comment-only, never close/push/merge (it carries the same shared prohibition the workers do).startedis posted only for an issue the preflight decided to dispatch — never for one skipped asalready-landed/already-open/ stale; the heartbeat is emitted in both merge and PR modes; reporting is best-effort (a failed or absent reporter never blocks, parks, or fails an issue); and each reporter dispatch is awaited so an issue's comments post in lifecycle order (which #50's status board reads back). A milestone verb carries an issue number, never a SHA, so it never parses as alandedmarker — #49's four preflight verdicts are unchanged and no falsealready-landedskip occurs.skills/orchestrate/orchestrate.workflow.jsgains thereporteragent,REPORTER_SCHEMA, the best-effortreportwrapper, the milestone templates, and the wave-loop /buildAndVerifyboundary dispatches;skills/orchestrate/SKILL.mddocuments the reporter lifecycle step, the milestone vocabulary, the two-authorized-writers operating-contract bullet, and out-of-band progress watching (the issue comment timeline / GitHub notifications, never the TUI); ADR-0006 records the decision and amends ADR-0005 §3 / ADR-0001 §7 by reference.tests/test_orchestrate*.pycover every milestone verb's round-trip, malformed-comment rejection, the no-milestone-parses-as-landed non-regression, the extended SKILL↔parser consistency binding, and the reporter engine structure, red-first. Theparkedreason is now sanitised at format time in both mirrored sources (sanitize_parked_reasoninscripts/orchestrate.py,sanitizeReasonin the engine): collapsed to one line, reduced to an allowlist — which drops:so a reason can never reconstruct anorchestrate:prefix and smuggle a second marker that would parse back as alandedverb (a falsealready-landedskip), drops()so it cannot break the single-line grammar #50 reads, and drops quotes/backticks/$so it cannot inject into the reporter'sghcommand — and truncated to a short cap so no unbounded verifier detail is disclosed durably on a public issue. Every per-issue park now emits a durableparkedheartbeat, not only the ones insidebuildAndVerify: the prerequisite-cascade park (a blocked dependent) and the loudlanded-marker-stalepark both post one, so a maintainer watching the timeline never sees a prerequisite park followed by silence about the issues it cascades to; the token-budget park (dispatching a reporter after the budget floor is breached would contradict it) and the run-level integration-review / hotfix parks (no per-issue number to post on) stay silent by design./orchestrateis now interrupt-safe across a dead cross-session resume (#49, ADR-0005). A run killed mid-flight and blindly relaunched used to re-run the whole plan from scratch — WorkflowresumeFromRunIdis same-session-only, so a cross-session relaunch gets zero cache hits — re-implementing already-landed issues on fresh branches and landing redundant commits. Three mechanisms close this. (1) Durable landed-markers: at integrate time the integrate step posts a machine-readable comment on the issue — canonicalorchestrate: landed <sha> on <branch>, run <runId>in merge mode,orchestrate: opened PR #<pr>, run <runId>in PR mode — with one source of truth (format_landed_marker/parse_landed_markerand theMarkerdataclass inscripts/orchestrate.py), designed to extend to #48's milestone vocabulary. (2) Close-at-integrate (Decision D1): a merge-mode issue is now closed by the integrate step at integrate time — the moment it has both cleared independent verification and landed — not by the orchestrator at finalize; PR mode leaves the issue open. This is the one narrow exception to the sub-agents' ban on outward writes (the integrate step alone may post the marker and close), forced by the orchestrator being blocked on the single Workflow call mid-run and the engine having no I/O of its own. (3) Preflight idempotence guard: before dispatching an implementer, a cheap mechanical preflight sub-agent gathers each issue's durable state (gh issue view --comments,git merge-base --is-ancestor, any orchestrate PR's state), and a pure, unit-tested decision function (preflightDecisioninlib/orchestrate/engine-helpers.mjs, mirrored byte-identically inline inskills/orchestrate/orchestrate.workflow.js) maps the facts to one of four verdicts —already-landed(skip, no implementer, marked landed so dependents proceed),landed-marker-stale(park loudly for a human, never rebuild from zero),already-open(benign PR-mode skip), ordispatch. So even a naive relaunch scoped to the same issues re-implements nothing that landed.skills/orchestrate/SKILL.mdgains a Restarting a stopped run section stating Workflow resume is same-session-only and prescribing the cross-session restart (re-plan the remainder, launch fresh, lean on the guard — never blind-resume), corrects the old "resumable via itsrunId" advice, documents the preflight lifecycle step and the durable-marker + close-at-integrate behaviour, and carries the narrow-exception operating-contract bullet.scripts/orchestrate.py's report gains thealready-landed/already-open(rendered as "already complete") andlanded-marker-stale(rendered as a blocker) statuses. ADR-0005 records the decision and amends ADR-0001 §5/§7 by reference; the mandatory final integration review handles a cross-issue defect at run level and never reopens an already-closed issue.tests/test_orchestrate.py,tests/test_orchestrate_skill.py, andtests/test_orchestrate_workflow.pycover the marker round-trip and rejection, the four preflight verdicts (through node), the integrate marker+close structure gated to a real issue, the restart protocol, the SKILL↔parser consistency binding, and ADR-0005's existence and cross-reference./orchestrate status— a deterministic per-issue run board you can watch from outside the run (#50). The durable milestone and landed comments #48/#49 post are the only out-of-band progress signal, but reading them meant scrolling each issue's timeline by hand. A newstatussubcommand sits besideplan/redgreen/reportinscripts/orchestrate.pyas a pure stdin→stdout renderer — no network I/O in the Python — that folds those comments into one board, a row per issue in one of four states:queued,working(with the current phase),done(with the landed SHA), orparked(with the reason). All marker reading goes through the single-source-of-truthparse_landed_marker, so the board and the preflight guard never diverge on what a comment means. The board is scoped to a single run — the latest by default,--run <id>to pin an earlier one — so a restarted run's fresh markers don't blur with an older run's.skills/orchestrate/SKILL.mddocuments thegh issue list … | statusone-liner and itswatchvariant (both driven with--state allso a landed-and-closed issue still renders a done row) and the first-page comment cap the reader honours.tests/test_orchestrate_status.pyandtests/test_orchestrate_skill.pycover the four states, run scoping and the latest-run default, the queued fallback, and the SKILL↔renderer consistency binding, red-first.
Fixed
/orchestrate plannow reads dependency edges from an issue's Agent Brief comment, not only its body (#51). The comment aboveHARD_EDGE_KEYWORDSalready promised the planner reads triage's inline**Depends on:** #Nlabels, butload_issuesfed onlyentry["body"]toparse_dependencies— and triage posts the Agent Brief as a comment, so a hard dependency written only there was invisible and a coupled set collapsed into one unsafe wave (the #50→#48 reproduction planned[[48, 50]]instead of[[48], [50]]).load_issuesnow runs the sameparse_dependenciesdiscipline over the body and every Agent Brief comment — selected by the sameAGENT_BRIEF_HEADING_REheading anchor_has_agent_briefuses, so only genuine briefs qualify — and unions the results (_union_signals), the body's edge provenance winning on a shared number. Non-brief comments are never scanned: triage notes, milestone markers, and grammar-quoting discussion comments are full of other issues' numbers, and scanning them would fabricate edges (the same false-positive class #47 closed). Soft phrases, self-references, and(Related: #N)asides inside a brief follow the existing clause-boundary discipline unchanged — no hard edge — and the code comment aboveHARD_EDGE_KEYWORDSis corrected to name both sources. No new keywords and no brief-specific grammar: one shared parser, two sources, a union of results._has_agent_briefnow derives from the new_agent_brief_textshelper, giving one authoritative definition of "an Agent Brief comment."tests/test_orchestrate.pycovers the #50/#48 reproduction planning as[[48], [50]], the non-brief-comment exclusion, the soft-phrase / self-reference /(Related: #N)cases inside a brief, the body∪brief union with body-wins provenance, a bare-string brief comment, and the unresolved-label warning reaching brief text — red-first./orchestrate statusno longer lets a quoted marker poison another issue's board row (#54). #48's milestone grammar deliberately carries the issue number inside each marker (orchestrate: started #47, run <runId>) so attribution is verifiable, but #50'sstatusconsumer never checked it:load_status_universeattributed everyorchestrate:marker in an issue's comments to that issue, so any comment that merely quotes the grammar — most sharply #48's own Agent Brief, which fences the templates in code — rendered a bogus row (a live#48 working startedscoped to the placeholder run<runId>, demonstrated by the integration review that found this).parse_landed_markeris intentionally prose-tolerant, which was safe only because its prior consumer, preflight, has a second factor (landedSHAs must be ancestors of the default tip);statushas none. A new_marker_attributableguard in the consumer/attribution layer restores that second factor without touching the single-source-of-truth parser: a milestone marker whose embeddednumberdiffers from the hosting issue is another issue's marker quoted here and is dropped, and arun_idstill wearing its<placeholder>angle brackets (_PLACEHOLDER_RUN_ID_RE) is an unsubstituted template example — never a run a reporter posted — so it is dropped too, which also keeps a phantom<runId>run from becoming the default scope in_resolve_runand stops a quotedopened PR #12, run <runId>(number-less, so unreachable by number attribution) from marking its hostdonethrough the any-run terminal→donefallback.tests/test_orchestrate_status.pycovers the #48-brief quoted payload, number attribution under a fully-substituted run id, and the placeholder terminal case, red-first; all existing status tests stay green./orchestrate's integrate step now structurally verifies a merge-mode landing reached disk, instead of trusting the agent not to strand it (#53). The #48 × #50 hotfix added a prompt-level guard forbidding the integrator from forcing a landing withgit update-ref/git branch -f/git push .or by flippingcore.bare, but that was advisory instruction to a mechanical-tier agent, with no positive post-condition check that the land actually reached disk and no defence when the repo was already corrupt at integrate time — a ref-only advance still looked "landed" while the working tree stayed at the pre-run commit, so the gates and the mandatory final re-run silently tested stale code. Now the integrator reports the raw post-land facts inINTEGRATE_SCHEMA—bareRepo(git rev-parse --is-bare-repository),defaultCheckedOut,headSha(git rev-parse HEADon the default after the fast-forward),featureSha(the feature-branch tip), andworktreeClean(git status --porcelainempty) — and a pure, unit-tested decision helper (landStrandedBlockerinlib/orchestrate/engine-helpers.mjs, mirrored byte-identically inline inskills/orchestrate/orchestrate.workflow.js) decides whether the land is sound: a bare repo or a default not checked out in the integrating worktree is refused before any sha comparison, and a missing sha, aHEADthat did not advance to the feature tip (a ref-only advance), or a dirty tree is a failed land. The engine — not the agent's ownintegratedflag — parks the issue with a specific blocker whenever those facts do not prove the tree advanced to the feature tip (merge mode only; PR mode lands nothing on the default), so a run can never record "landed" over stranded code. The merge-mode integrate prompt now instructs the integrator to gather and report those facts, andskills/orchestrate/SKILL.mddocuments the engine-side check.tests/test_orchestrate_workflow.pycovers the schema fields, the merge-gated engine call and its park, the prompt requirement, andlandStrandedBlocker's verdicts through node — red-first; the existing drift guard binds the two mirrored copies./orchestrate statusno longer regresses a landed-and-closed issue toqueuedon a restarted run (#48 × #50 integration). The board defaults its scope to the newest run, but a cross-session restart (#49) re-runs the whole plan, so an issue that landed-and-closed in an earlier run carries only that run's markers. Scoping to the newest run rendered every such issuequeued— silently defeating #50's own--state allamendment (which exists precisely so the board can show a done row) and wrongly answering the board's headline "was it done?".build_statusinscripts/orchestrate.pynow falls back, when an issue has no marker in the scoped run, to its latest terminaldonemarker from any run (landed/opened-pr, named by the newSTATUS_TERMINAL_VERBS); a non-terminal earlier-run marker still does not carry over, so an issue merely started in an old run and untouched in this one staysqueued.tests/test_orchestrate_status.pycovers the restart universe red-first./orchestrate's integrate step is now barred from corrupting the repository to force a landing (#48 × #50 integration). A run fast-forwarded the default branch while it was checked out in the primary worktree and setcore.bare = trueto bypass git's checked-out-branch refusal, leaving the repo(bare), the default's working tree stranded at its pre-run commit (the landed code never reached disk), and nolandedmarkers posted. The merge-mode integrate prompt inskills/orchestrate/orchestrate.workflow.js(mirrored inskills/orchestrate/SKILL.md) now requires thegit merge --ff-onlybe run from the one worktree that actually holds the default branch — so ref and working tree advance together — and explicitly forbids settingcore.bare, reconfiguring the repository, or force-advancing the default withgit update-ref/git branch -f/git push ., parking a blocker instead when the default is not checked out where the agent runs.tests/test_orchestrate_workflow.pybinds the guard structurally, red-first.- The
doctor/inittest fixtures no longer leak the git environment and corrupt the real repository under the pre-commit hook (#52). Git hooks exportGIT_DIR(and, for index-touching hooks,GIT_INDEX_FILE/GIT_WORK_TREE) into everything they run, and those outrank a fixture's-C <tmpdir>targeting — so when the pre-committestshook launched pytest, thegit_projectfixture's owngit init/add/commitran against the developer's real.git, corrupting its index and (via a straygit inithonouring the exportedGIT_DIR) flippingcore.bare = true; this was the upstream trigger of the integrate-time corruption fixed above (#48 × #50), and it had already forced--no-verifycommits twice in oneorchestraterun. A newtests/conftest.pyautouse fixture nowmonkeypatch.delenvsGIT_DIR,GIT_INDEX_FILE,GIT_WORK_TREE,GIT_OBJECT_DIRECTORY, andGIT_COMMON_DIRfrom the process environment for every test, so every git subprocess beneath pytest — the fixtures' own and the onesscripts/doctor.py/scripts/init.pyspawn when driven against temp projects — inherits a clean environment; the fixtures keep their-C <dir>targeting for ergonomics. A decoy-repo regression test intests/test_doctor.pylocks the isolation in: it seeds a throwaway repo, snapshots its.git/configand index bytes, exports the leak at the decoy exactly as the hook would, drives both a fixture-backed test and adoctor.maininvocation (its own git) in a child pytest, and asserts the decoy is byte-for-byte unchanged — red before the scrub existed, green after. As defence-in-depth thetestshookentryin.pre-commit-config.yamlnow scrubs the same variables withenv -u …before pytest starts, so even a future test that bypassesconftest.pystays isolated.pre-commit run --all-filesnow completes with the working repo's index and config intact — no--no-verifyneeded.
Full changelog: https://github.com/Kntnt/kntnt-code-skills/blob/v0.17.0/CHANGELOG.md