Skip to content

feat(rig-sync): spec ⇄ code reconciler — M0–M2 (plan + drift engine + durable Smithers sink) - #45

Merged
pgebheim merged 10 commits into
feature/smithersfrom
worktree-rig-sync-skill
Aug 1, 2026
Merged

feat(rig-sync): spec ⇄ code reconciler — M0–M2 (plan + drift engine + durable Smithers sink)#45
pgebheim merged 10 commits into
feature/smithersfrom
worktree-rig-sync-skill

Conversation

@pgebheim

@pgebheim pgebheim commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

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.mdagent-rig board #1 → gated build.

What's implemented (M0–M2, 28 bun tests, all green)

M0 — plan (read-only drift)

  • sync.* config block (rig.schema.json + example).
  • scripts/rig-sync.ts computeDrift — directional bidirectional diff keyed by (kind,id)missing / undocumented / diverged / aligned + carried invariants.
  • report verb → terraform-plan-style DRIFT.md.
  • validate-extractor verb — enforces the adapter contract.
  • SKILL plan verb wired to the script (extractor resolver → validate → diff → report → STOP).

M1 — apply sinks

  • driftToUnits — routes each drift item by truth (missing=work; diverged/undocumented → work|doc|decision).
  • report sink (spec verb → .rig/plan.md); backlog sink (→ /rig-plan, SKILL-wired).

M2 — durable workflow sink

  • smithers/workflows/rig-sync.tsx — parameterized reconcile workflow (drift as input, not regenerated per run): verify-drift → plan gate → per-unit Worktree + coder/reviewer lanes → merge gate → MergeQueue → final-verify. Renders under smithers graph (verified with real notes-api drift). Multi-modal / engine-agnostic (workers from the target project's smithers/agents.ts).
  • workflow-input verb — 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-workflow is an authoring tool, not a runtime sink. The reconcile workflow is authored once, parameterized by drift — no 40-min per-apply generation.
  • Smithers for execution (durable, resumable-over-days, multi-modal); the report/backlog sinks need no runtime. rig-sync picks no model/engine.
  • Never edits product code directly — all through gated lanes.

Remaining

  • M3 / T12 (optional projection layer) — Todo on the board.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GHxxuWxnyaNz3cZkcxmnRM

@pgebheim
pgebheim changed the base branch from main to feature/smithers July 31, 2026 18:04
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
pgebheim force-pushed the worktree-rig-sync-skill branch from 7442491 to b356f58 Compare July 31, 2026 18:05
pgebheim and others added 5 commits July 31, 2026 18:17
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
@pgebheim pgebheim changed the title draft(rig-sync): spec ⇄ code reconciler (terraform loop for code) feat(rig-sync): spec ⇄ code reconciler — M0–M2 (plan + drift engine + durable Smithers sink) Jul 31, 2026
pgebheim and others added 4 commits July 31, 2026 22:52
…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
@pgebheim
pgebheim marked this pull request as ready for review August 1, 2026 19:51
@pgebheim
pgebheim merged commit 714c857 into feature/smithers Aug 1, 2026
1 of 2 checks passed
@pgebheim
pgebheim deleted the worktree-rig-sync-skill branch August 1, 2026 19:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant