Skip to content

Sync handoff + state across machines via refs/cdd/<branch>#53

Merged
drabaioli merged 2 commits into
mainfrom
task_ref_sync
Jul 21, 2026
Merged

Sync handoff + state across machines via refs/cdd/<branch>#53
drabaioli merged 2 commits into
mainfrom
task_ref_sync

Conversation

@drabaioli

Copy link
Copy Markdown
Owner

Summary

Completes multi-machine resume (issue #22): the handoff (<branch>.md) and state record (<branch>.state.json) now sync across machines via a per-task ref refs/cdd/<branch> on origin.

  • Push (cdd-state, on seed/set): bundles the two files into a git tree (stable in-tree names handoff.md / state.json), wraps it in a parentless commit under a fixed cdd/cdd@local identity, and force-pushes (latest-wins). Plumbing only — never touches the index or working tree. No slash-command changes: the push funnels through the state helper.
  • Fetch + materialize (cdd-worktree-resume, before it finishes): fetches the ref and materializes both files into ~/.cdd/handoffs/<repo>/. Handoff is immutable after seed (written only when absent locally); state record follows most-advanced-stage-wins.
  • Cleanup (cdd-worktree-done): best-effort deletes the remote ref when the branch is deleted.
  • Advisory end-to-end: no origin / offline / missing jq / no ref all warn-and-continue, so a resume with no ref behaves exactly as before. git notes was rejected because it anchors metadata to a commit and must chase the moving branch tip; the branch-keyed ref does not.

Testing

  • New scripts/ref-sync-assert.sh (wired into template-smoke.yml) drives a local bare origin with two separate-$HOME clones as machines A/B and asserts: push on seed/set, byte-for-byte handoff materialize + advanced state, most-advanced-wins in both directions, immutable-handoff preservation, and the clean no-ref path — with a stubbed claude guarding it is never launched.
  • All existing gates pass: shellcheck, command-set drift, prompt-seam, install smoke, worktree-resume smoke, template end-to-end smoke, demo seed-overlay smoke.

Docs

Process doc §2.8/§2.13, doc/architecture/shell-helpers.md (new "Task-ref sync" section), README, CLAUDE.md build section, and roadmap all reconciled.

Closes #22

🤖 Generated with Claude Code

drabaioli and others added 2 commits July 20, 2026 22:33
The handoff (<branch>.md) and state record (<branch>.state.json) were
out-of-tree, per-user files stranded on the machine that created them.
cdd-worktree-resume recreated only the code branch. Carry the two files
across machines through a per-task git ref.

- cdd-state (seed + set): bundle whichever of the two files exist into a
  git tree under stable in-tree names (handoff.md/state.json), wrap it in
  a parentless commit, and force-push to refs/cdd/<branch> on origin.
  Plumbing only (hash-object/mktree/commit-tree) so the live worktree is
  never touched; fixed cdd/cdd@local identity so it never depends on user
  git config. Sits under the existing jq guard. Advisory/best-effort:
  any failure warns and returns 0, never failing the state write.
- cdd-worktree-resume: before it finishes, fetch refs/cdd/<branch> and
  materialize both files into ~/.cdd/handoffs/<repo>/. Handoff is
  immutable so it is written only when locally absent; state follows
  most-advanced-stage-wins (compare .stage enum indices), falling back to
  write-only-if-absent without jq. Byte-exact extraction. No ref ->
  resumes exactly as before, with an honest message.
- cdd-worktree-done: best-effort delete of refs/cdd/<branch> on origin
  when it deletes the branch, so the namespace does not accumulate.

No slash-command changes (the push funnels through cdd-state). New smoke
scripts/ref-sync-assert.sh covers the round-trip, byte-for-byte
materialize, both directions of the heuristic, and the no-ref path;
wired into CI and CLAUDE.md. Process doc SS2.8/SS2.13, shell-helpers.md,
roadmap, and README updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-task ref sync leaves cdd-worktree-done as the only reaper of the
handoff, state record, and refs/cdd/<branch>, so they leak when done never
runs, its ref delete fails offline, or a multi-machine resume leaves
materialized copies on every machine but the one where done ran.

cdd-worktree-gc [--force] sweeps them, reaping ONLY tasks whose PR has
merged — a merged PR is the sole trustworthy "done" signal, since a
scoped-but-unstarted task's handoff and ref exist before its branch does
and so can't be told apart by branch/ref presence. Enumerates local
handoffs plus refs/cdd/* so any machine can reap leaked refs and its own
orphaned locals; dry-run unless --force; needs gh for PR state.

scripts/gc-assert.sh (stubbed gh, local bare origin) + CI step; process
doc §2.8, shell-helpers.md, roadmap, README, CLAUDE.md reconciled.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@drabaioli
drabaioli merged commit d685c89 into main Jul 21, 2026
1 check passed
@drabaioli
drabaioli deleted the task_ref_sync branch July 21, 2026 20:19
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.

Recreate a worktree on a new machine

1 participant