feat(rig-sync): spec ⇄ code reconciler — M0–M2 (plan + drift engine + durable Smithers sink) - #45
Merged
Merged
Conversation
A design-draft skill: treat the spec as desired state and code as actual state, compute bidirectional drift (plan, read-only), then reconcile via a pluggable sink — an ephemeral Smithers workflow (default), a tracked milestone of tickets, or report-only. Never edits product code directly; work lands through gated rig-task/rig-plan or a Smithers workflow lane. Modeled on rig-plan; extractor is a project-supplied adapter (rig-tracker pattern). Not wired into DEFAULT_SKILLS — proposal for discussion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
pgebheim
force-pushed
the
worktree-rig-sync-skill
branch
from
July 31, 2026 18:05
7442491 to
b356f58
Compare
demos/ is a home for try-it sandboxes. notes-api ships a spec, Express-style code with three planted drifts (missing DELETE, PUT<->PATCH divergence, undocumented GET /health), a real grep-based extractor adapter, and the rig-sync skill + rig-architect agent copied in so /rig-sync plan runs in place. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
- SPEC.md for rig-sync (plan/apply, durable Smithers workflow sink, extractor adapter) — the backlog on agent-rig board #1. - T1: sync.* config block in schema + example. - T3: scripts/rig-sync.ts computeDrift — directional bidirectional diff by (kind,id): missing / undocumented / diverged / aligned + carried invariants. 16 bun tests; reproduces the notes-api demo drift from the real extractor. - T4: renderReport + 'report' verb -> terraform-plan-style .rig/DRIFT.md. - Dogfood: .rig/config.json points rig at agent-rig board #1. Refs #46 #48 #49 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
… (M0 T2,T5) - T2: validateSurfaceDoc + 'validate-extractor' verb (rejects malformed adapter output with exit 1); docs/rig-sync.md contract + reference extractor; validated against the real notes-api extractor. 23 bun tests. - T5: SKILL plan verb wired to scripts/rig-sync.ts (extractor resolver -> validate -> desired surface -> diff/report -> STOP). Corrected the apply/ workflow wording to the durable, parameterized Smithers workflow model (run once, drift as input; never make-workflow; engine-agnostic). M0 complete (T1-T5). Refs #47 #50 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
- T6: driftToUnits — routes each drift item by truth (missing=work always; diverged/undocumented -> work|doc|decision by spec|code|ask). - T7: renderDriftSpec + 'spec' verb -> the report sink's .rig/plan.md; also the input /rig-plan decomposes for the backlog sink (T8, SKILL-wired). 28 bun tests. Refs #51 #52 #53 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
…10,T11) - T9: smithers/workflows/rig-sync.tsx — parameterized reconcile workflow (driftReport units as INPUT, not regenerated): verify-drift -> plan gate -> per-unit Worktree + coder/reviewer Ralph lanes -> merge gate -> MergeQueue -> final-verify. Renders under `smithers graph` (verified with real notes-api drift input). Authored once, run many; engine-agnostic (agents from the target project's smithers/agents.ts). - T10: 'workflow-input' verb -> deterministic drift -> the workflow's --input. - T11: engine-agnostic docs (docs/rig-sync.md). M2 complete. Refs #54 #55 #56 #57 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
…hildren Running the reconcile workflow end-to-end surfaced a real bug: nesting the per-unit lanes + merge-gate + final-verify as CHILDREN of <Approval> did not schedule them — the run finished right after plan-gate approval (only verify-drift + plan-gate executed). Switched to rig EpicFlow's convention: Approval is a decision node, and subsequent steps render conditionally on ctx.outputMaybe(gate)?.approved. Verified: after approval the coder/reviewer lanes now dispatch (impl-* + review-* nodes go live). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
Second run-only bug: unit ids like 'DELETE /notes/{id}' were used verbatim as
the git branch (rig-sync/DELETE /notes/{id}) and worktree path — invalid ref
(spaces, slashes, braces), so every lane failed at worktree creation (12
retries, ~18min, zero coding). Added slug() and applied to branch/path + node
ids. Verified: the worktree now creates and the coder agent runs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
…eam) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
…ts dependency Downstream testing surfaced two real problems: (1) smithers init generates Codex/Fable-first agent pools that most Claude users don't have, and rig-sync inherited them by importing ../agents; (2) editing agents.ts to fix that fights Claude Code's bg-isolation. Both vanish if the workflow doesn't touch agents.ts: the two seats (coder, reviewer) now default to ClaudeCodeAgent inline, so it runs out of the box with no agents.ts to configure. Still multi-modal — swap the seats for your own agents.ts pools. Renders under smithers graph with no agents.ts present. Docs/SKILL wording corrected (Claude default, overridable). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM
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.
rig-sync — the terraform loop for code: treat the spec as desired state, code as actual state, compute drift (
plan), reconcile it (apply). Built by dogfooding rig itself:SPEC.md→ agent-rig board #1 → gated build.What's implemented (M0–M2, 28
buntests, all green)M0 —
plan(read-only drift)sync.*config block (rig.schema.json+ example).scripts/rig-sync.tscomputeDrift— directional bidirectional diff keyed by(kind,id)→ missing / undocumented / diverged / aligned + carried invariants.reportverb → terraform-plan-styleDRIFT.md.validate-extractorverb — enforces the adapter contract.planverb wired to the script (extractor resolver → validate → diff → report → STOP).M1 —
applysinksdriftToUnits— routes each drift item bytruth(missing=work; diverged/undocumented → work|doc|decision).reportsink (specverb →.rig/plan.md);backlogsink (→/rig-plan, SKILL-wired).M2 — durable
workflowsinksmithers/workflows/rig-sync.tsx— parameterized reconcile workflow (drift as input, not regenerated per run): verify-drift → plan gate → per-unitWorktree+ coder/reviewer lanes → merge gate →MergeQueue→ final-verify. Renders undersmithers graph(verified with real notes-api drift). Multi-modal / engine-agnostic (workers from the target project'ssmithers/agents.ts).workflow-inputverb — deterministic drift → the workflow's--input.docs/rig-sync.md— extractor adapter contract + engine-agnostic notes.Verified end-to-end against
demos/notes-api: real extractor → diff → report → drift-spec → workflow-input → workflow renders.Key design decisions
make-workflowis an authoring tool, not a runtime sink. The reconcile workflow is authored once, parameterized by drift — no 40-min per-apply generation.report/backlogsinks need no runtime. rig-sync picks no model/engine.Remaining
🤖 Generated with Claude Code
https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM