From 522fd03c124828b977b575d623aa385795a039d1 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:38:26 -0400 Subject: [PATCH 01/24] feat(agents-init): add gitignore helper function --- functions/_agents_init_ensure_gitignore.fish | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 functions/_agents_init_ensure_gitignore.fish diff --git a/functions/_agents_init_ensure_gitignore.fish b/functions/_agents_init_ensure_gitignore.fish new file mode 100644 index 0000000..77235b5 --- /dev/null +++ b/functions/_agents_init_ensure_gitignore.fish @@ -0,0 +1,46 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# SYNOPSIS +# _agents_init_ensure_gitignore +# +# DESCRIPTION +# Appends to /.gitignore if the path it describes is not +# already covered by any existing ignore rule. Uses `git check-ignore` for +# accurate rule matching (catches wildcards and parent-dir globs). Falls +# back to a plain string search when the root is not a git repository. +# +# ARGUMENTS +# root Absolute path to the project root containing .gitignore +# pattern Path pattern to ensure is ignored (e.g. "AGENTS/", "CLAUDE.md") +# +# RETURNS +# 0 Pattern already ignored or successfully appended +# 1 Could not write to .gitignore +# +# EXAMPLE +# _agents_init_ensure_gitignore /home/user/myproject "AGENTS/" +function _agents_init_ensure_gitignore + set -l root $argv[1] + set -l pattern $argv[2] + set -l gitignore "$root/.gitignore" + + set -l c_ok (set_color green) + set -l c_reset (set_color normal) + + # Prefer git check-ignore (respects wildcards, parent globs, negations). + # --no-index lets it evaluate non-existent paths. + set -l already_ignored 0 + if test -d "$root/.git" + git -C "$root" check-ignore -q --no-index "$pattern" 2>/dev/null + and set already_ignored 1 + else if test -f "$gitignore" + grep -qF "$pattern" "$gitignore" + and set already_ignored 1 + end + + if test $already_ignored -eq 0 + echo "$pattern" >>"$gitignore" + echo "$c_ok→ Added $pattern to .gitignore$c_reset" + end +end From b6ed77d8f935212c6e57870d43d1475a2c480f49 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:40:27 -0400 Subject: [PATCH 02/24] fix(agents-init): add write-error check and arg validation to gitignore helper --- functions/_agents_init_ensure_gitignore.fish | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/functions/_agents_init_ensure_gitignore.fish b/functions/_agents_init_ensure_gitignore.fish index 77235b5..2fff9bf 100644 --- a/functions/_agents_init_ensure_gitignore.fish +++ b/functions/_agents_init_ensure_gitignore.fish @@ -23,11 +23,17 @@ function _agents_init_ensure_gitignore set -l root $argv[1] set -l pattern $argv[2] - set -l gitignore "$root/.gitignore" set -l c_ok (set_color green) set -l c_reset (set_color normal) + if test (count $argv) -lt 2 + echo (set_color red)"_agents_init_ensure_gitignore: requires and "(set_color normal) >&2 + return 1 + end + + set -l gitignore "$root/.gitignore" + # Prefer git check-ignore (respects wildcards, parent globs, negations). # --no-index lets it evaluate non-existent paths. set -l already_ignored 0 @@ -40,7 +46,10 @@ function _agents_init_ensure_gitignore end if test $already_ignored -eq 0 - echo "$pattern" >>"$gitignore" + if not echo "$pattern" >>"$gitignore" + echo (set_color red)"Error: could not write to $gitignore"(set_color normal) >&2 + return 1 + end echo "$c_ok→ Added $pattern to .gitignore$c_reset" end end From e6de825fb1c764b3b0584a149a3fb84284f4adcb Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:41:14 -0400 Subject: [PATCH 03/24] fix(agents-init): move argv assignments after guard in gitignore helper --- functions/_agents_init_ensure_gitignore.fish | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/functions/_agents_init_ensure_gitignore.fish b/functions/_agents_init_ensure_gitignore.fish index 2fff9bf..69a2063 100644 --- a/functions/_agents_init_ensure_gitignore.fish +++ b/functions/_agents_init_ensure_gitignore.fish @@ -21,9 +21,6 @@ # EXAMPLE # _agents_init_ensure_gitignore /home/user/myproject "AGENTS/" function _agents_init_ensure_gitignore - set -l root $argv[1] - set -l pattern $argv[2] - set -l c_ok (set_color green) set -l c_reset (set_color normal) @@ -32,6 +29,9 @@ function _agents_init_ensure_gitignore return 1 end + set -l root $argv[1] + set -l pattern $argv[2] + set -l gitignore "$root/.gitignore" # Prefer git check-ignore (respects wildcards, parent globs, negations). From 1e1c2003f3d1d7f084d19fba94786009ee2b2aea Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:42:58 -0400 Subject: [PATCH 04/24] feat(agents-init): scaffold function with argparse, help, and sub-repo init --- functions/agents-init.fish | 104 +++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 functions/agents-init.fish diff --git a/functions/agents-init.fish b/functions/agents-init.fish new file mode 100644 index 0000000..be25dd9 --- /dev/null +++ b/functions/agents-init.fish @@ -0,0 +1,104 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# SYNOPSIS +# agents-init [--agents] [--plugins] [-h | --help] +# +# DESCRIPTION +# Scaffolds an AGENTS/ sub-repository inside a project directory. Creates +# a self-contained git repo for agent specifications, moves any existing +# agent-related files into it, and replaces them with symlinks so the outer +# project never tracks agent files directly. +# +# With no flags, runs both --agents and --plugins setup. At the end of +# every invocation, commits any uncommitted changes in the AGENTS/ sub-repo +# so that agent-made edits are captured automatically. +# +# ARGUMENTS +# --agents Set up AGENTS/ repo + AGENTS.md / CLAUDE.md symlinks only +# --plugins Set up AGENTS/ repo + plugins dirs + docs/ symlinks only +# -h, --help Show this help message and exit +# +# RETURNS +# 0 Setup completed successfully +# 1 Fatal error (git init failed, move failed, etc.) +# +# EXAMPLE +# agents-init +# agents-init --agents +# agents-init --plugins +function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec files and plugin dirs' + set -l c_head (set_color --bold cyan) + set -l c_cmd (set_color --bold white) + set -l c_flag (set_color yellow) + set -l c_ok (set_color green) + set -l c_dim (set_color brblack) + set -l c_err (set_color red) + set -l c_reset (set_color normal) + + argparse 'h/help' 'agents' 'plugins' -- $argv + or return 1 + + if set -q _flag_help + echo "$c_head""Usage:$c_reset $c_cmd""agents-init$c_reset $c_flag""[--agents] [--plugins] [-h]$c_reset" + echo + echo " Scaffold an AGENTS/ sub-repository for tracking agent specifications." + echo + echo "$c_head""Options:$c_reset" + echo " $c_flag-h$c_reset, $c_flag--help$c_reset Show this help message" + echo " $c_flag--agents$c_reset Set up AGENTS.md / CLAUDE.md symlinks only" + echo " $c_flag--plugins$c_reset Set up plugins dirs and docs/ symlinks only" + echo " $c_dim(no flags)$c_reset Run both --agents and --plugins setup" + return 0 + end + + # No flags → run both modes + set -l do_agents 0 + set -l do_plugins 0 + set -q _flag_agents; and set do_agents 1 + set -q _flag_plugins; and set do_plugins 1 + if test $do_agents -eq 0 -a $do_plugins -eq 0 + set do_agents 1 + set do_plugins 1 + end + + # Resolve target root: git root if available, otherwise cwd + set -l root (git rev-parse --show-toplevel 2>/dev/null) + test -z "$root"; and set root (pwd) + + set -l agents_dir "$root/AGENTS" + set -l plugins_dir "$agents_dir/plugins" + + # ─────────────────────── Always: AGENTS/ sub-repo ─────────────────────── + set -l did_init 0 + + if not test -d "$agents_dir" + mkdir -p "$agents_dir" + echo "$c_ok→ Created AGENTS/$c_reset" + end + + if not test -d "$agents_dir/.git" + git -C "$agents_dir" init -q + or begin + echo "$c_err""Error: git init failed in AGENTS/$c_reset" >&2 + return 1 + end + echo "$c_ok→ Initialized git repo in AGENTS/$c_reset" + set did_init 1 + end + + # Ensure plugins dirs with .gitkeep + for dir in "$plugins_dir" "$plugins_dir/superpowers" "$plugins_dir/plans" "$plugins_dir/specs" + if not test -d "$dir" + mkdir -p "$dir" + echo "$c_ok→ Created "(string replace "$root/" "" "$dir")"/$c_reset" + end + test -f "$dir/.gitkeep"; or touch "$dir/.gitkeep" + end + + # ── Auto-commit (runs at end — defined here as a closure-style block) ───── + # Implemented in Task 5; placeholder comment keeps structure clear. + + # ── Mode dispatch ───────────────────────────────────────────────────────── + # --agents and --plugins blocks added in Tasks 3 and 4. +end From 7463d894f2b84ccc88ba3fafd4a6f7f10b23f534 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:46:59 -0400 Subject: [PATCH 05/24] fix(agents-init): address code quality issues in skeleton --- functions/agents-init.fish | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/functions/agents-init.fish b/functions/agents-init.fish index be25dd9..003ac55 100644 --- a/functions/agents-init.fish +++ b/functions/agents-init.fish @@ -32,6 +32,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi set -l c_cmd (set_color --bold white) set -l c_flag (set_color yellow) set -l c_ok (set_color green) + set -l c_warn (set_color yellow) set -l c_dim (set_color brblack) set -l c_err (set_color red) set -l c_reset (set_color normal) @@ -40,7 +41,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi or return 1 if set -q _flag_help - echo "$c_head""Usage:$c_reset $c_cmd""agents-init$c_reset $c_flag""[--agents] [--plugins] [-h]$c_reset" + echo "$c_head""Usage:$c_reset $c_cmd""agents-init$c_reset $c_flag""[--agents] [--plugins] [-h | --help]$c_reset" echo echo " Scaffold an AGENTS/ sub-repository for tracking agent specifications." echo @@ -57,7 +58,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi set -l do_plugins 0 set -q _flag_agents; and set do_agents 1 set -q _flag_plugins; and set do_plugins 1 - if test $do_agents -eq 0 -a $do_plugins -eq 0 + if test $do_agents -eq 0; and test $do_plugins -eq 0 set do_agents 1 set do_plugins 1 end @@ -70,10 +71,13 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi set -l plugins_dir "$agents_dir/plugins" # ─────────────────────── Always: AGENTS/ sub-repo ─────────────────────── - set -l did_init 0 + set -l did_init 0 # ponytail: set to 1 after git init — consumed by auto-commit in Task 5 if not test -d "$agents_dir" - mkdir -p "$agents_dir" + if not mkdir -p "$agents_dir" + echo "$c_err""Error: could not create AGENTS/$c_reset" >&2 + return 1 + end echo "$c_ok→ Created AGENTS/$c_reset" end @@ -90,7 +94,10 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi # Ensure plugins dirs with .gitkeep for dir in "$plugins_dir" "$plugins_dir/superpowers" "$plugins_dir/plans" "$plugins_dir/specs" if not test -d "$dir" - mkdir -p "$dir" + if not mkdir -p "$dir" + echo "$c_err""Error: could not create "(string replace "$root/" "" "$dir")"/$c_reset" >&2 + return 1 + end echo "$c_ok→ Created "(string replace "$root/" "" "$dir")"/$c_reset" end test -f "$dir/.gitkeep"; or touch "$dir/.gitkeep" From d1949953df0c406972bad6c11a7baa0374dbc33b Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:48:25 -0400 Subject: [PATCH 06/24] feat(agents-init): add --agents mode (AGENTS.md move + symlinks + gitignore) --- functions/agents-init.fish | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/functions/agents-init.fish b/functions/agents-init.fish index 003ac55..f76285d 100644 --- a/functions/agents-init.fish +++ b/functions/agents-init.fish @@ -106,6 +106,38 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi # ── Auto-commit (runs at end — defined here as a closure-style block) ───── # Implemented in Task 5; placeholder comment keeps structure clear. - # ── Mode dispatch ───────────────────────────────────────────────────────── - # --agents and --plugins blocks added in Tasks 3 and 4. + # ──────────────────────────── --agents mode ────────────────────────────── + if test $do_agents -eq 1 + # Move AGENTS.md from project root into sub-repo if it's a real file + if test -f "$root/AGENTS.md"; and not test -L "$root/AGENTS.md" + mv "$root/AGENTS.md" "$agents_dir/AGENTS.md" + echo "$c_ok→ Moved AGENTS.md → AGENTS/AGENTS.md$c_reset" + end + + # Create empty AGENTS.md in sub-repo if still missing + if not test -f "$agents_dir/AGENTS.md" + touch "$agents_dir/AGENTS.md" + echo "$c_ok→ Created AGENTS/AGENTS.md$c_reset" + end + + # Symlink AGENTS.md → AGENTS/AGENTS.md in project root + if not test -L "$root/AGENTS.md" + ln -s AGENTS/AGENTS.md "$root/AGENTS.md" + echo "$c_ok→ Linked AGENTS.md → AGENTS/AGENTS.md$c_reset" + end + + # Symlink CLAUDE.md → AGENTS/AGENTS.md in project root + if not test -L "$root/CLAUDE.md" + ln -s AGENTS/AGENTS.md "$root/CLAUDE.md" + echo "$c_ok→ Linked CLAUDE.md → AGENTS/AGENTS.md$c_reset" + end + + # Update .gitignore + for pattern in "AGENTS/" "AGENTS.md" "CLAUDE.md" + _agents_init_ensure_gitignore "$root" "$pattern" + end + end + + # ─────────────────────────── --plugins mode ────────────────────────────── + # Added in Task 4. end From 2a9a7ed2ffb7618719e6aa1f54614fbf9cf14fcf Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:51:05 -0400 Subject: [PATCH 07/24] fix(agents-init): add error checks and CLAUDE.md move to --agents mode --- functions/agents-init.fish | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/functions/agents-init.fish b/functions/agents-init.fish index f76285d..75dea5b 100644 --- a/functions/agents-init.fish +++ b/functions/agents-init.fish @@ -110,7 +110,10 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi if test $do_agents -eq 1 # Move AGENTS.md from project root into sub-repo if it's a real file if test -f "$root/AGENTS.md"; and not test -L "$root/AGENTS.md" - mv "$root/AGENTS.md" "$agents_dir/AGENTS.md" + if not mv "$root/AGENTS.md" "$agents_dir/AGENTS.md" + echo "$c_err""Error: could not move AGENTS.md → AGENTS/AGENTS.md$c_reset" >&2 + return 1 + end echo "$c_ok→ Moved AGENTS.md → AGENTS/AGENTS.md$c_reset" end @@ -122,13 +125,28 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi # Symlink AGENTS.md → AGENTS/AGENTS.md in project root if not test -L "$root/AGENTS.md" - ln -s AGENTS/AGENTS.md "$root/AGENTS.md" + if not ln -s AGENTS/AGENTS.md "$root/AGENTS.md" + echo "$c_err""Error: could not create AGENTS.md symlink$c_reset" >&2 + return 1 + end echo "$c_ok→ Linked AGENTS.md → AGENTS/AGENTS.md$c_reset" end + # Move real CLAUDE.md into sub-repo if it exists as a regular file + if test -f "$root/CLAUDE.md"; and not test -L "$root/CLAUDE.md" + if not mv "$root/CLAUDE.md" "$agents_dir/CLAUDE.md" + echo "$c_err""Error: could not move CLAUDE.md → AGENTS/CLAUDE.md$c_reset" >&2 + return 1 + end + echo "$c_ok→ Moved CLAUDE.md → AGENTS/CLAUDE.md$c_reset" + end + # Symlink CLAUDE.md → AGENTS/AGENTS.md in project root if not test -L "$root/CLAUDE.md" - ln -s AGENTS/AGENTS.md "$root/CLAUDE.md" + if not ln -s AGENTS/AGENTS.md "$root/CLAUDE.md" + echo "$c_err""Error: could not create CLAUDE.md symlink$c_reset" >&2 + return 1 + end echo "$c_ok→ Linked CLAUDE.md → AGENTS/AGENTS.md$c_reset" end From 3befc07887e01142db3b49995190e2eee0b8dfed Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:53:32 -0400 Subject: [PATCH 08/24] feat(agents-init): add --plugins mode (docs/ move + symlinks + gitignore) --- functions/agents-init.fish | 40 +++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/functions/agents-init.fish b/functions/agents-init.fish index 75dea5b..44e7f93 100644 --- a/functions/agents-init.fish +++ b/functions/agents-init.fish @@ -157,5 +157,43 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi end # ─────────────────────────── --plugins mode ────────────────────────────── - # Added in Task 4. + if test $do_plugins -eq 1 + set -l docs_dir "$root/docs" + + if not test -d "$docs_dir" + if not mkdir -p "$docs_dir" + echo "$c_err""Error: could not create docs/$c_reset" >&2 + return 1 + end + echo "$c_ok→ Created docs/$c_reset" + end + + for plug in superpowers plans specs + set -l docs_target "$docs_dir/$plug" + set -l agents_target "$plugins_dir/$plug" + + # If a real directory exists in docs/, move its contents to AGENTS/plugins/ + if test -d "$docs_target"; and not test -L "$docs_target" + if test -n "$(ls -A $docs_target 2>/dev/null)" + if not cp -r "$docs_target/." "$agents_target/" + echo "$c_err""Error: could not move docs/$plug → AGENTS/plugins/$plug$c_reset" >&2 + return 1 + end + end + rm -rf "$docs_target" + echo "$c_ok→ Moved docs/$plug → AGENTS/plugins/$plug$c_reset" + end + + # Create symlink docs/ → ../AGENTS/plugins/ + if not test -L "$docs_target" + if not ln -s "../AGENTS/plugins/$plug" "$docs_target" + echo "$c_err""Error: could not create docs/$plug symlink$c_reset" >&2 + return 1 + end + echo "$c_ok→ Linked docs/$plug → AGENTS/plugins/$plug$c_reset" + end + + _agents_init_ensure_gitignore "$root" "docs/$plug" + end + end end From a483c30c055f9786be4afc11c9efceac832a0979 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:55:05 -0400 Subject: [PATCH 09/24] fix(agents-init): use fish-idiomatic command substitution in --plugins mode --- functions/agents-init.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/agents-init.fish b/functions/agents-init.fish index 44e7f93..b97336f 100644 --- a/functions/agents-init.fish +++ b/functions/agents-init.fish @@ -174,7 +174,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi # If a real directory exists in docs/, move its contents to AGENTS/plugins/ if test -d "$docs_target"; and not test -L "$docs_target" - if test -n "$(ls -A $docs_target 2>/dev/null)" + if test -n (ls -A $docs_target 2>/dev/null) if not cp -r "$docs_target/." "$agents_target/" echo "$c_err""Error: could not move docs/$plug → AGENTS/plugins/$plug$c_reset" >&2 return 1 From 8d0f425b109a61b3e78e523ae821da825f06c93f Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 21:59:02 -0400 Subject: [PATCH 10/24] feat(agents-init): add auto-commit step for AGENTS/ sub-repo --- functions/agents-init.fish | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/functions/agents-init.fish b/functions/agents-init.fish index b97336f..a9b9735 100644 --- a/functions/agents-init.fish +++ b/functions/agents-init.fish @@ -103,9 +103,6 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi test -f "$dir/.gitkeep"; or touch "$dir/.gitkeep" end - # ── Auto-commit (runs at end — defined here as a closure-style block) ───── - # Implemented in Task 5; placeholder comment keeps structure clear. - # ──────────────────────────── --agents mode ────────────────────────────── if test $do_agents -eq 1 # Move AGENTS.md from project root into sub-repo if it's a real file @@ -196,4 +193,16 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi _agents_init_ensure_gitignore "$root" "docs/$plug" end end + + # ──────────────────────── Auto-commit AGENTS/ ──────────────────────────── + git -C "$agents_dir" add -A 2>/dev/null + set -l status_out (git -C "$agents_dir" status --porcelain 2>/dev/null) + if test -n "$status_out" + set -l msg "chore: sync AGENTS repository" + test $did_init -eq 1; and set msg "chore: initialize AGENTS repository" + if git -C "$agents_dir" -c commit.gpgsign=false commit -q -m "$msg" 2>/dev/null + set -l sha (git -C "$agents_dir" rev-parse --short HEAD 2>/dev/null) + echo "$c_ok→ Committed AGENTS/ ($sha) $c_dim$msg$c_reset" + end + end end From 016737082346fd78081ed9dc57e509297a99e035 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 22:01:50 -0400 Subject: [PATCH 11/24] refactor(claude): delegate symlink logic to agents-init --agents --- functions/claude.fish | 38 +++++--------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/functions/claude.fish b/functions/claude.fish index cb05f41..6fdf110 100644 --- a/functions/claude.fish +++ b/functions/claude.fish @@ -5,12 +5,10 @@ # claude [ARGS...] # # DESCRIPTION -# Wrapper for the claude CLI that ensures CLAUDE.md exists before launch. -# Both the current directory and the git project root are checked. When -# CLAUDE.md is absent but AGENTS.md is present in a checked directory, a -# relative symlink CLAUDE.md -> AGENTS.md is created automatically so that -# Claude Code picks up shared agent instructions without duplicating the -# file. All arguments are forwarded verbatim to the real claude binary. +# Wrapper for the claude CLI that ensures the AGENTS/ sub-repository is +# initialized and any agent-made changes are committed before launch. +# Delegates all scaffold and commit logic to agents-init --agents. +# All arguments are forwarded verbatim to the real claude binary. # # Opinionated component (C1): when disabled via __fish_config_op_aliases # (or the __fish_config_opinionated master), the command is passed through @@ -32,33 +30,7 @@ function claude --wraps=claude --description 'claude wrapper: auto-links AGENTS. return $status end - set -l c_ok (set_color green) - set -l c_reset (set_color normal) - - # Build the list of directories to inspect: cwd always, git root when different. - set -l check_dirs (pwd) - set -l git_root (git rev-parse --show-toplevel 2>/dev/null) - if test -n "$git_root" -a "$git_root" != (pwd) - set check_dirs $check_dirs $git_root - end - - # Anchor for relative display: git root when available, otherwise cwd. - set -l anchor $git_root - test -z "$anchor" && set anchor (pwd) - - for dir in $check_dirs - if not test -e "$dir/CLAUDE.md" - if test -f "$dir/AGENTS.md" - ln -s AGENTS.md "$dir/CLAUDE.md" - set -l prefix "" - if test "$dir" != "$anchor" - set prefix (string replace "$anchor/" "" "$dir")/ - end - set -l msg (string join "" "→ Linked " $prefix "CLAUDE.md → " $prefix "AGENTS.md") - echo $c_ok$msg$c_reset >&2 - end - end - end + agents-init --agents command claude $argv end From 11dc5841047d325ec94949b2e2b609b5e96b63c9 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 22:04:12 -0400 Subject: [PATCH 12/24] docs: add agents-init entry and update claude description in fish-config.md --- docs/fish-config.md | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/docs/fish-config.md b/docs/fish-config.md index 00a06ee..c6777f2 100644 --- a/docs/fish-config.md +++ b/docs/fish-config.md @@ -43,15 +43,18 @@ The configuration is split across: config.fish Main entry point; sets env vars and PATH conf.d/ abbr.fish All abbreviations - cheat.fish cheat.sh completions + autopair.fish Auto-pair brackets and quotes (bundled from jorgebucaran/autopair.fish) + cheat.fish cheat.sh tab completions done.fish Desktop notifications for long commands first_run.fish One-time init: Fisher bootstrap, theme, welcome key_bindings.fish Custom key bindings and Vi mode + logging-events.fish C5 --on-variable event handlers; syncs logging state at startup paru-wrapper.fish Auto-generates ~/.local/bin/paru logging wrapper + puffer.fish !! / !$ / ./ expansion (bundled from nickeb96/puffer-fish) + sponge_privacy.fish Sponge privacy patterns; filters credentials from history starship.fish fish_prompt with OSC 133 shell-integration markers tailscale.fish Tailscale CLI tab completions theme.fish Catppuccin syntax highlight colors - sponge_privacy.fish Sponge privacy patterns; filters credentials from history tricks.fish PATH, bang-bang helpers, bat man pages, aliases wakatime.fish WakaTime shell hook yay-wrapper.fish Auto-generates ~/.local/bin/yay logging wrapper @@ -1105,15 +1108,33 @@ Add -i (interactive confirmation) to destructive commands: file in the current directory, or opens an interactive fzf picker if no session file is found. +### agents-init + + Synopsis: agents-init [--agents | --plugins] + Scaffold an AGENTS/ sub-repository for tracking agent specs and plugin + directories. Creates AGENTS/ as a standalone git repo, initializes + standard plugin subdirectories (superpowers/, plans/, specs/), moves any + existing AGENTS.md and docs/plugin dirs into the sub-repo, and replaces + them with relative symlinks. Also adds CLAUDE.md -> AGENTS/AGENTS.md so + Claude Code picks up the shared agent instructions. Adds all managed + paths to .gitignore and auto-commits every change inside the AGENTS/ + sub-repo. Fully idempotent: a second run produces no output and no new + commits. Flags: --agents re-runs only the AGENTS.md / symlink step; + --plugins re-runs only the plugin-directory wiring step. Called + automatically by the claude wrapper on every invocation. + + agents-init + agents-init --agents + agents-init --plugins + ### claude Synopsis: claude [args...] - Wrapper for the claude CLI. Before launching, checks the current - directory and the git project root for CLAUDE.md; when it is absent but - AGENTS.md is present, creates a relative symlink CLAUDE.md -> AGENTS.md - so Claude Code picks up shared agent instructions without duplicating - the file. All arguments are forwarded verbatim. Command shadow (C1): - when __fish_config_op_aliases (or the master) is disabled, the call is + Wrapper for the claude CLI. Before launching, delegates to agents-init + --agents to ensure AGENTS/ is scaffolded and CLAUDE.md is symlinked to + AGENTS/AGENTS.md in the current project, then forwards all arguments + verbatim to the real claude binary. Command shadow (C1): when + __fish_config_op_aliases (or the master) is disabled, the call is passed through to the real claude binary unchanged. claude From 45cba3a15b25eee50a7dcff75bc9fcffd0f91b75 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 22:09:44 -0400 Subject: [PATCH 13/24] fix(agents-init): address final review issues (CLAUDE.md safety, rm-rf guard, gitignore anchoring, worktree detection) --- functions/_agents_init_ensure_gitignore.fish | 2 +- functions/agents-init.fish | 28 +++++++++----------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/functions/_agents_init_ensure_gitignore.fish b/functions/_agents_init_ensure_gitignore.fish index 69a2063..f19d6ec 100644 --- a/functions/_agents_init_ensure_gitignore.fish +++ b/functions/_agents_init_ensure_gitignore.fish @@ -37,7 +37,7 @@ function _agents_init_ensure_gitignore # Prefer git check-ignore (respects wildcards, parent globs, negations). # --no-index lets it evaluate non-existent paths. set -l already_ignored 0 - if test -d "$root/.git" + if git -C "$root" rev-parse --git-dir >/dev/null 2>&1 git -C "$root" check-ignore -q --no-index "$pattern" 2>/dev/null and set already_ignored 1 else if test -f "$gitignore" diff --git a/functions/agents-init.fish b/functions/agents-init.fish index a9b9735..956d57c 100644 --- a/functions/agents-init.fish +++ b/functions/agents-init.fish @@ -71,7 +71,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi set -l plugins_dir "$agents_dir/plugins" # ─────────────────────── Always: AGENTS/ sub-repo ─────────────────────── - set -l did_init 0 # ponytail: set to 1 after git init — consumed by auto-commit in Task 5 + set -l did_init 0 # set to 1 when git init runs this invocation; selects commit message if not test -d "$agents_dir" if not mkdir -p "$agents_dir" @@ -129,17 +129,11 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi echo "$c_ok→ Linked AGENTS.md → AGENTS/AGENTS.md$c_reset" end - # Move real CLAUDE.md into sub-repo if it exists as a regular file - if test -f "$root/CLAUDE.md"; and not test -L "$root/CLAUDE.md" - if not mv "$root/CLAUDE.md" "$agents_dir/CLAUDE.md" - echo "$c_err""Error: could not move CLAUDE.md → AGENTS/CLAUDE.md$c_reset" >&2 - return 1 - end - echo "$c_ok→ Moved CLAUDE.md → AGENTS/CLAUDE.md$c_reset" - end - # Symlink CLAUDE.md → AGENTS/AGENTS.md in project root - if not test -L "$root/CLAUDE.md" + # If a real CLAUDE.md already exists, warn and skip — don't clobber or orphan content. + if test -f "$root/CLAUDE.md"; and not test -L "$root/CLAUDE.md" + echo "$c_warn""Warning: CLAUDE.md exists as a real file — skipping symlink. Remove it manually to let agents-init manage it.$c_reset" >&2 + else if not test -L "$root/CLAUDE.md" if not ln -s AGENTS/AGENTS.md "$root/CLAUDE.md" echo "$c_err""Error: could not create CLAUDE.md symlink$c_reset" >&2 return 1 @@ -148,7 +142,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi end # Update .gitignore - for pattern in "AGENTS/" "AGENTS.md" "CLAUDE.md" + for pattern in "AGENTS/" "/AGENTS.md" "/CLAUDE.md" _agents_init_ensure_gitignore "$root" "$pattern" end end @@ -171,13 +165,17 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi # If a real directory exists in docs/, move its contents to AGENTS/plugins/ if test -d "$docs_target"; and not test -L "$docs_target" - if test -n (ls -A $docs_target 2>/dev/null) + set -l contents (ls -A "$docs_target" 2>/dev/null) + if test (count $contents) -gt 0 if not cp -r "$docs_target/." "$agents_target/" - echo "$c_err""Error: could not move docs/$plug → AGENTS/plugins/$plug$c_reset" >&2 + echo "$c_err""Error: could not copy docs/$plug → AGENTS/plugins/$plug$c_reset" >&2 return 1 end end - rm -rf "$docs_target" + if not rm -rf "$docs_target" + echo "$c_err""Error: could not remove docs/$plug after copy$c_reset" >&2 + return 1 + end echo "$c_ok→ Moved docs/$plug → AGENTS/plugins/$plug$c_reset" end From 178214c812e9340bfc7ff0f795ec8c2d243e7e08 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 22:13:31 -0400 Subject: [PATCH 14/24] docs: add SYNOPSIS/DESCRIPTION doc blocks to session hook scripts and index entries --- docs/fish-config.index | 4 ++++ functions/save_antigravity_session.fish | 22 ++++++++++++++++++++++ functions/save_claude_session.fish | 22 ++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/docs/fish-config.index b/docs/fish-config.index index 8989ab6..de17cd9 100644 --- a/docs/fish-config.index +++ b/docs/fish-config.index @@ -11,6 +11,10 @@ synopsis=# SYNOPSIS description=# DESCRIPTION toc=# TABLE OF CONTENTS contents=# TABLE OF CONTENTS +autopair=# DESCRIPTION +puffer=# DESCRIPTION +puffer-fish=# DESCRIPTION +logging-events=# DESCRIPTION # ── Section 1: Configuration Variables ─────────────────────── variables=# 1. CONFIGURATION VARIABLES diff --git a/functions/save_antigravity_session.fish b/functions/save_antigravity_session.fish index f3e91bb..88ca3be 100755 --- a/functions/save_antigravity_session.fish +++ b/functions/save_antigravity_session.fish @@ -3,6 +3,28 @@ # Copyright (C) 2026 Rootiest # SPDX-License-Identifier: AGPL-3.0-or-later +# SYNOPSIS +# Invoked as an Antigravity session hook; reads JSON from stdin. +# +# DESCRIPTION +# Hook script called by the Antigravity CLI (agy) on session start. +# Reads a JSON payload from stdin, extracts the session_id field, and +# writes it to .antigravity_session in the current directory. Ensures +# that file is excluded via .gitignore. Sets the universal variable +# LAST_ANTIGRAVITY_SESSION for cross-terminal access. Falls back to a +# no-op (emitting "{}") when python3 is unavailable (Convention §6). +# +# ARGUMENTS +# stdin JSON payload from the Antigravity CLI containing a "session_id" key +# +# RETURNS +# 0 Always; emits "{}" to stdout as required by the hook contract +# +# EXAMPLE +# echo '{"session_id":"abc123"}' | fish save_antigravity_session.fish +# cat .antigravity_session # → abc123 +# echo $LAST_ANTIGRAVITY_SESSION # → abc123 + # 1. Read the JSON from stdin set -l input (cat) diff --git a/functions/save_claude_session.fish b/functions/save_claude_session.fish index bdbb520..ed2e04f 100755 --- a/functions/save_claude_session.fish +++ b/functions/save_claude_session.fish @@ -3,6 +3,28 @@ # Copyright (C) 2026 Rootiest # SPDX-License-Identifier: AGPL-3.0-or-later +# SYNOPSIS +# Invoked as a Claude Code session hook; reads JSON from stdin. +# +# DESCRIPTION +# Hook script called by Claude Code on session start. Reads a JSON payload +# from stdin, extracts the session_id field, and writes it to .claude_session +# in the current directory. Ensures that file is excluded via .gitignore. +# Sets the universal variable LAST_CLAUDE_SESSION for cross-terminal access. +# Falls back to a no-op (emitting "{}") when python3 is unavailable +# (Convention §6). +# +# ARGUMENTS +# stdin JSON payload from Claude Code containing a "session_id" key +# +# RETURNS +# 0 Always; emits "{}" to stdout as required by the hook contract +# +# EXAMPLE +# echo '{"session_id":"abc123"}' | fish save_claude_session.fish +# cat .claude_session # → abc123 +# echo $LAST_CLAUDE_SESSION # → abc123 + # 1. Read input and extract session ID # python3 parses the session_id out of the hook's JSON payload. If it is # unavailable we emit valid empty JSON and skip session tracking rather From e96f8744690aa446f6954d4db4196b692691f228 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 22:25:47 -0400 Subject: [PATCH 15/24] feat(agy): wrap agy with agents-init --agents, same as claude wrapper --- docs/fish-config.md | 20 +++++++++++++++++--- functions/agy.fish | 36 ++++++++++++++++++++++++++++++++++++ functions/antigravity.fish | 2 +- 3 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 functions/agy.fish diff --git a/docs/fish-config.md b/docs/fish-config.md index c6777f2..3650e4c 100644 --- a/docs/fish-config.md +++ b/docs/fish-config.md @@ -1088,11 +1088,25 @@ Add -i (interactive confirmation) to destructive commands: ## 5.12 AI and Developer Tools +### agy + + Synopsis: agy [args...] + Wrapper for the agy Antigravity AI CLI. Before launching, delegates to + agents-init --agents to ensure AGENTS/ is scaffolded and CLAUDE.md is + symlinked to AGENTS/AGENTS.md in the current project, then forwards all + arguments verbatim to the real agy binary. Command shadow (C1): when + __fish_config_op_aliases (or the master) is disabled, the call is + passed through to the real agy binary unchanged. + + agy chat + agy resume + ### antigravity Synopsis: antigravity [args...] - Runs the agy CLI (Antigravity AI assistant) with noisy deprecation - warnings filtered from stderr. + Alias for agy with noisy deprecation warnings filtered from stderr. + Delegates to the agy fish function, so agents-init --agents runs on + every invocation. antigravity chat @@ -1121,7 +1135,7 @@ Add -i (interactive confirmation) to destructive commands: sub-repo. Fully idempotent: a second run produces no output and no new commits. Flags: --agents re-runs only the AGENTS.md / symlink step; --plugins re-runs only the plugin-directory wiring step. Called - automatically by the claude wrapper on every invocation. + automatically by the claude and agy wrappers on every invocation. agents-init agents-init --agents diff --git a/functions/agy.fish b/functions/agy.fish new file mode 100644 index 0000000..d078b0e --- /dev/null +++ b/functions/agy.fish @@ -0,0 +1,36 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# SYNOPSIS +# agy [ARGS...] +# +# DESCRIPTION +# Wrapper for the agy Antigravity AI CLI that ensures the AGENTS/ +# sub-repository is initialized and any agent-made changes are committed +# before launch. Delegates all scaffold and commit logic to agents-init +# --agents. All arguments are forwarded verbatim to the real agy binary. +# +# Opinionated component (C1): when disabled via __fish_config_op_aliases +# (or the __fish_config_opinionated master), the command is passed through +# to the real agy binary unchanged. +# +# ARGUMENTS +# ARGS Any arguments forwarded verbatim to the underlying agy binary +# +# RETURNS +# Exit status of the underlying agy binary +# +# EXAMPLE +# agy +# agy chat +# agy resume +function agy --wraps=agy --description 'agy wrapper: auto-initializes AGENTS/ sub-repo before launch' + if not __fish_config_op_enabled __fish_config_op_aliases + command agy $argv + return $status + end + + agents-init --agents + + command agy $argv +end diff --git a/functions/antigravity.fish b/functions/antigravity.fish index 251ab88..42ca85b 100644 --- a/functions/antigravity.fish +++ b/functions/antigravity.fish @@ -15,5 +15,5 @@ # antigravity chat function antigravity --wraps='agy' --description 'alias antigravity=agy' # In fish, we pipe stderr using '2>|' to another command - command agy $argv 2>| grep -v "'app' is not in the list of known options" >&2 + agy $argv 2>| grep -v "'app' is not in the list of known options" >&2 end From d68bedef95187219e82680d3eeaafd0f6a5405c1 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 22:26:56 -0400 Subject: [PATCH 16/24] chore: remove antigravity wrapper (filtered error no longer exists, use agy directly) --- functions/antigravity.fish | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 functions/antigravity.fish diff --git a/functions/antigravity.fish b/functions/antigravity.fish deleted file mode 100644 index 42ca85b..0000000 --- a/functions/antigravity.fish +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (C) 2026 Rootiest -# SPDX-License-Identifier: AGPL-3.0-or-later - -# SYNOPSIS -# antigravity [args...] -# -# DESCRIPTION -# Wrapper for the agy Antigravity AI CLI that filters a known noisy warning -# about an unrecognized 'app' option from stderr. -# -# ARGUMENTS -# args... Arguments passed through to the agy command -# -# EXAMPLE -# antigravity chat -function antigravity --wraps='agy' --description 'alias antigravity=agy' - # In fish, we pipe stderr using '2>|' to another command - agy $argv 2>| grep -v "'app' is not in the list of known options" >&2 -end From 015daec928e06002553d09d489693dcb70645e33 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 22:27:34 -0400 Subject: [PATCH 17/24] chore: update ag/ag. abbreviations and docs to point to agy instead of antigravity --- conf.d/abbr.fish | 4 ++-- docs/fish-config.md | 13 ++----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/conf.d/abbr.fish b/conf.d/abbr.fish index be6c762..efc43cf 100644 --- a/conf.d/abbr.fish +++ b/conf.d/abbr.fish @@ -72,8 +72,8 @@ abbr -a g git abbr -a gitig gi abbr -a git-ignore gi # Antigravity -abbr -a ag antigravity -abbr -a ag. antigravity . +abbr -a ag agy +abbr -a ag. agy . # Quit abbr -a /exit exit # Window-management abbreviations are opinionated (C4 integrations) diff --git a/docs/fish-config.md b/docs/fish-config.md index 3650e4c..c936b00 100644 --- a/docs/fish-config.md +++ b/docs/fish-config.md @@ -416,8 +416,8 @@ Appending n to any :cd* abbreviation also runs nvim after changing dir. ## 4.8 AI Assistants - ag antigravity - ag. antigravity . + ag agy + ag. agy . v antigravity-ide s wezterm ssh (WezTerm only) @@ -1101,15 +1101,6 @@ Add -i (interactive confirmation) to destructive commands: agy chat agy resume -### antigravity - - Synopsis: antigravity [args...] - Alias for agy with noisy deprecation warnings filtered from stderr. - Delegates to the agy fish function, so agents-init --agents runs on - every invocation. - - antigravity chat - ### antigravity-ide Synopsis: antigravity-ide [args...] From 3a054021cf57f233d81b5df06b9280a87bcc1797 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 23:05:40 -0400 Subject: [PATCH 18/24] fix(agents-init): migrate plugin dirs, smarter CLAUDE.md handling, wrappers run full init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move plugin dir creation into --plugins mode (not 'Always') so --agents alone no longer creates empty AGENTS/plugins/ dirs - Wrappers (claude, agy) now call plain agents-init (both modes) so plugin dirs in docs/ are migrated on the first AI launch, not just --agents - Rewrite --agents CLAUDE.md logic: detect which root files are real vs symlinks and handle all four cases (both/agents-only/claude-only/neither) without ever losing content - AGENTS/CLAUDE.md is now its own file in AGENTS/ (real file when both existed, symlink → AGENTS.md for single-source cases) - Root CLAUDE.md now points to AGENTS/CLAUDE.md instead of AGENTS/AGENTS.md; readlink checks auto-fix existing symlinks with the wrong target - New empty setups get AGENTS/AGENTS.md pre-populated with the agent directive warning editors not to write through the root symlinks --- functions/agents-init.fish | 146 ++++++++++++++++++++++++++++--------- functions/agy.fish | 4 +- functions/claude.fish | 4 +- 3 files changed, 116 insertions(+), 38 deletions(-) diff --git a/functions/agents-init.fish b/functions/agents-init.fish index 956d57c..add22cf 100644 --- a/functions/agents-init.fish +++ b/functions/agents-init.fish @@ -10,6 +10,14 @@ # agent-related files into it, and replaces them with symlinks so the outer # project never tracks agent files directly. # +# File layout after setup: +# AGENTS/AGENTS.md canonical agent spec (real file) +# AGENTS/CLAUDE.md real file (if CLAUDE.md existed separately) +# or symlink → AGENTS.md (single-source case) +# /AGENTS.md → AGENTS/AGENTS.md +# /CLAUDE.md → AGENTS/CLAUDE.md +# docs/ → ../AGENTS/plugins/ +# # With no flags, runs both --agents and --plugins setup. At the end of # every invocation, commits any uncommitted changes in the AGENTS/ sub-repo # so that agent-made edits are captured automatically. @@ -71,7 +79,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi set -l plugins_dir "$agents_dir/plugins" # ─────────────────────── Always: AGENTS/ sub-repo ─────────────────────── - set -l did_init 0 # set to 1 when git init runs this invocation; selects commit message + set -l did_init 0 if not test -d "$agents_dir" if not mkdir -p "$agents_dir" @@ -91,37 +99,91 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi set did_init 1 end - # Ensure plugins dirs with .gitkeep - for dir in "$plugins_dir" "$plugins_dir/superpowers" "$plugins_dir/plans" "$plugins_dir/specs" - if not test -d "$dir" - if not mkdir -p "$dir" - echo "$c_err""Error: could not create "(string replace "$root/" "" "$dir")"/$c_reset" >&2 - return 1 - end - echo "$c_ok→ Created "(string replace "$root/" "" "$dir")"/$c_reset" - end - test -f "$dir/.gitkeep"; or touch "$dir/.gitkeep" - end - # ──────────────────────────── --agents mode ────────────────────────────── if test $do_agents -eq 1 - # Move AGENTS.md from project root into sub-repo if it's a real file + # Detect which root-level files are real (not symlinks) + set -l has_agents 0 + set -l has_claude 0 if test -f "$root/AGENTS.md"; and not test -L "$root/AGENTS.md" - if not mv "$root/AGENTS.md" "$agents_dir/AGENTS.md" - echo "$c_err""Error: could not move AGENTS.md → AGENTS/AGENTS.md$c_reset" >&2 + set has_agents 1 + end + if test -f "$root/CLAUDE.md"; and not test -L "$root/CLAUDE.md" + set has_claude 1 + end + + # ── Move real files into AGENTS/ ────────────────────────────────────── + if test $has_agents -eq 1; and test $has_claude -eq 1 + # Both exist: preserve each as its own file in AGENTS/ + if not test -f "$agents_dir/AGENTS.md" + if not mv "$root/AGENTS.md" "$agents_dir/AGENTS.md" + echo "$c_err""Error: could not move AGENTS.md → AGENTS/AGENTS.md$c_reset" >&2 + return 1 + end + echo "$c_ok→ Moved AGENTS.md → AGENTS/AGENTS.md$c_reset" + end + if not test -f "$agents_dir/CLAUDE.md"; and not test -L "$agents_dir/CLAUDE.md" + if not mv "$root/CLAUDE.md" "$agents_dir/CLAUDE.md" + echo "$c_err""Error: could not move CLAUDE.md → AGENTS/CLAUDE.md$c_reset" >&2 + return 1 + end + echo "$c_ok→ Moved CLAUDE.md → AGENTS/CLAUDE.md$c_reset" + end + else if test $has_agents -eq 1 + if not test -f "$agents_dir/AGENTS.md" + if not mv "$root/AGENTS.md" "$agents_dir/AGENTS.md" + echo "$c_err""Error: could not move AGENTS.md → AGENTS/AGENTS.md$c_reset" >&2 + return 1 + end + echo "$c_ok→ Moved AGENTS.md → AGENTS/AGENTS.md$c_reset" + end + else if test $has_claude -eq 1 + # Only CLAUDE.md: treat it as the agent spec + if not test -f "$agents_dir/AGENTS.md" + if not mv "$root/CLAUDE.md" "$agents_dir/AGENTS.md" + echo "$c_err""Error: could not move CLAUDE.md → AGENTS/AGENTS.md$c_reset" >&2 + return 1 + end + echo "$c_ok→ Moved CLAUDE.md → AGENTS/AGENTS.md$c_reset" + end + else + # Neither exists: create AGENTS/AGENTS.md with the agent directive + if not test -f "$agents_dir/AGENTS.md" + printf '%s\n' \ + '# AGENTS.md' \ + '' \ + '> ⚠️ **SYSTEM DIRECTIVE FOR AI AGENTS: FILE EDITING**' \ + '> You may be reading this file via a symlink (`CLAUDE.md` or `AGENTS.md`) in' \ + '> the root of the project. Your environment'\''s file-editing tools cannot write' \ + '> through symlinks and will throw an error.' \ + '>' \ + '> **DO NOT** attempt to write to or edit `CLAUDE.md` or `AGENTS.md` in the' \ + '> project root. If you need to update these instructions, you **MUST write' \ + '> directly to `AGENTS/AGENTS.md`**.' \ + > "$agents_dir/AGENTS.md" + echo "$c_ok→ Created AGENTS/AGENTS.md with agent directive$c_reset" + end + end + + # ── Ensure AGENTS/CLAUDE.md exists ──────────────────────────────────── + # When both files existed, AGENTS/CLAUDE.md is already a real file. + # Otherwise, create it as a symlink → AGENTS.md (within AGENTS/). + if not test -f "$agents_dir/CLAUDE.md"; and not test -L "$agents_dir/CLAUDE.md" + if not ln -s AGENTS.md "$agents_dir/CLAUDE.md" + echo "$c_err""Error: could not create AGENTS/CLAUDE.md symlink$c_reset" >&2 return 1 end - echo "$c_ok→ Moved AGENTS.md → AGENTS/AGENTS.md$c_reset" + echo "$c_ok→ Linked AGENTS/CLAUDE.md → AGENTS/AGENTS.md$c_reset" end - # Create empty AGENTS.md in sub-repo if still missing - if not test -f "$agents_dir/AGENTS.md" - touch "$agents_dir/AGENTS.md" - echo "$c_ok→ Created AGENTS/AGENTS.md$c_reset" - end - - # Symlink AGENTS.md → AGENTS/AGENTS.md in project root + # ── Root symlink: AGENTS.md → AGENTS/AGENTS.md ─────────────────────── + set -l _need_link 0 if not test -L "$root/AGENTS.md" + set _need_link 1 + else if test (readlink "$root/AGENTS.md") != AGENTS/AGENTS.md + rm -f "$root/AGENTS.md" + set _need_link 1 + end + if test $_need_link -eq 1 if not ln -s AGENTS/AGENTS.md "$root/AGENTS.md" echo "$c_err""Error: could not create AGENTS.md symlink$c_reset" >&2 return 1 @@ -129,19 +191,23 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi echo "$c_ok→ Linked AGENTS.md → AGENTS/AGENTS.md$c_reset" end - # Symlink CLAUDE.md → AGENTS/AGENTS.md in project root - # If a real CLAUDE.md already exists, warn and skip — don't clobber or orphan content. - if test -f "$root/CLAUDE.md"; and not test -L "$root/CLAUDE.md" - echo "$c_warn""Warning: CLAUDE.md exists as a real file — skipping symlink. Remove it manually to let agents-init manage it.$c_reset" >&2 - else if not test -L "$root/CLAUDE.md" - if not ln -s AGENTS/AGENTS.md "$root/CLAUDE.md" + # ── Root symlink: CLAUDE.md → AGENTS/CLAUDE.md ─────────────────────── + set -l _need_link 0 + if not test -L "$root/CLAUDE.md" + set _need_link 1 + else if test (readlink "$root/CLAUDE.md") != AGENTS/CLAUDE.md + rm -f "$root/CLAUDE.md" + set _need_link 1 + end + if test $_need_link -eq 1 + if not ln -s AGENTS/CLAUDE.md "$root/CLAUDE.md" echo "$c_err""Error: could not create CLAUDE.md symlink$c_reset" >&2 return 1 end - echo "$c_ok→ Linked CLAUDE.md → AGENTS/AGENTS.md$c_reset" + echo "$c_ok→ Linked CLAUDE.md → AGENTS/CLAUDE.md$c_reset" end - # Update .gitignore + # ── .gitignore ──────────────────────────────────────────────────────── for pattern in "AGENTS/" "/AGENTS.md" "/CLAUDE.md" _agents_init_ensure_gitignore "$root" "$pattern" end @@ -149,6 +215,18 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi # ─────────────────────────── --plugins mode ────────────────────────────── if test $do_plugins -eq 1 + # Ensure AGENTS/plugins/ dirs exist with .gitkeep + for dir in "$plugins_dir" "$plugins_dir/superpowers" "$plugins_dir/plans" "$plugins_dir/specs" + if not test -d "$dir" + if not mkdir -p "$dir" + echo "$c_err""Error: could not create "(string replace "$root/" "" "$dir")"/$c_reset" >&2 + return 1 + end + echo "$c_ok→ Created "(string replace "$root/" "" "$dir")"/$c_reset" + end + test -f "$dir/.gitkeep"; or touch "$dir/.gitkeep" + end + set -l docs_dir "$root/docs" if not test -d "$docs_dir" @@ -160,10 +238,10 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi end for plug in superpowers plans specs - set -l docs_target "$docs_dir/$plug" + set -l docs_target "$docs_dir/$plug" set -l agents_target "$plugins_dir/$plug" - # If a real directory exists in docs/, move its contents to AGENTS/plugins/ + # If a real directory exists in docs/, migrate its contents to AGENTS/plugins/ if test -d "$docs_target"; and not test -L "$docs_target" set -l contents (ls -A "$docs_target" 2>/dev/null) if test (count $contents) -gt 0 diff --git a/functions/agy.fish b/functions/agy.fish index d078b0e..f1343be 100644 --- a/functions/agy.fish +++ b/functions/agy.fish @@ -8,7 +8,7 @@ # Wrapper for the agy Antigravity AI CLI that ensures the AGENTS/ # sub-repository is initialized and any agent-made changes are committed # before launch. Delegates all scaffold and commit logic to agents-init -# --agents. All arguments are forwarded verbatim to the real agy binary. +# (full setup). All arguments are forwarded verbatim to the real agy binary. # # Opinionated component (C1): when disabled via __fish_config_op_aliases # (or the __fish_config_opinionated master), the command is passed through @@ -30,7 +30,7 @@ function agy --wraps=agy --description 'agy wrapper: auto-initializes AGENTS/ su return $status end - agents-init --agents + agents-init command agy $argv end diff --git a/functions/claude.fish b/functions/claude.fish index 6fdf110..b2b1f92 100644 --- a/functions/claude.fish +++ b/functions/claude.fish @@ -7,7 +7,7 @@ # DESCRIPTION # Wrapper for the claude CLI that ensures the AGENTS/ sub-repository is # initialized and any agent-made changes are committed before launch. -# Delegates all scaffold and commit logic to agents-init --agents. +# Delegates all scaffold and commit logic to agents-init (full setup). # All arguments are forwarded verbatim to the real claude binary. # # Opinionated component (C1): when disabled via __fish_config_op_aliases @@ -30,7 +30,7 @@ function claude --wraps=claude --description 'claude wrapper: auto-links AGENTS. return $status end - agents-init --agents + agents-init command claude $argv end From 9f9248deb1364639fbbcf172650d084d3f9a3ad0 Mon Sep 17 00:00:00 2001 From: rootiest Date: Fri, 12 Jun 2026 23:30:12 -0400 Subject: [PATCH 19/24] fix(agents-init): fix gitignore duplicate entries, add block comment style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Strip leading / from pattern before git check-ignore so root-anchored patterns like /AGENTS.md are checked as repo-relative paths (AGENTS.md) and correctly match existing rules — fixes duplicates on every run - Rework helper to accept multiple patterns and write them as a single labeled block with project-style header/footer comment rather than appending bare patterns one at a time - Move gitignore calls out of per-plug loop in --plugins mode so all three docs/ patterns are checked and written in one block - Remove 5 duplicate bare entries left in .gitignore by the broken runs --- functions/_agents_init_ensure_gitignore.fish | 85 +++++++++++++------- functions/agents-init.fish | 6 +- 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/functions/_agents_init_ensure_gitignore.fish b/functions/_agents_init_ensure_gitignore.fish index f19d6ec..f4f411a 100644 --- a/functions/_agents_init_ensure_gitignore.fish +++ b/functions/_agents_init_ensure_gitignore.fish @@ -2,54 +2,81 @@ # SPDX-License-Identifier: AGPL-3.0-or-later # SYNOPSIS -# _agents_init_ensure_gitignore +# _agents_init_ensure_gitignore