From predicate
Automates the deterministic campaign-execution protocol: drives dispatch/reconcile loop on a validated DAG to produce a merged branch.
How this skill is triggered — by the user, by Claude, or both
Slash command
/predicate:orchestrationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
`/orchestrate` is the **runnable layer** that executes
/orchestrate is the runnable layer that executes
docs/orchestration-protocol.md over a
live validated DAG. The protocol document is the spec — the exact procedure,
the exit-code routing, the four [HUMAN SEAM]s. This skill does not restate that
procedure; it lifts it to a state machine a runner walks and wires its abstract
steps to concrete repo commands. Where the spec says "assert the structural gate
exits 0," this skill says which command, with which arguments, and what each exit
code branches to.
It slots between campaign's §DISPATCH and §RECONCILE — the two steps campaign already delegates by reference to the protocol. Until this skill is invoked, the architect drives the protocol by hand; invoked, it drives DISPATCH ⇄ RECONCILE as a loop a cheap-tier runner can replay.
[!IMPORTANT] Non-duplication pointer. This skill does not re-specify campaign mechanics. campaign/SKILL.md §6 DISPATCH and §7 RECONCILE own the narrative (what the architect decides, the tier routing, the worker IBC contract); docs/orchestration-protocol.md owns the deterministic procedure (the pseudocode + exit-code rules). This skill is strictly the driver: it names protocol steps and sequences their commands. If you find yourself explaining why a step exists or how an architect judges, you have left orchestration space — that prose lives in campaign and the protocol, link to it.
The protocol declares the inputs an orchestrator needs
(protocol §"inputs", lines 19-24). This
skill makes them an explicit, parameterized contract — the protocol's
pseudocode and ledger/derive/layers.ncl reference the project-state DAG by a
fixed path; a driver run binds that path, it does not hardcode it.
| Parameter | Binds | Default (this repo) |
|---|---|---|
DAG | the validated DAG artifact — must pass ledger/contracts/dag.ncl (Dag ∘ DagNoConflict) | .ledger/state/dag.ncl |
LAYERS | the Kahn-layering derivation that imports DAG | ledger/derive/layers.ncl |
PLAN | the campaign plan (node intents, tier routing) | the campaign working set's PLAN.md |
PROMPTS | the per-node worker IBCs handed at DISPATCH | prompts/<node-id>-*.md |
TOPIC | the campaign topic — names the integration branch campaign/<TOPIC> and the sketch | the active flight-recorder slug |
MODE | AUTONOMOUS (resolve seams by policy / escalate) or INTERACTIVE (surface seams to the human) | INTERACTIVE |
layers.ncl imports DAG internally; pointing the driver at a different DAG
(e.g. a demonstration graph) means binding the import that LAYERS resolves, not
editing the derivation. The driver never improvises a schedule — it nickel exports LAYERS and reads the result.
The driver must LOCATE its own recorder and REACH neighboring context. The convention is fixed, so both are mechanical, not discovered:
.ledger/, a nested repo) — not loose files.git -C <recorder> branch --show-current; in this repo, the branch named
for the project umbrella).git -C <recorder> log <sibling-branch> -- log/),
never by leaving the repo or guessing paths.log/ of the recorder; project-state
artifacts (the DAG, reconcile log) under state/.This lets the driver resolve its recorder, its branch, and its siblings by query — and lets it enforce the convention (a campaign that writes loose sketch files outside the recorder repo is malformed).
The orchestrator's entire state is reconstructable from git + the sketch
checkpoint (rules.md §2 Prime Invariant 5; protocol §State).
Per node: STATUS ∈ {PENDING, DISPATCHED, LANDED, ACCEPTED, REWORK, INVALIDATED},
its worktree and branch. Globally: shared_branch (the integration branch),
tip (the commit the current layer branches from), layers (the derived Kahn
schedule). No state lives only in the runner's memory — every transition lands in
git or the sketch.
Resuming a partial campaign is reconstruction, not recall (rules.md §7, sharpened for episodic memory). The procedure is log-first and it is a hard rule, not a convenience:
git -C <recorder> log --oneline -- log/ and the live git log (project
tree). The recorder's campaign-lifecycle commits are subject-tagged: an
episode opens with a log: open <topic> … commit and closes with a
log: close <topic> … commit (the convention the sketch discipline writes).
The log says what happened, when, with what status — which layers landed,
which nodes are ACCEPTED, where the run halted.log: history contains a close commit for it
with no later open:
git -C <recorder> log --grep='^log: \(open\|close\) <topic>' --format='%s'
— if the most recent matching subject is a close, the episode is finished
(index entry only); if it is an open (or the topic has an open with no
close), the episode is in-flight. This is the field the gate keys on; the
sketch is never opened to decide it.log: marker is open, matching TOPIC / the
current branch), full-read that sketch alone. Reconstruct STATUS, tip,
shared_branch, and the RECONCILE_LOG cursor from it + git.log:
marker is close is an index entry, not working context. Only the in-flight
episode is loaded.The log is the map; exactly one sketch is the territory. (Prime Invariant 5, "reconstruct, don't recall.")
The protocol's pseudocode (DRIVE / RUN_LAYER / RECONCILE_AND_MERGE /
SURFACE_EXCEED / CLOSE) lifts to a state machine: each protocol step is a
state, each exit-code rule is a transition. The runner walks the table; it never
chooses the next action — the table + the exit code compute it.
The DERIVE state writes the active-dag pointer ($root/.ledger/active-dag,
one line = the bound DAG path, relative-to-$root or absolute) once the
structural gate exits 0 — from that point every worker-worktree commit and
integration-branch commit enforces authority against the active plan (the commit
gate's authority overlay, hooks/pre-commit §4, reads line 1 of this file).
CLOSE — and any campaign-ending halt — clears it (rm -f $root/.ledger/active-dag)
so post-campaign ordinary commits revert to structural-only.
| State | Lifts (protocol) | Action (the wired command) | Transition |
|---|---|---|---|
DERIVE | DRIVE head, "Derived schedule" | nickel export DAG (structural gate); then nickel export LAYERS → {layer_count, layers}; on rc 0: printf '%s\n' "$DAG" > $root/.ledger/active-dag | export rc≠0 → HALT (the DAG is malformed; not a driver decision). rc 0 → create shared_branch from HEAD, tip := HEAD, k := 0 → RUN_LAYER |
RUN_LAYER | RUN_LAYER step 1 (PARTITION) | read layers[k]; split into serial (nodes with serialize=true) and parallel := layer \ serial — a read of the validated DAG, not a fresh conflict computation (DagNoConflict already proved the parallel set disjoint) | → DISPATCH for the parallel set |
DISPATCH | RUN_LAYER step 2, DISPATCH | per node: git worktree add .scratch/worktrees/<id> -b node/<descriptive-slug> <base> — the worktree directory stays the generic node <id> (so dirs don't proliferate), but the branch is a descriptive slug so stacked branches/PRs self-describe; hand the worker ONLY PROMPTS/<id>-*.md + its discipline; STATUS := DISPATCHED | all dispatched → AWAIT |
AWAIT | RUN_LAYER step 2, AWAIT | workers run autonomously, commit in their worktree under their discipline's commit gate, never push; collect each return | a worker FREEZE (surface-exceed) → SURFACE_EXCEED; FREEZE (refuted premise) → REALIGN; any other reserved halt → [HUMAN SEAM]; all returned → RECONCILE |
SURFACE_EXCEED | SURFACE_EXCEED | authorized.py --collision-check --path <req> --against-surfaces <concurrent surfaces> | rc 0 (WIDEN) → widen node surface, re-export DAG (must pass Dag ∘ DagNoConflict), resume worker → AWAIT. rc 3 (SERIALIZE) → mark serialize=true, re-export, re-schedule into serial → RUN_LAYER |
RECONCILE | RECONCILE_AND_MERGE (1)-(5) | for each LANDED node in node-id order, run the boundary checks (below); compute VERDICT. Process-adherence gate (first node only): bash ledger/gate/adherence_audit.sh <baseline> <shared_branch> — rc 1 → HALT (isolation bypass detected; surface diagnostic to human before any merge proceeds) | ACCEPT → MERGE; REWORK → emit corrective delta IBC, re-dispatch from current tip, STATUS := PENDING → DISPATCH; ESCALATE → REALIGN or [HUMAN SEAM] |
MERGE | RECONCILE_AND_MERGE (5) ACCEPT | merge the accepted node branch(es) into shared_branch with the strategy the situation calls for: individual --no-ff for sequential or distinct-concern landings; an octopus merge when a concurrent layer of one parallel job lands together. The invariant is a merge-based history, not the specific strategy — the adherence audit accepts any merge commits and only rejects direct first-parent commits. STATUS := ACCEPTED; mark mitigated findings | → CHECKPOINT |
BOUNDARY | LAYER_BOUNDARY | (1) cumulative-diff coherence gate: coherence_impact.sh --removed <cut-set> over the layer's cumulative diff. (2) DAG vs goal re-examination (campaign §Goal Supremacy): does the remaining DAG still serve the goal? If amendments (add/edit/remove nodes) are warranted, surface them as [HUMAN SEAM] — a node addition is a boundary the human signs off on before any affected node is re-dispatched. | coherence rc 1 → ESCALATE. rc 0, no DAG amendment → advance the tip. rc 0, amendment needed → [HUMAN SEAM]: halt, surface the amendment; on approval re-export DAG + LAYERS, then advance the tip. |
CHECKPOINT | RECONCILE_AND_MERGE (6) | append a RECONCILE_LOG round (judged verdicts, freshness, realignments) to the active sketch; commit it in the recorder (git -C <recorder> commit) | more nodes in layer → RECONCILE; layer done → BOUNDARY; BOUNDARY rc 0 and k+1 < layer_count → tip := shared_branch HEAD, k++ → RUN_LAYER; last layer → CLOSE. BOUNDARY rc 1 → ESCALATE → architect realigns the plan/DAG (PLAN), then re-dispatch |
REALIGN | REALIGN | rewrite the node's premises/surface to current HEAD; if topology/surfaces change, re-export DAG + LAYERS (schedule may change); STATUS := PENDING; log it | → DISPATCH (or RUN_LAYER if the schedule changed) |
CLOSE | CLOSE | assert every finding MITIGATED/accepted + every node ACCEPTED; run the full deterministic surface over shared_branch; process-adherence gate: bash ledger/gate/adherence_audit.sh <baseline> <shared_branch> — rc 1 → HALT (protocol deviation in history; a CLOSE that bypassed RECONCILE's gate or ran pre-gate must not pass CLOSE); ONE final decorrelated MBSS sweep over the cumulative diff; emit the retrospective to .ledger/log/ (commit log: close <topic> retrospective in the recorder — content per campaign §CLOSE); recorder-close gate: bash ledger/gate/recorder_close_check.sh <topic> — rc≠0 → HALT (the retrospective was not recorded; CLOSE must not complete without the durable record); produce the campaign report; rm -f $root/.ledger/active-dag | → [HUMAN SEAM]: HALT for human final acceptance + any push |
sort is node-id order throughout: a fixed reconcile order makes the run
replayable — re-running from a checkpoint reproduces the same sequence.
For each LANDED node (in node-id order), the RECONCILE state runs, in order
(protocol §RECONCILE_AND_MERGE):
# (1) JUDGE THE CHANGESET — the worker's self-report is not evidence.
# Re-run the evaluators the node's IBC names in its acceptance criteria
# against its worktree. Any evaluator non-zero -> VERDICT := REWORK.
# (2) SURFACE HONESTY — derive the actual touched set, reconcile vs declared.
touched=$(git -C .scratch/worktrees/<id> diff --name-only <base>..HEAD)
python3 ledger/gate/authorized.py --dag <exported-DAG.json> \
--reconcile-node <id> $(printf -- '--path %s ' $touched)
# rc 0 -> stayed within declared surface
# rc 1 -> undeclared touches: run SURFACE_EXCEED on each before proceeding
# (3) BIDIRECTIONAL COHERENCE-IMPACT — does this landing break landed/pending?
bash ledger/gate/coherence_impact.sh <repo-root> [--removed <workflow> ...]
# rc 1 -> INCOHERENT (a machine-check failed): VERDICT := REWORK
# rc 0 -> machine-surface coherent; record any decorrelated-review DISPATCH
# lines and their converged verdict before ACCEPT (adversarial path)
# (4) PREMISE-FRESHNESS — re-verify EVERY pending node against the new HEAD.
for p in <pending nodes>; do
bash ledger/gate/premise_fresh.sh <p-id> <p's tripwire spec>
# rc 1 -> p INVALIDATED: REALIGN p's IBC before it dispatches
# rc 0 -> p stays FRESH
done
# (5) VERDICT: ACCEPT (1-4 clean, reviews converged) -> MERGE; else REWORK/ESCALATE.
[!IMPORTANT] File-surface disjointness ≠ semantic independence.
DagNoConflictproves the parallel set's file surfaces are disjoint — it cannot see that a node's cut or rename orphaned a reference living in a surviving file owned by nobody in this layer. This campaign learned it the hard way: removing a workflow left dangling references the conflict gate was structurally blind to, and they surfaced at CLOSE instead of at a boundary. So theLAYER_BOUNDARYstep (protocol §LAYER_BOUNDARY) runs a semantic/reference-coherence gate over the layer's cumulative diff, for the campaign's whole cut-set — not merely the per-node surface honesty of RECONCILE step (2). This is a genuine evolution of the protocol the spec now carries.
At each layer edge, before advancing the tip, BOUNDARY runs one command —
coherence_impact.sh already runs the contract export, the orphan gate
(check_orphans over the cut-set, internally at coherence_impact.sh:88), and
the markdown-link gate, so no separate check_orphans call is needed:
# coherence-impact over the LAYER's cumulative diff for the campaign's cut-set.
# Internally: contract export + orphan gate (over --removed) + link gate.
bash ledger/gate/coherence_impact.sh <repo-root> --removed <cut-1> --removed <cut-2> ...
# rc 0 -> the layer is semantically coherent; advance the tip.
# rc 1 -> INCOHERENT: a cut/rename orphaned a cross-node reference. The fault
# is NOT localizable to one node (the broken ref and the cut that broke
# it live in DIFFERENT nodes' surfaces), so it does NOT route to
# single-node REWORK. It routes to ESCALATE -> PLAN: the architect
# realigns the plan/DAG for the cross-node coupling, then re-dispatches
# the affected nodes. (This campaign's own cross-node couplings were
# resolved exactly this way — an architect plan-fault, not a node fault.)
This is a boundary gate (cumulative diff, whole cut-set), not the per-node
check — it catches cross-node orphaning a single node's reconcile cannot see.
Because index-sensitive evaluators give false failures while a worker has
uncommitted changes, BOUNDARY runs only at a quiescent layer edge (all of
this layer's worktrees merged or idle).
demo/ is a recorded end-to-end run of this driver over a small
synthetic DAG (demo/dag.ncl: 2 layers, a conflict-free parallel
pair, one serialize edge), with demo/layers.ncl the live
schedule derivation bound to that fixture. demo/TRANSCRIPT.md
records every command and its actual gate exit code: schedule derivation →
worktree dispatch → the authorized.py reconcile checks → the --collision-check
serialize/widen routing (rc 3 / rc 0) → premise_fresh.sh → merge --no-ff →
the LAYER_BOUNDARY coherence gate (GREEN rc 0 and a RED rc 1 → ESCALATE). A
reviewer reproduces the schedule with the two nickel export commands at the top
of the transcript.
campaign/<TOPIC> integration branch — every ACCEPTED node arriving
via a merge (strategy per situation; never a direct commit), in
layer-then-node-id order, branched from the advancing tip.state/reconcile_log.ncl /
the sketch): one round per boundary — judged verdicts, freshness results,
realignments, the gate that justified each ACCEPT.This skill carries the autonomy seam as an abstraction point; it is not a
programmatic hermes engine (out of scope). The protocol marks exactly four
[HUMAN SEAM]s (protocol §automatability boundary);
everything else is deterministic-or-dispatched. At each seam, MODE decides:
| Seam | Where (state) | AUTONOMOUS | INTERACTIVE |
|---|---|---|---|
| Final acceptance + push | CLOSE | resolve-by-policy is forbidden — a release is a sovereignty decision; HALT and escalate regardless | HALT; surface the CLOSE report; the human accepts + pushes (agents never push — rules.md §3) |
| Non-resolvable reserved halt | AWAIT/DISPATCH | escalate to the human (a reserved predicate is, by definition, a human call) | surface the worker's freeze report |
| Decision-rights realignment | RECONCILE/REALIGN | resolve only if inside the IBC's declared sovereignty gates; else escalate | surface the realignment question |
| Non-converging adversarial review | RECONCILE step (3) | escalate (the dual escalates to human when decorrelated reviewers do not converge — rules.md §2 Invariant 1) | surface the divergence |
Push and final acceptance are never resolved by policy in either mode:
remotes belong to the human (rules.md §3). The other three seams resolve by
policy in AUTONOMOUS only when the call is inside a declared sovereignty
gate, and surface in INTERACTIVE.
The worktree-isolated, dependency-layered, merge-at-boundary execution pattern
this driver implements is a well-established production pattern, not a novelty.
The grounding references are recorded in the active campaign's flight recorder
(the in-flight sketch under the recorder's log/, located by the resume
procedure above — <recorder>/log/<active-topic>.md, its OSR1 prior-art block)
per the Outward-Search Reflex and the
prior-art
procedure: parallel make -j and Apache Airflow (DAG-derived independent units
run concurrently, dependents wait on upstreams) anchor the layering; Bazel's
per-action execroot/ sandbox and git-worktree (one repo, many isolated
working trees from a common object store) anchor the per-unit isolation. The
driver's contribution is binding that pattern to git worktrees as the isolation
primitive and the Verification Dual's gates as the merge-boundary check (the
prior art integrates by artifact, not by a coherence-gated --no-ff merge).
ledger/gate/authorized.py,
ledger/gate/coherence_impact.sh, ledger/gate/premise_fresh.sh,
gates/check_orphans.sh.npx claudepluginhub nrdxp/predicate --plugin predicateOrchestrates multi-model campaign workflows (/campaign) with exhaustive survey, mitigation planning, tiered dispatch, and premise-freshness reconciliation for architect-class agents.
Autonomous multi-session campaign agent that decomposes large work into phases, delegates to sub-agents, reviews output, and maintains campaign state across context windows.
Defines a 4-phase execution loop (IMPLEMENT, VALIDATE, ADVERSARIAL REVIEW, COMMIT) for orchestrating complex multi-step work units with written specs and quality gates.