feat(agents-cleanup): reverse an agents-init scaffold and opt a project out #183

Merged
rootiest merged 11 commits from feat/agents-cleanup into main 2026-09-30 21:46:51 +00:00
Owner

Summary

Adds agents-cleanup, which undoes agents-init in a project, and an opt-out marker that agents-init honors. Once a project is cleaned, claude/agy launches no longer scaffold it again.

agents-cleanup

  • Every symlink into AGENTS/ becomes the real file or directory it points to.
    • When two links share a target, the shallower one wins, e.g. docs/plans over docs/superpowers/plans.
    • Links to .gitkeep-only targets, dangling links, and links to AGENTS/ itself are removed.
  • AGENTS.md handling:
    • An AGENTS.md that is exactly the agents-init stub is deleted.
    • Any other AGENTS.md loses only the "SYSTEM DIRECTIVE" blockquote.
  • Before anything moves:
    • Pending AGENTS/ changes are committed.
    • The full history goes to a verified git bundle in ${XDG_STATE_HOME:-~/.local/state}/agents-cleanup/.
    • Only then are AGENTS/, the docs/superpowers/ and docs/ directories if left empty, and the Added by agents-init blocks in .gitignore removed.
  • Never commits to or touches the outer repo's index. Every change is a working-tree change for you to commit or revert.
  • Refuses before changing anything when:
    • AGENTS/ holds unlinked files (--drop-extras overrides this).
    • AGENTS/ contains nested git repos (no override).
    • AGENTS/ is itself a symlink.
    • A rebase is in progress.
  • A failed move restores its link, and every rewrite is checked, so a re-run resumes where it stopped.
  • Flags: --dry-run, --drop-extras, --marker-file, -v/-q/-s.

Opt-out marker

  • The per-clone git config key agents-init.disabled, which cleanup always sets.
  • An optional .agents-disabled file in the project root. You commit it to opt every clone out.
  • agents-init --enable clears the git key. It refuses while the file exists.

Shared helper fix (own commit, e7683d1)

_agents_repo_sync only checked that .git existed. After an interrupted rm -rf AGENTS/, git fell through to the outer repository and committed its whole working tree, untracked secrets included. The helper now requires git rev-parse --git-dir to print .git. This also hardens agents-init and agents-vault.

Refactors

  • _agents_init_find: the shared prune walk.
  • _agents_init_stub: the stub AGENTS.md text. agents-cleanup compares against it byte for byte.

Docs

  • New "Opting a project out: agents-cleanup" section in docs/manual/16-agent-tooling.md.
  • Regenerated docs/fish-config.md.

Testing

  • New hermetic suite tests/test-agents-cleanup.fish (99 assertions). It uses real agents-init scaffolds in mktemp repos.
  • Covered cases:
    • bundle clone round-trip
    • tree-hash proof that a refusal or dry run changes nothing
    • hook-rejected final commit
    • chmod-induced move and rewrite failures
    • interrupted-removal regression
    • log-file truncation regression
    • tracked vs untracked .gitignore
  • tests/test-agents-init.fish: marker and --enable cases, plus the helper extractions.
  • fish tests/run-tests.fish: exit 0, 1036/1036, lint clean.
  • Hand-verified the undo path: cleanup, then git clone <bundle> AGENTS, then agents-init --enable. The files were relinked and the content restored.

Known follow-ups (non-blocking, no data loss)

Recorded in the AGENTS task list:

  • The docs overstate dangling-link removal outside git.
  • A global agents-init.disabled key is not cleared by --enable.
  • A covered nested repo with no commits gives a vague error.
  • A damaged AGENTS/.git is deleted without a warning.
  • Some test polish.
## Summary Adds `agents-cleanup`, which undoes `agents-init` in a project, and an opt-out marker that `agents-init` honors. Once a project is cleaned, `claude`/`agy` launches no longer scaffold it again. ### `agents-cleanup` - Every symlink into `AGENTS/` becomes the real file or directory it points to. - When two links share a target, the shallower one wins, e.g. `docs/plans` over `docs/superpowers/plans`. - Links to `.gitkeep`-only targets, dangling links, and links to `AGENTS/` itself are removed. - `AGENTS.md` handling: - An `AGENTS.md` that is exactly the agents-init stub is deleted. - Any other `AGENTS.md` loses only the "SYSTEM DIRECTIVE" blockquote. - Before anything moves: - Pending `AGENTS/` changes are committed. - The full history goes to a **verified git bundle** in `${XDG_STATE_HOME:-~/.local/state}/agents-cleanup/`. - Only then are `AGENTS/`, the `docs/superpowers/` and `docs/` directories if left empty, and the `Added by agents-init` blocks in `.gitignore` removed. - **Never commits to or touches the outer repo's index.** Every change is a working-tree change for you to commit or revert. - Refuses before changing anything when: - `AGENTS/` holds unlinked files (`--drop-extras` overrides this). - `AGENTS/` contains nested git repos (no override). - `AGENTS/` is itself a symlink. - A rebase is in progress. - A failed move restores its link, and every rewrite is checked, so a re-run resumes where it stopped. - Flags: `--dry-run`, `--drop-extras`, `--marker-file`, `-v`/`-q`/`-s`. ### Opt-out marker - The per-clone git config key `agents-init.disabled`, which cleanup always sets. - An optional `.agents-disabled` file in the project root. You commit it to opt every clone out. - `agents-init --enable` clears the git key. It refuses while the file exists. ### Shared helper fix (own commit, e7683d1) `_agents_repo_sync` only checked that `.git` existed. After an interrupted `rm -rf AGENTS/`, git fell through to the **outer** repository and committed its whole working tree, untracked secrets included. The helper now requires `git rev-parse --git-dir` to print `.git`. This also hardens `agents-init` and `agents-vault`. ### Refactors - `_agents_init_find`: the shared prune walk. - `_agents_init_stub`: the stub `AGENTS.md` text. `agents-cleanup` compares against it byte for byte. ## Docs - New "Opting a project out: agents-cleanup" section in `docs/manual/16-agent-tooling.md`. - Regenerated `docs/fish-config.md`. ## Testing - New hermetic suite `tests/test-agents-cleanup.fish` (99 assertions). It uses real `agents-init` scaffolds in mktemp repos. - Covered cases: - bundle clone round-trip - tree-hash proof that a refusal or dry run changes nothing - hook-rejected final commit - chmod-induced move and rewrite failures - interrupted-removal regression - log-file truncation regression - tracked vs untracked `.gitignore` - `tests/test-agents-init.fish`: marker and `--enable` cases, plus the helper extractions. - `fish tests/run-tests.fish`: exit 0, 1036/1036, lint clean. - Hand-verified the undo path: cleanup, then `git clone <bundle> AGENTS`, then `agents-init --enable`. The files were relinked and the content restored. ## Known follow-ups (non-blocking, no data loss) Recorded in the AGENTS task list: - The docs overstate dangling-link removal outside git. - A global `agents-init.disabled` key is not cleared by `--enable`. - A covered nested repo with no commits gives a vague error. - A damaged `AGENTS/.git` is deleted without a warning. - Some test polish.
rootiest added the Kind/BugKind/FeatureArea/FunctionsArea/DocsArea/Tests labels 2026-09-30 21:37:52 +00:00
rootiest added 11 commits 2026-09-30 21:37:52 +00:00
A half-removed AGENTS/.git passed the test -d guard, so git walked up and
committed (and bundled) the enclosing repository. Require rev-parse
--git-dir to report .git; agents-cleanup uses the same test.
- keep the verbose log intact: awk writes /dev/stderr itself instead of a
  fish-level reopen that truncates a log-file stderr
- refuse nested git repositories in AGENTS/ even with --drop-extras
- drop a link to AGENTS/ itself instead of moving the whole repository
- inventory links even when AGENTS/ is already gone (inside git only)
- never overwrite a same-second bundle; report a failed link restore
- quiet summary includes the restore command
- tests: hermetic git config, skip chmod cases as root, .gitignore order
docs(manual): agents-cleanup nested repos, link edge cases, non-git root
CI / test (pull_request) Successful in 2m36s
CI / github-mirror (pull_request) Skipped
CI / docs (pull_request) Successful in 1m18s
88b43d582f
rootiest merged commit 019afc3570 into main 2026-09-30 21:46:51 +00:00
rootiest deleted branch feat/agents-cleanup 2026-09-30 21:46:51 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rootiest/fish-config#183