@eric0117/agentforge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +275 -0
  3. package/dist/add-agent.js +145 -0
  4. package/dist/add-skill.js +185 -0
  5. package/dist/agent-prompt.js +211 -0
  6. package/dist/agentforge-config.js +106 -0
  7. package/dist/agents/claude.js +46 -0
  8. package/dist/agents/codex.js +67 -0
  9. package/dist/agents/cursor.js +54 -0
  10. package/dist/agents/index.js +15 -0
  11. package/dist/agents/io.js +252 -0
  12. package/dist/agents/types.js +1 -0
  13. package/dist/cli.js +374 -0
  14. package/dist/confirm.js +20 -0
  15. package/dist/doctor.js +223 -0
  16. package/dist/enter.js +85 -0
  17. package/dist/init.js +272 -0
  18. package/dist/lang-prompt.js +88 -0
  19. package/dist/list-skills.js +120 -0
  20. package/dist/logo.js +181 -0
  21. package/dist/path-prompt.js +148 -0
  22. package/dist/remove-agent.js +63 -0
  23. package/dist/remove-skill.js +88 -0
  24. package/dist/rename.js +222 -0
  25. package/dist/skill-prompt.js +199 -0
  26. package/dist/skills-data.js +727 -0
  27. package/dist/sync-skills.js +59 -0
  28. package/dist/templates/CLAUDE.md.tpl +141 -0
  29. package/dist/templates/context-handoff.SKILL.md.tpl +222 -0
  30. package/dist/templates/cross-repo-impact.SKILL.md.tpl +241 -0
  31. package/dist/templates/feature-retro.SKILL.md.tpl +312 -0
  32. package/dist/templates/feature-start.SKILL.md.tpl +631 -0
  33. package/dist/templates/history.SKILL.md.tpl +165 -0
  34. package/dist/templates/incident-context.SKILL.md.tpl +260 -0
  35. package/dist/templates/pr-create.SKILL.md.tpl +403 -0
  36. package/dist/templates/pr-review-analyze.SKILL.md.tpl +303 -0
  37. package/dist/templates/pre-deploy-check.SKILL.md.tpl +350 -0
  38. package/dist/templates/project-router.SKILL.md.tpl +55 -0
  39. package/dist/templates/release-coordinate.SKILL.md.tpl +209 -0
  40. package/package.json +54 -0
@@ -0,0 +1,59 @@
1
+ import { existsSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { readMasterDir } from "./agents/io.js";
4
+ import { getAgent } from "./agents/index.js";
5
+ import { masterDir, requireWorkspace } from "./agentforge-config.js";
6
+ import { SKILLS } from "./skills-data.js";
7
+ const DIM = "\x1b[2m";
8
+ const GREEN = "\x1b[32m";
9
+ const YELLOW = "\x1b[33m";
10
+ const CYAN = "\x1b[36m";
11
+ const BOLD = "\x1b[1m";
12
+ const RED = "\x1b[31m";
13
+ const RESET = "\x1b[0m";
14
+ export async function runSyncSkills(opts) {
15
+ const root = resolve(opts.pathArg ?? process.cwd());
16
+ const cfg = requireWorkspace(root);
17
+ if (!existsSync(masterDir(root))) {
18
+ process.stderr.write(`\n${YELLOW}⚠${RESET} No master skills directory at ${DIM}${masterDir(root)}${RESET}\n\n` +
19
+ ` Run ${CYAN}agentforge init${RESET} here first to set up the workspace.\n\n`);
20
+ process.exit(1);
21
+ }
22
+ const { skills: masterSkills, skipped, warnings } = readMasterDir(masterDir(root));
23
+ if (skipped.length > 0) {
24
+ console.log(`${YELLOW}skipped invalid master files:${RESET}`);
25
+ for (const sk of skipped) {
26
+ console.log(` ${DIM}- ${sk.file}: ${sk.reason}${RESET}`);
27
+ }
28
+ console.log("");
29
+ }
30
+ if (warnings.length > 0) {
31
+ console.log(`${YELLOW}master file warnings:${RESET}`);
32
+ for (const w of warnings) {
33
+ console.log(` ${DIM}- ${w.file}: ${w.warning}${RESET}`);
34
+ }
35
+ console.log("");
36
+ }
37
+ if (masterSkills.length === 0) {
38
+ console.log(`${YELLOW}no valid master skills found — nothing to sync.${RESET}`);
39
+ return;
40
+ }
41
+ console.log(`${BOLD}${GREEN}↻${RESET} syncing ${masterSkills.length} skill(s) → ${cfg.agents.length} agent(s) in ${CYAN}${root}${RESET}`);
42
+ console.log("");
43
+ // sync-skills is propagate-by-design: always back up and overwrite. Pass
44
+ // forceSkills=true unconditionally; forceClaude only when explicit.
45
+ for (const id of cfg.agents) {
46
+ const adapter = getAgent(id);
47
+ console.log(`${BOLD}${CYAN}▸ ${adapter.label}${RESET}`);
48
+ adapter.install({
49
+ root,
50
+ masterSkills,
51
+ skillCatalog: SKILLS.slice(),
52
+ lang: cfg.lang,
53
+ forceSkills: true,
54
+ forceClaude: opts.forceClaude,
55
+ });
56
+ console.log("");
57
+ }
58
+ console.log(`${BOLD}${GREEN}✓${RESET} sync complete ${DIM}(skills: ${masterSkills.map((s) => s.id).join(", ")})${RESET}`);
59
+ }
@@ -0,0 +1,141 @@
1
+ # Multi-Repo Workspace
2
+
3
+ This directory is an [agentforge](https://github.com/) workspace — a bootstrapped layout
4
+ for working across multiple repositories with Claude Code, designed for the case where
5
+ one feature spans several repos and several features need to be developed in parallel.
6
+
7
+ ## Directory layout
8
+
9
+ ```
10
+ .
11
+ ├── repos/ # main branch of each repo (read / explore only)
12
+ ├── anvil/ # per-feature worktrees — ONLY in-progress work
13
+ │ └── <slug>/
14
+ │ ├── <repo>/ # a worktree of <repo> for this feature
15
+ │ └── CLAUDE.md # feature description + repos in scope
16
+ ├── artifacts/ # closed features, grouped by completion date
17
+ │ └── <YYYYMMDD>/
18
+ │ └── <slug>/
19
+ │ ├── CLAUDE.md # original feature metadata (moved here on retro)
20
+ │ ├── RETRO.md # retrospective
21
+ │ ├── sessions/ # Claude Code transcripts
22
+ │ ├── plans/ # plan files
23
+ │ └── refs.json # per-repo branch + HEAD + PR pointers
24
+ ├── agentforge/ # workspace metadata + master skills (the single source of truth)
25
+ │ ├── config.json
26
+ │ ├── skills/
27
+ │ └── log.jsonl # append-only activity log
28
+ └── .claude/skills/ .cursor/rules/ .agents/skills/ # per-agent generated files
29
+ ```
30
+
31
+ - **`repos/<name>/`** — you `git clone` your repos here yourself. Used for
32
+ read / explore only. Don't edit code here.
33
+ - **`anvil/<slug>/<repo>/`** — feature work happens in worktrees. The
34
+ `agentforge-feature-start` skill creates these.
35
+ - **`artifacts/<YYYYMMDD>/<slug>/`** — once `feature-retro` closes a feature, the
36
+ worktree is removed and the retrospective + supporting artifacts land here.
37
+ `ls artifacts/` shows every completed feature, newest dates first.
38
+ - **`agentforge/skills/<id>.md`** — master copy of every skill. Edit a file here
39
+ and run `agentforge sync-skills` to push the change to every installed agent.
40
+
41
+ ## Installed skills
42
+
43
+ All skills below are workspace-local (under `.claude/skills/`) and are auto-loaded by
44
+ Claude Code when you run `claude` from this directory or any subdirectory. Trigger them
45
+ by describing what you want in natural language — you don't have to remember the names.
46
+
47
+ ### Day-to-day
48
+
49
+ #### Ask a question / explore code
50
+ From the workspace root, just describe what you want.
51
+ **`agentforge-project-router`** picks the right `repos/<name>/` to look in, or asks you
52
+ when ambiguous.
53
+
54
+ > "Where is the auth handler in the backend API?"
55
+ > "What does the admin's user list page do?"
56
+
57
+ ### Feature lifecycle
58
+
59
+ #### 1. Start a new feature
60
+ > "Let's start a new feature: search ranking."
61
+
62
+ **`agentforge-feature-start`** proposes a kebab-case slug, asks which repos the feature
63
+ touches, and creates `git worktree`s under `anvil/<slug>/<repo>/`.
64
+
65
+ #### 2. Work on the feature
66
+ ```bash
67
+ cd anvil/<slug>/
68
+ claude
69
+ ```
70
+ A single session at that path sees all worktrees of the feature at once.
71
+
72
+ #### 3. Check what a change would break (before touching shared code)
73
+ > "Where else is `doSomething` used?" · "Blast radius of removing `/v1/things`?"
74
+
75
+ **`agentforge-cross-repo-impact`** searches every other `repos/*` for call sites,
76
+ imports, HTTP callers, type usages, etc. and flags breaking changes.
77
+
78
+ #### 4. Pre-deploy sanity check
79
+ > "Anything ops needs before I ship this?" · "Pre-deploy check."
80
+
81
+ **`agentforge-pre-deploy-check`** scans the worktree diff for non-code changes —
82
+ DB migrations, env vars, cache keys, message-queue schemas, dependency locks, infra
83
+ config, feature flags, API surface, cron jobs — and outputs a checklist + deploy
84
+ order.
85
+
86
+ #### 5. Open PRs for the feature
87
+ > "Open PRs for this feature." · "Make the PRs."
88
+
89
+ **`agentforge-pr-create`** detects which worktrees have commits ahead, lets you
90
+ multi-select, then opens one PR per repo via `gh`. Drafts titles + bodies from the
91
+ feature's `CLAUDE.md` and the per-repo diff stat, and cross-links the PRs to each
92
+ other.
93
+
94
+ #### 6. Audit review comments
95
+ > "Audit the PR comments." · "What do we need to fix from the review?"
96
+
97
+ **`agentforge-pr-review-analyze`** pulls every review thread, verifies each against the
98
+ live code, classifies impact (Critical → Discussion), traces the call path, and notes
99
+ test coverage. Returns a prioritized action list.
100
+
101
+ #### 7. Wrap up a finished feature
102
+ > "We're done with this feature." · "Write a retro and clean up."
103
+
104
+ **`agentforge-feature-retro`**:
105
+ 1. Creates `artifacts/<YYYYMMDD>/<slug>/` (close-date directory).
106
+ 2. Copies Claude Code session logs (`~/.claude/projects/.../*.jsonl`) into
107
+ `artifacts/<YYYYMMDD>/<slug>/sessions/`.
108
+ 3. Copies relevant plan files (`~/.claude/plans/*.md`) into the same archive's
109
+ `plans/`.
110
+ 4. Captures per-repo branch + HEAD + PR pointers into `refs.json`.
111
+ 5. Writes `RETRO.md` — what was asked, decided, built, learned.
112
+ 6. Moves `anvil/<slug>/CLAUDE.md` into the archive directory.
113
+ 7. Removes each `anvil/<slug>/<repo>/` worktree (only if no dirty / unpushed
114
+ changes), then deletes the now-empty `anvil/<slug>/` directory so `anvil/`
115
+ only contains in-progress features.
116
+
117
+ ### Looking back
118
+
119
+ #### Recall past features
120
+ > "How did we handle the retry logic last time?" · "Which feature touched
121
+ > mobile-app for queue config?" · "Find that PR about search rankings."
122
+
123
+ **`agentforge-history`** searches every `artifacts/<YYYYMMDD>/<slug>/` (RETROs, plan
124
+ files, `refs.json` with branch/HEAD/PR pointers) and answers with grounded
125
+ references — file paths, commit hashes, PR URLs — so you can verify and dig
126
+ deeper. Filters by keyword, repo, date window, or PR/commit. Read-only.
127
+
128
+ ### Operations
129
+
130
+ #### Incident context (you just got paged)
131
+ > "Got an alert about `NullPointerException at Foo.process` — pull context."
132
+
133
+ **`agentforge-incident-context`** searches every repo for matching code, identifies
134
+ recent merged PRs that touched it, names the last committers, traces the call path
135
+ (highlighting async entry points), and proposes next steps. Optimized for a 30-second
136
+ read.
137
+
138
+ ## Current repos
139
+
140
+ Run `ls repos/` to see them. agentforge does not maintain a separate metadata file —
141
+ the filesystem is the source of truth.
@@ -0,0 +1,222 @@
1
+ ---
2
+ name: agentforge-context-handoff
3
+ description: Packages a feature's current state into a single handoff document so another developer (or future-self) can pick up without context loss. Gathers per-worktree git state, open PRs and their review state, unaddressed comments, pending plan items, recent decisions, recently touched files, open TODOs and questions. Writes anvil/<slug>/HANDOFF.md. Optionally posts the same summary as a comment on each related PR — only with explicit user confirmation. Never modifies CLAUDE.md, never pushes commits. Triggers on "hand this off", "휴가 가니 정리해줘", "leave notes for next session", "다음 사람한테 넘길 패키지", "package this up".
4
+ ---
5
+
6
+ # context-handoff
7
+
8
+ Packages the current state of a feature into a single document — `HANDOFF.md` —
9
+ so another developer (or future-you, three weeks from now) can resume without
10
+ having to reconstruct context from git, PR threads, and memory.
11
+
12
+ Read-mostly: writes one new file in the feature directory and, only with
13
+ explicit confirmation, posts the same summary as a comment on each related PR.
14
+ Never touches existing CLAUDE.md, never pushes commits, never modifies code.
15
+
16
+ ## When to apply
17
+
18
+ Trigger phrases:
19
+ - "Hand this off." / "Package this up."
20
+ - "Leave notes for next session."
21
+ - "휴가 가니 정리해줘." / "다음 사람한테 넘길 패키지."
22
+ - "I'm switching pairs — write a handoff."
23
+
24
+ Also a good fit before a long pause (vacation, parental leave, sprint
25
+ boundary), or before genuinely handing the feature to a different developer.
26
+
27
+ ## Resolve scope
28
+
29
+ The handoff is **always per-feature**. Resolve the slug from cwd:
30
+
31
+ - `…/anvil/<slug>/` (or anywhere inside it) → that feature.
32
+ - Workspace root, no obvious context → ask the user for the slug, or list
33
+ active features (`ls anvil/`).
34
+
35
+ If the named slug has no `anvil/<slug>/` directory, stop and tell the user —
36
+ either the feature was already wrapped up (check `artifacts/`) or the slug is
37
+ wrong.
38
+
39
+ ## Step 1 — Gather feature metadata
40
+
41
+ Read `anvil/<slug>/CLAUDE.md`:
42
+ - Feature description (the heading + first paragraph)
43
+ - `Started:` / `Expanded:` dates
44
+ - `Repos in scope:` list with per-repo branch names
45
+
46
+ If `anvil/<slug>/PLAN.md` exists (from `feature-plan` or hand-written), read
47
+ its pending items.
48
+
49
+ ## Step 2 — Per-worktree state
50
+
51
+ For each repo in scope (`ls -d anvil/<slug>/*/`):
52
+
53
+ ```bash
54
+ branch=$(git -C anvil/<slug>/<repo> rev-parse --abbrev-ref HEAD)
55
+ base=$(git -C anvil/<slug>/<repo> symbolic-ref --quiet refs/remotes/origin/HEAD \
56
+ | sed 's@^refs/remotes/origin/@@')
57
+
58
+ # Recent commits on this branch (since base)
59
+ git -C anvil/<slug>/<repo> log --oneline "origin/$base..HEAD" | head -20
60
+
61
+ # Working-tree state — uncommitted work is the most important thing to flag
62
+ git -C anvil/<slug>/<repo> status --porcelain
63
+
64
+ # Unpushed commits
65
+ git -C anvil/<slug>/<repo> log @{u}..HEAD --oneline 2>/dev/null
66
+
67
+ # Files recently touched (signal for "where I left off")
68
+ git -C anvil/<slug>/<repo> diff --name-only "origin/$base"...HEAD
69
+ git -C anvil/<slug>/<repo> diff --name-only # unstaged
70
+ git -C anvil/<slug>/<repo> diff --cached --name-only # staged
71
+ ```
72
+
73
+ Capture per repo:
74
+ - branch + base
75
+ - # of commits ahead of base
76
+ - dirty? (uncommitted changes — itemize files)
77
+ - unpushed? (local commits not on remote)
78
+ - last commit message + date (a one-line "where I was")
79
+
80
+ ## Step 3 — Open PRs and their state
81
+
82
+ For each repo's branch, look up the PR:
83
+
84
+ ```bash
85
+ gh -R <owner>/<repo> pr list --head "$branch" --state open \
86
+ --json number,url,isDraft,mergeStateStatus,statusCheckRollup,reviews,reviewRequests
87
+ ```
88
+
89
+ If a PR exists, also pull:
90
+
91
+ ```bash
92
+ gh -R <owner>/<repo> pr view <num> --json title,body,comments,reviewDecision
93
+ gh api repos/<owner>/<repo>/pulls/<num>/comments # inline review threads
94
+ ```
95
+
96
+ For each PR, capture:
97
+ - number + URL + draft/ready
98
+ - CI status (failing / pending / green)
99
+ - review state (approved / changes-requested / pending)
100
+ - **unaddressed comments**: review threads where the last reply is from a
101
+ reviewer and not the author, and the thread is not marked resolved. These are
102
+ the most important things for the next person to handle.
103
+
104
+ Note repos with no PR yet — that's a follow-up item.
105
+
106
+ ## Step 4 — Decisions, TODOs, open questions
107
+
108
+ Extract from sources in this order:
109
+
110
+ 1. `anvil/<slug>/CLAUDE.md` — any free-text decisions the user wrote.
111
+ 2. `anvil/<slug>/PLAN.md` — pending plan items (unchecked boxes).
112
+ 3. Recent commits with subjects like `chore:`, `fixup!`, `WIP:` — flag these
113
+ as "needs cleanup before merge."
114
+ 4. `git -C anvil/<slug>/<repo> diff "origin/$base"...HEAD | grep -E '^\+.*(TODO|FIXME|XXX)'`
115
+ — TODOs the user introduced in this feature.
116
+ 5. The most recent Claude Code session transcript for this feature (under
117
+ `~/.claude/projects/.../*.jsonl` matching this workspace), if accessible —
118
+ skim the last summary block for "next steps" / "blocked on" phrases. Don't
119
+ re-read the entire session.
120
+
121
+ If extraction yields nothing concrete, leave the section as
122
+ "(no explicit open questions captured — ask the original author)."
123
+
124
+ ## Step 5 — Write HANDOFF.md
125
+
126
+ Write to `anvil/<slug>/HANDOFF.md` (overwrite if it exists; back up the old one
127
+ to `HANDOFF.md.bak` first). Structure:
128
+
129
+ ```markdown
130
+ # Handoff: <slug>
131
+
132
+ > Generated <YYYY-MM-DD HH:MM> by agentforge-context-handoff.
133
+ > This file is informational. Source of truth is git + the open PRs.
134
+
135
+ ## Feature
136
+
137
+ <one-paragraph description from CLAUDE.md>
138
+
139
+ Started <date>. <N> repo(s) in scope.
140
+
141
+ ## State at handoff time
142
+
143
+ | Repo | Branch | PR | CI | Reviews | Dirty? | Unpushed? |
144
+ |---|---|---|---|---|---|---|
145
+ | <repo-1> | <branch-1> | #<N> | <icon> | <state> | <yes/no> | <yes/no> |
146
+ | ... |
147
+
148
+ ## What's done
149
+
150
+ - <repo-1>: <N> commits ahead — <high-level summary of what the diff does>
151
+ - <repo-2>: ...
152
+
153
+ ## What's pending
154
+
155
+ ### Unaddressed review comments
156
+ - <repo-1> #<N>: <comment thread summary + file:line + reviewer> → <link>
157
+ - ...
158
+
159
+ ### Open questions
160
+ - <extracted question 1>
161
+ - ...
162
+
163
+ ### TODO markers introduced in this feature
164
+ - <file:line>: <TODO text> (<repo>)
165
+ - ...
166
+
167
+ ### Plan items not yet done
168
+ - [ ] <item from PLAN.md>
169
+ - ...
170
+
171
+ ## Where to look next
172
+
173
+ - <repo-1>/<file>:<line> — most recently edited; <last commit message>
174
+ - ...
175
+
176
+ ## How to resume
177
+
178
+ 1. `cd anvil/<slug>/` and start a session (`claude` or your CLI).
179
+ 2. Read this file first.
180
+ 3. Read each open PR's unaddressed comments.
181
+ 4. Run `agentforge-feature-resume` (if available) for an AI briefing.
182
+ ```
183
+
184
+ After writing, print the path and a one-line summary to the user.
185
+
186
+ ## Step 6 — (Optional) PR comments
187
+
188
+ Ask the user explicitly: "Post a handoff summary as a comment on each open PR?
189
+ (default: no)"
190
+
191
+ Only on "yes":
192
+
193
+ ```bash
194
+ # Summarize for PR audience (different from the full HANDOFF.md — shorter,
195
+ # focused on what reviewers need to know to keep the PR moving)
196
+ gh -R <owner>/<repo> pr comment <num> --body "<summary>"
197
+ ```
198
+
199
+ The PR comment should include:
200
+ - "Handoff posted on <date>" + link to `anvil/<slug>/HANDOFF.md` path (relative)
201
+ - A short list of "what's pending on this PR specifically"
202
+ - Who the next person to contact is, if known
203
+
204
+ **Never post comments without explicit user confirmation** — comments are
205
+ visible to teammates and can confuse them if posted prematurely.
206
+
207
+ ## Rules
208
+
209
+ - **Read-only on existing files** — never edit `CLAUDE.md`, `PLAN.md`, code, or
210
+ PR descriptions. Only write the new `HANDOFF.md`.
211
+ - **No git push, no PR merge, no PR review.**
212
+ - **PR comments only with explicit confirmation.**
213
+ - **Back up before overwrite** — if `HANDOFF.md` exists, move it to
214
+ `HANDOFF.md.bak` first (don't silently overwrite).
215
+ - **Branch names from worktrees, not slug** — per-repo branches may differ.
216
+ - **Dirty worktrees are the #1 thing to flag** — uncommitted work is invisible
217
+ to anyone but the original author; the handoff exists primarily to surface
218
+ this.
219
+
220
+ ## Output language
221
+
222
+ {{OUTPUT_LANGUAGE_INSTRUCTION}}
@@ -0,0 +1,241 @@
1
+ ---
2
+ name: agentforge-cross-repo-impact
3
+ description: Traces the blast radius of a change across every repo in the workspace. Given a symbol (function, class, type, API endpoint, env var, config key) or the current worktree's diff, finds all the places in other repos that depend on it, classifies each usage (call site / import / HTTP caller / string reference), and flags breaking-change risks. Triggers on "what's the impact of this change?", "where else is X used?", "if I rename this, what breaks?", "blast radius of …", "any callers in other repos?".
4
+ ---
5
+
6
+ # cross-repo-impact
7
+
8
+ This is the multi-repo workspace's blast-radius tool. When the user changes something in
9
+ one repo, this skill finds every other repo in the workspace that touches it and
10
+ reports the impact, grouped by repo and by usage kind.
11
+
12
+ **Read-only.** This skill never modifies code.
13
+
14
+ ## When to apply
15
+
16
+ Trigger on questions like:
17
+ - "What's the impact of this change?"
18
+ - "Where else is `<symbol>` used?"
19
+ - "If I rename / change the signature of `<symbol>`, what breaks?"
20
+ - "Blast radius of removing endpoint `/v1/things`?"
21
+ - "Anything in admin-web that calls this?"
22
+
23
+ If the user is mid-implementation and asks "before I touch this, who uses it?" — that's
24
+ this skill.
25
+
26
+ ## Locate the workspace
27
+
28
+ This skill needs the workspace layout (`repos/` and possibly `anvil/<slug>/`). Walk up
29
+ from cwd until you find a directory containing `repos/`. If no such directory is found,
30
+ tell the user: "Not inside an agentforge workspace — falling back to current repo only,"
31
+ and proceed with cwd as the single search target.
32
+
33
+ The source repo (where the change lives) is determined from cwd:
34
+ - `…/anvil/<slug>/<repo>/` → source = that `<repo>`; search the **other** `repos/*`
35
+ (and other `anvil/<slug>/*` worktrees) for usages.
36
+ - `…/repos/<name>/` → source = `<name>`; search the other `repos/*`.
37
+ - Elsewhere → ask the user which repo is the source.
38
+
39
+ The search set is every `repos/<other>/` plus every `anvil/<other-slug>/<other-repo>/`
40
+ the user wants included (default: just `repos/*` to avoid duplicate hits from sibling
41
+ worktrees of the same repo).
42
+
43
+ ## Determine what to analyze
44
+
45
+ Two modes:
46
+
47
+ ### Mode A — user names a target
48
+
49
+ The user gives one or more of:
50
+ - A symbol name (`doSomething`, `User`, `SomeType`)
51
+ - An HTTP endpoint (`POST /v1/things`, `/api/users/:id`)
52
+ - A config / env key (`KAFKA_BROKER_URL`, `feature.search-ranking.enabled`)
53
+ - A message / event name (`ItemCreated`, `something.changed`)
54
+
55
+ Use this verbatim.
56
+
57
+ ### Mode B — auto from worktree diff
58
+
59
+ If the user says "what does this change touch?" without naming a target, derive
60
+ candidates from the current diff:
61
+
62
+ ```bash
63
+ git -C <source-repo> diff --unified=0 <main-branch>...HEAD
64
+ ```
65
+
66
+ Extract candidate targets:
67
+ - **Function / method renames or signature changes** — look for hunks where a `def`,
68
+ `function`, `fun`, `func` line was modified.
69
+ - **Newly exported / removed symbols** — look for changes in `export`, `pub`, public
70
+ visibility.
71
+ - **HTTP route changes** — look for hunks containing route decorators / annotations
72
+ (`@RequestMapping`, `@Get(`, `app.get(`, `@router.get`, Gin/Fiber/Express patterns).
73
+ - **Removed env / config keys** — look for `process.env.X`, `System.getenv("X")`,
74
+ `os.getenv("X")`, `viper.GetString("X")` patterns that disappeared.
75
+ - **Type / schema changes** — modified `interface`, `type`, `class`, `data class`,
76
+ `struct`, proto fields.
77
+
78
+ Show the user the candidate list and ask them to pick which ones to analyze. Don't
79
+ silently analyze everything — the diff may contain noise.
80
+
81
+ ## Detect languages per target repo
82
+
83
+ For each repo in the search set, sample a few source files to infer language(s):
84
+
85
+ ```bash
86
+ find <repo> -maxdepth 3 -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.kt' \
87
+ -o -name '*.java' -o -name '*.py' -o -name '*.go' -o -name '*.rs' \
88
+ -o -name '*.rb' -o -name '*.php' \) 2>/dev/null | head -10
89
+ ```
90
+
91
+ Per-language search idioms (use whichever applies):
92
+
93
+ | Language | Call / use patterns |
94
+ |---|---|
95
+ | TypeScript / JavaScript | `\bX\(` , `import {[^}]*X[^}]*}` , `from ['"][^'"]*['"]` |
96
+ | Kotlin / Java | `\.X\(` , `import .*\.X` |
97
+ | Python | `\bX\(` , `from .* import .*X` , `import .*X` |
98
+ | Go | `\.X\(` , `X\(` (after dot-less import) |
99
+ | Rust | `::X\(` , `\.X\(` , `use .*::X` |
100
+ | Ruby | `\.X\b` , `X\(` |
101
+ | PHP | `->X\(` , `::X\(` , `use .*\\X` |
102
+
103
+ For HTTP endpoints, search for the literal path in any source/config file (route
104
+ strings are usually written as-is in client code), not just the framework idiom. For
105
+ config / env keys, grep the literal key name.
106
+
107
+ ## Standard exclusions (apply to every grep / search in this skill)
108
+
109
+ Always exclude these from any code search to avoid noise + speed up big repos:
110
+
111
+ ```
112
+ :!node_modules :!dist :!build :!target :!.next :!.nuxt :!.venv :!__pycache__
113
+ :!*.lock :!package-lock.json :!yarn.lock :!pnpm-lock.yaml :!Cargo.lock
114
+ :!*.min.js :!*.bundle.js :!coverage :!.git :!vendor
115
+ ```
116
+
117
+ With `git grep`, pass them as pathspec exclusions:
118
+ ```bash
119
+ git -C <repo> grep -nE '<pattern>' \
120
+ -- ':!node_modules' ':!dist' ':!build' ':!target' ':!.next' \
121
+ ':!*.lock' ':!coverage' ':!vendor'
122
+ ```
123
+
124
+ With plain `grep -r`, use `--exclude-dir=` / `--exclude=` repeatedly. If the user has
125
+ a `.gitignore`, prefer `git grep` (which already honors it).
126
+
127
+ ## Search & classify
128
+
129
+ For each (target, target-repo) pair, run the searches and classify each hit into one
130
+ of these kinds:
131
+
132
+ | Kind | Signal |
133
+ |---|---|
134
+ | 📞 **Call site** | symbol invoked: `X(...)` |
135
+ | 📥 **Import** | imported but not yet shown to be called in the surrounding hunk |
136
+ | 🌐 **HTTP caller** | code that opens the URL (axios/fetch/http client) targeting the endpoint string |
137
+ | 🔤 **String reference** | literal name appears in a log message, config, schema |
138
+ | 🧩 **Type usage** | the changed type appears in a signature, declaration, or generic parameter |
139
+ | 📜 **Schema / proto** | reference in a `.proto`, OpenAPI, JSON schema, SQL migration |
140
+ | 🧪 **Test reference** | hit is inside a test file (`*test*` , `__tests__`, etc.) |
141
+
142
+ Test hits are reported separately because they signal regression coverage rather than
143
+ production risk.
144
+
145
+ ## Breaking-change assessment
146
+
147
+ For each target, decide what kind of change it is and what that means for callers:
148
+
149
+ | Change kind | Effect on call sites |
150
+ |---|---|
151
+ | **Renamed** | All non-test call sites break — they need updating. |
152
+ | **Removed** | Hard break for all kinds. Highest urgency. |
153
+ | **Signature changed** (params added / removed / reordered / typed) | Call sites with the old shape break. Required vs optional parameters matter — note the difference. |
154
+ | **Return type changed** | Callers consuming the return value need updating. |
155
+ | **Behavior changed (same signature)** | Compiler / type checker won't catch it. Manual review per call site. |
156
+ | **New symbol** | No callers can break yet, but document it for discoverability. |
157
+ | **Endpoint URL changed** | HTTP callers using the old path break. Headers / methods matter too. |
158
+ | **Env / config key renamed** | Deployments need re-configuring before code roll-out. Mention deployment ordering. |
159
+
160
+ Note the trickiest case: **behavior changed, signature unchanged**. Static search can
161
+ list call sites, but the caller code still compiles. Flag this explicitly so the user
162
+ knows manual review is needed.
163
+
164
+ ## Output format
165
+
166
+ ```markdown
167
+ # Cross-repo impact: <target description>
168
+
169
+ > Source: `<source-repo>` (from `<cwd>`)
170
+ > Change kind: <renamed / removed / signature / behavior / new / endpoint / config>
171
+ > Search set: 3 repos (`admin-web`, `worker-service`, `mobile-app`)
172
+
173
+ ---
174
+
175
+ ## 💥 Breaking call sites
176
+
177
+ ### `admin-web` — 4 hits
178
+
179
+ | File | Line | Kind | Snippet |
180
+ |---|---|---|---|
181
+ | `src/pages/things.tsx` | 42 | 📞 Call site | `doSomething(id)` |
182
+ | `src/api/things.ts` | 11 | 📥 Import | `import { doSomething } from '@/api'` |
183
+ | `src/components/SomeButton.tsx` | 88 | 📞 Call site | `await doSomething(...)` |
184
+ | `src/__tests__.test.ts` | 19 | 🧪 Test | `doSomething(mockInput)` |
185
+
186
+ ### `mobile-app` — 1 hit
187
+
188
+ | File | Line | Kind | Snippet |
189
+ |---|---|---|---|
190
+ | `src/handlers/things.kt` | 102 | 📞 Call site | `someClient.doSomething(...)` |
191
+
192
+ ---
193
+
194
+ ## ⚠️ Same-signature behavior changes
195
+
196
+ If applicable, list call sites that won't be caught by the compiler but may behave
197
+ differently. Same table layout.
198
+
199
+ ---
200
+
201
+ ## ✅ Safe references (no action needed)
202
+
203
+ Things that match the symbol name but are unrelated (different scope, comment, log
204
+ string). Keep this list short — only include hits that the user might worry about.
205
+
206
+ ---
207
+
208
+ ## Summary
209
+
210
+ - `admin-web`: 3 production + 1 test → must update before merge
211
+ - `mobile-app`: 1 production → must update before merge
212
+ - `worker-service`: no hits
213
+
214
+ Suggested next steps:
215
+ 1. Update `admin-web` first (largest blast radius).
216
+ 2. Coordinate deploy ordering: backend-api before clients.
217
+ 3. Add a deprecation shim if you can't update all clients in one go.
218
+ ```
219
+
220
+ Group by repo, then by file. Always include the snippet (one line). Don't truncate
221
+ file paths.
222
+
223
+ ## Rules
224
+
225
+ - **Never edit code.** Report only.
226
+ - **Don't claim a hit is broken without seeing it.** When the snippet alone is
227
+ ambiguous (e.g. the symbol name is a common word), open the file and confirm scope.
228
+ - **Respect the workspace boundary.** Only search `repos/*` (and explicitly-included
229
+ worktrees). Don't escape into the user's home directory or unrelated dirs.
230
+ - **Distinguish production vs test hits.** Both matter, but test hits are coverage
231
+ signal, not regression risk.
232
+ - **Acknowledge unknowns.** If a language in the workspace isn't in the table above,
233
+ fall back to a plain symbol-name grep and tell the user the analysis is best-effort.
234
+ - **Common names need extra care.** A symbol called `get` or `update` will match
235
+ noise — narrow the search using import paths or enclosing scope before reporting.
236
+ - **Don't truncate.** If there are too many hits, summarize counts per file but still
237
+ list every file.
238
+
239
+ ## Output language
240
+
241
+ {{OUTPUT_LANGUAGE_INSTRUCTION}}