Skip to content

Manifest-driven deploy: pilot driver with dry-run, backup-on-conflict and audit#10

Draft
nonrational wants to merge 8 commits into
mainfrom
worktree-manifest-deploy-spike
Draft

Manifest-driven deploy: pilot driver with dry-run, backup-on-conflict and audit#10
nonrational wants to merge 8 commits into
mainfrom
worktree-manifest-deploy-spike

Conversation

@nonrational

@nonrational nonrational commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Spike for #6, answered yes: a small manifest + bash driver reaches parity with link-dotfiles.sh for the pilot slice, with no external engine. Full findings: #6 (comment)

What

  • deploy.sh (162 lines, bash 3.2 + coreutils only). Reads a 3-column manifest (source, target, optional os=/host= condition) and reconciles each matching entry to a symlink. Modes: apply (default), --dry-run, audit. Validates the whole manifest before acting; backup-on-conflict is non-interactive and refuses to clobber an existing .bak; entries whose condition doesn't match are skipped, never removed.
  • manifest. Pilot slice only: bin.Darwin, bin.Linux, .bashrc.nyx. link-dotfiles.sh is untouched and keeps handling everything else until migration.
  • test_deploy.sh. 23 tests, fully sandboxed (own repo copy + fake $HOME under mktemp); covers fault injection and a checksum proof that --dry-run changes nothing.
  • Design spec and implementation plan under docs/superpowers/.

Verification

  • ./test_deploy.sh: 23 passed, 0 failed on /bin/bash 3.2.
  • Live parity on nyx (run from the main checkout): deploy.sh --dry-run apply proposes zero changes; deploy.sh audit exits 0. Output captured in the findings comment.

Next steps (post-merge)

  • Migrate remaining dotfiles into the manifest a few at a time.
  • Drop the bin.$(uname) special case from link-dotfiles.sh once the manifest covers it.

nonrational and others added 8 commits July 6, 2026 15:26
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Parses [--dry-run] [apply|audit] and validates every manifest line
(column count, condition key, source existence) before acting.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117PaLyHdWjQwzFbdP34Hft
Reconciles each condition-matched manifest entry: correct link is a
no-op, missing target is linked (creating parents), wrong symlink is
replaced, and a regular file or directory is moved to <target>.bak
first. Refuses to clobber an existing .bak and exits non-zero instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117PaLyHdWjQwzFbdP34Hft
Prints the same per-entry decisions prefixed "would:" and touches
nothing, proven in tests by checksumming the tree before and after.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117PaLyHdWjQwzFbdP34Hft
Read-only drift report per manifest entry: ok, missing or drift, with
non-zero exit when anything is missing or drifted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117PaLyHdWjQwzFbdP34Hft
Verified against the live machine from the main checkout: dry-run
apply proposes zero changes and audit exits clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117PaLyHdWjQwzFbdP34Hft
Reject targets that are neither absolute nor ~/-prefixed (a dropped
prefix would otherwise scatter symlinks relative to the CWD), and make
condition_matches fail closed on unrecognized conditions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117PaLyHdWjQwzFbdP34Hft
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