Skip to content

feat!: newcomer safety — block unmanaged overwrites, snapshot/restore, safe default names, YAML upload - #14

Merged
machado144 merged 1 commit into
mainfrom
feat/newcomer-safety
Jul 9, 2026
Merged

feat!: newcomer safety — block unmanaged overwrites, snapshot/restore, safe default names, YAML upload#14
machado144 merged 1 commit into
mainfrom
feat/newcomer-safety

Conversation

@machado144

Copy link
Copy Markdown
Contributor

Why

A first-time user who imports someone else's bundle (.tar.gz or .loadout.yaml) and runs loadout sync could have their own pre-existing agent config silently overwritten — skills/commands/hook-scripts are whole-file writes, and engine.Apply never consulted install state. There was no backup and no undo. Separately, generated command names like plan collide with Claude Code's built-in /plan.

This PR closes both gaps. Bundle import was already safe (store-only, gated); the danger was at sync time.

What changed

Sync safety (spec 004)

  • Conflicts blocked by default. A MergeReplace target that exists on disk but loadout never installed (or can't prove it owns) is a conflict — skipped. --force (CLI) / a checkbox (web) overwrites on purpose. Skipped conflicts are not recorded in state, so they can't be clobbered on a later sync (regression-tested).
  • Auto-snapshot + loadout restore. Before any overwrite/delete, originals are copied to a timestamped machine-local backup (fail-closed). loadout restore lists/restores them; restores are themselves snapshotted and never touch install state. Retention via backups.keep (default 10).

Naming safety (spec 005)

  • Namespace prefix in the wizard: /plan/af-plan, applied to defaulted names only (explicit renames win).
  • Reserved-name warnings (advisory, never blocking) in wizard, loadout new, bundle import, doctor.
  • Web import accepts .yaml/.yml files (backend already content-sniffed).

Breaking change

loadout sync no longer overwrites files it did not install. Pass --force to opt in (a snapshot is taken first).

Verification

  • go test -race ./... — 222 pass · golangci-lint 0 issues · gofmt clean
  • web: 45 tests + tsc clean · make build-web committed
  • integration (real binary, temp HOME) — 40 pass
  • Cross-feature end-to-end: import a flat-YAML bundle with a reserved-name plan command → naming warning fires → sync blocks the clobber of the user's own plan.md--force + restore brings the original back byte-for-byte.

Specs: docs/specs/004-sync-safety.md, docs/specs/005-naming-safety.md

🤖 Generated with Claude Code

…, safe default names, YAML upload

Protects a first-time user who imports a shared bundle and syncs from silently
destroying their own agent config, and stops generated names from clashing
with agent built-ins.

- Sync (spec 004): a whole-file target that exists on disk but loadout never
  installed is a conflict — skipped by default; --force (CLI) / a checkbox
  (web) overwrites on purpose. Before any overwrite or delete, originals are
  snapshotted to a machine-local backup; `loadout restore` recovers them.
- Naming (spec 005): optional wizard namespace prefix (/plan -> /af-plan);
  advisory reserved-name warnings in wizard, `new`, `bundle import`, `doctor`;
  the web import file picker accepts .yaml/.yml (backend already sniffed).

BREAKING CHANGE: `loadout sync` no longer overwrites files it did not install;
pass --force to opt in (a snapshot is taken first).

Specs: docs/specs/004-sync-safety.md, docs/specs/005-naming-safety.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

StructLint — All checks passed

276 rules validated against .structlint.yaml. No violations found.

View full run · Powered by StructLint

@machado144
machado144 merged commit e5b77fb into main Jul 9, 2026
6 checks passed
@machado144
machado144 deleted the feat/newcomer-safety branch July 9, 2026 17:17
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