@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,631 @@
1
+ ---
2
+ name: agentforge-feature-start
3
+ description: Starts a new feature in a multi-repo workspace, or adds repos to an existing one. Summarizes the feature into a kebab-case slug, suggests which repos it likely touches by grepping repos/* for keywords, asks the user to confirm via multi-select, and creates git worktrees under anvil/<slug>/<repo>/. Re-runnable — calling it again with an existing slug switches to "additive" mode and only adds the newly chosen repos. Triggers when the user says things like "let's start a new feature", "I want to build X", "add repo Y to feature Z", or otherwise signals starting or expanding a unit of work.
4
+ ---
5
+
6
+ # feature-start
7
+
8
+ Bootstraps a new feature by laying down git worktrees so the user can work across one
9
+ or more repos in parallel without disturbing their main checkouts. Re-runnable: calling
10
+ it again with the same slug extends the existing feature instead of starting over.
11
+
12
+ ## When to apply
13
+
14
+ Apply this skill when the user signals the **start of new work** or wants to **extend
15
+ an existing feature** with another repo:
16
+
17
+ - "Let's start a new feature."
18
+ - "I'm going to build X."
19
+ - "Let's begin work on Y."
20
+ - "Cut a new branch for Z."
21
+ - "Add repo `d` to `feat-search-ranking` too."
22
+ - "Also include the admin side in this feature."
23
+
24
+ Plain questions or exploration go to `project-router`. Only apply here when scope is
25
+ being opened or expanded.
26
+
27
+ ## Concurrency lock
28
+
29
+ Before any destructive action, take a workspace-level lock so two concurrent sessions
30
+ don't fight over the same feature:
31
+
32
+ ```bash
33
+ LOCK="anvil/<slug>/.agentforge.lock"
34
+ if [ -f "$LOCK" ]; then
35
+ cat "$LOCK" # shows pid + started-at written by the other session
36
+ # → tell the user another session is working on this feature and stop.
37
+ else
38
+ mkdir -p "$(dirname "$LOCK")"
39
+ printf 'pid=%s\nstarted=%s\nskill=agentforge-feature-start\n' \
40
+ "$$" "$(date -u +%FT%TZ)" > "$LOCK"
41
+ fi
42
+ ```
43
+
44
+ Release the lock on success **and** on every failure path (`trap` or explicit
45
+ removal). If a stale lock exists (older than ~30 min with no live pid), report it to
46
+ the user and ask whether to override.
47
+
48
+ ## Mode detection
49
+
50
+ Before anything else, decide which mode you're in by checking the slug:
51
+
52
+ - **New mode** — the user is describing a brand-new piece of work, and no
53
+ `anvil/<slug>/` directory exists yet for it.
54
+ - **Additive mode** — the user named an existing feature slug (or you derived the same
55
+ slug from the description and `anvil/<slug>/` already exists). In this mode, do not
56
+ re-derive the slug, do not overwrite `CLAUDE.md` — extend.
57
+
58
+ To detect additive mode:
59
+ 1. Walk up from cwd to find the workspace root (the directory containing `repos/` and
60
+ `anvil/`).
61
+ 2. If the user named a slug, check `test -d anvil/<slug>/`. If yes → additive mode.
62
+ 3. Otherwise derive a fresh slug from the description (see Step 1) and check the same
63
+ way. Match → additive. No match → new mode.
64
+
65
+ **Validate the metadata against reality.** In additive mode, read
66
+ `anvil/<slug>/CLAUDE.md` to learn which repos are listed as in-scope, then **verify
67
+ each one still has a worktree under `anvil/<slug>/<repo>/`**. If a listed repo's
68
+ directory is missing, treat it as "no longer present" — drop it from the locked set,
69
+ report the discrepancy to the user, and offer to update CLAUDE.md to reflect the
70
+ current state.
71
+
72
+ ## How to do it
73
+
74
+ ### Step 0 — Suggest which repos this feature likely touches
75
+
76
+ Before asking the user, run a light grep across `repos/*` using keywords from the
77
+ feature description. Goal: pre-check the repos that obviously contain related code, so
78
+ the user just confirms instead of guessing.
79
+
80
+ Process:
81
+ 1. Extract searchable tokens from the feature description: drop stop-words, keep nouns
82
+ and identifier-like phrases. Example: "Improve the search ranking" →
83
+ `[search, ranking, improve]`.
84
+ 2. For each `repos/<name>/`, run a fast case-insensitive search restricted to source
85
+ files (exclude `node_modules`, `dist`, `build`, `.git`, lock files):
86
+ ```bash
87
+ git -C repos/<name> grep -li -E '<token1>|<token2>|<token3>' \
88
+ -- ':!*.lock' ':!node_modules' ':!dist' ':!build' \
89
+ | head -5
90
+ ```
91
+ Or fall back to `grep -rli` if not a git repo.
92
+ 3. Score each repo by hit count. **Pre-check repos with at least one hit.**
93
+ 4. **Always include all repos in the multi-select** — the pre-check is a *suggestion*,
94
+ not a filter. The user may know about a repo that grep missed (e.g. a new module
95
+ being added from scratch).
96
+
97
+ Tell the user what you found, briefly:
98
+ ```
99
+ Searched repos/ for: search, ranking, improve
100
+ ✓ backend-api (12 files match)
101
+ ✓ admin-web (4 files match)
102
+ ✓ worker-service (1 file matches)
103
+ · mobile-app (no matches)
104
+ ```
105
+
106
+ In **additive mode**, restrict the search to repos NOT already in the feature, so the
107
+ suggestion is about what to add.
108
+
109
+ ### Step 1 — Get / confirm the slug
110
+
111
+ **New mode:** derive a kebab-case slug from the description.
112
+
113
+ The slug has three parts: `<YYMMDD>-<kind>-<core>`.
114
+
115
+ **Date prefix** — today in `YYMMDD` form (e.g. `260523` for 2026-05-23). This
116
+ makes `ls anvil/` naturally sort by start date.
117
+
118
+ ```bash
119
+ date -u +%y%m%d
120
+ ```
121
+
122
+ **Kind prefix** — infer from the user's wording. This is what distinguishes a
123
+ new feature from a bug fix or refactor in the directory listing and in
124
+ `artifacts/` history:
125
+
126
+ | Kind | Trigger words (en / ko) |
127
+ |----------|-------------------------------------------------------------------------------------------|
128
+ | `feat` | "feature", "add", "implement", "introduce", "support", "build" / "추가", "구현", "기능", "도입" |
129
+ | `fix` | "bug", "fix", "broken", "incorrect", "wrong", "regression" / "버그", "오류", "고치", "픽스", "잘못" |
130
+ | `refactor` | "refactor", "cleanup", "rewrite", "simplify", "reorganize" / "리팩터", "정리", "단순화", "재구성" |
131
+ | `chore` | "chore", "bump", "deps", "tooling", "ci", "config", "format" / "버전 업", "의존성", "툴링", "설정" |
132
+
133
+ If the wording is ambiguous (e.g. "let's start a new one" with no other
134
+ context), default to `feat` and confirm with the user when showing the slug.
135
+
136
+ **Core** — the kebab-case body. Lowercase ASCII letters, digits, hyphens only.
137
+ Up to 8 words. Capture the core meaning, drop filler words.
138
+
139
+ Examples (assuming today is 2026-05-23):
140
+ - "Improve the search ranking" → `260523-feat-search-ranking`
141
+ - "Tighten the rate limit" → `260523-feat-rate-limit-tighten`
142
+ - "Fix the search ranking regression" → `260523-fix-search-ranking`
143
+ - "Refactor the rate limit module" → `260523-refactor-rate-limit`
144
+ - "Bump axios across all repos" → `260523-chore-axios-bump`
145
+
146
+ Show the slug back to the user and **get explicit confirmation** (or a corrected
147
+ slug — the user can change the kind too if you guessed wrong). The slug is used
148
+ for the worktree directory; per-repo branch names are decided separately in
149
+ Step 3.5 and may follow each repo's own convention.
150
+
151
+ **Additive mode:** the slug is the existing one — skip this step. Read
152
+ `anvil/<slug>/CLAUDE.md` to learn the original description and which repos are
153
+ already in scope.
154
+
155
+ ### Step 2 — Multi-select repos
156
+
157
+ Run `ls repos/` to list the workspace's repos. Present them to the user as a
158
+ multi-select with the Step 0 suggestions **pre-checked**:
159
+
160
+ ```
161
+ Which repos does this feature touch? (suggestions pre-checked)
162
+ [x] backend-api ← matched 12 files for the keywords
163
+ [x] admin-web ← matched 4 files
164
+ [x] worker-service ← matched 1 file
165
+ [ ] mobile-app (no matches, include if you know it's involved)
166
+ ```
167
+
168
+ **In additive mode**, also indicate which repos are already in the feature — show them
169
+ as `(already in feature)` and **disabled** (informational only). The user picks only
170
+ from the rest:
171
+
172
+ ```
173
+ feat-search-ranking — Repos in scope:
174
+ [*] backend-api (already in feature)
175
+ [ ] mobile-app
176
+ [ ] admin-web ← matched 4 files for "search, ranking, improve"
177
+ [x] worker-service ← matched 1 file
178
+ ```
179
+
180
+ If your environment supports a structured multi-select, use it. Otherwise accept names
181
+ or numbers. **The pre-check is a suggestion; the user is still in control.**
182
+
183
+ ### Step 3 — Pre-flight check (per chosen repo)
184
+
185
+ Before touching any repo, run a quick state check on each one. This catches the case
186
+ where `repos/<repo>` is on an unexpected branch or has in-progress work, so the new
187
+ worktree starts from a deliberate base.
188
+
189
+ For each chosen repo, gather:
190
+
191
+ 1. **Base branch** — try in order, pick the first that exists:
192
+ ```bash
193
+ # default branch from origin
194
+ git -C repos/<repo> symbolic-ref --quiet refs/remotes/origin/HEAD \
195
+ | sed 's@^refs/remotes/origin/@@'
196
+ # fallback: a local branch named main / master / develop / trunk
197
+ git -C repos/<repo> show-ref --verify --quiet refs/heads/main && echo main
198
+ git -C repos/<repo> show-ref --verify --quiet refs/heads/master && echo master
199
+ git -C repos/<repo> show-ref --verify --quiet refs/heads/develop && echo develop
200
+ ```
201
+ If none found → ask the user which branch to base off.
202
+
203
+ 2. **Current branch** (or detached HEAD):
204
+ ```bash
205
+ git -C repos/<repo> symbolic-ref --short HEAD 2>/dev/null \
206
+ || echo "(detached at $(git -C repos/<repo> rev-parse --short HEAD))"
207
+ ```
208
+
209
+ 3. **Working-tree state**:
210
+ ```bash
211
+ git -C repos/<repo> status --porcelain
212
+ ```
213
+ Non-empty = uncommitted changes (staged + unstaged + untracked).
214
+
215
+ Present a state report to the user:
216
+
217
+ ```
218
+ Pre-flight:
219
+
220
+ repos/a
221
+ base = origin/main
222
+ current = feat-other ⚠ not on base
223
+ working = 3 uncommitted files
224
+ repos/d
225
+ base = origin/main
226
+ current = main ✓
227
+ working = clean
228
+ repos/e
229
+ base = origin/main
230
+ current = main ✓
231
+ working = 5 staged files ⚠ uncommitted (will be preserved)
232
+ ```
233
+
234
+ **Ask the user to confirm before proceeding** if any repo has a warning:
235
+ - Different current branch → "the new worktree will start from `origin/<base>`,
236
+ not from your current branch. OK?"
237
+ - Detached HEAD → same prompt, plus a heads-up that the current commit isn't on a
238
+ branch.
239
+ - Uncommitted changes → "these stay in `repos/<repo>` untouched; only the new
240
+ worktree is affected. Proceed?"
241
+
242
+ If the user says no for a repo, drop it from the set (do not auto-substitute).
243
+
244
+ ### Step 3.5 — Detect branch naming convention (per repo)
245
+
246
+ Different repos may use different branch naming conventions — one team writes
247
+ `feat/<COMPONENT>-<YYMMDD>-<topic>`, another writes `feature/<TICKET>`. Before
248
+ creating worktrees, sample each repo's recent branches, identify the dominant
249
+ template, and propose a branch name. The user confirms or edits per repo.
250
+
251
+ For each chosen repo (in **additive mode**, only the newly added ones):
252
+
253
+ **1. Sample recent branches:**
254
+
255
+ ```bash
256
+ git -C repos/<repo> for-each-ref \
257
+ --sort=-committerdate --count=30 \
258
+ --format='%(refname:short)' \
259
+ refs/heads refs/remotes/origin \
260
+ | sed 's|^origin/||' \
261
+ | grep -vE '^(HEAD|main|master|develop|trunk)$' \
262
+ | grep -vE '^(release|hotfix)/' \
263
+ | awk '!seen[$0]++' \
264
+ | head -15
265
+ ```
266
+
267
+ `awk '!seen[$0]++'` dedups local vs remote while preserving committer-date order.
268
+
269
+ **2. Analyze the template.** Read the samples and identify, as an LLM:
270
+ - **prefix namespace** — `feature/`, `feat/`, `bugfix/`, a username, or none
271
+ - **ticket / component tokens** — e.g. `<PROJ>-<CORE>`, `<PROJ>-1234`, `JIRA-42`.
272
+ Note both the format (component code vs Jira number) and its position.
273
+ - **date component** — `YYMMDD`, `YYYY-MM-DD`, `YYYYMMDD`, or none
274
+ - **separator** — `-`, `_`, or mixed
275
+ - **topic charset** — if ≥1 sample's topic part contains non-ASCII (Korean, etc.),
276
+ allow non-ASCII in the proposed topic; otherwise ASCII kebab only
277
+ - **component ordering** — derive the dominant order, e.g.
278
+ `<prefix>/<TICKET>-<YYMMDD>-<topic>`
279
+
280
+ Do **not** brute-force this with a rigid regex — orderings vary by team. Read the
281
+ samples as a human would. If samples are inconsistent (< 60% follow any one
282
+ template) or there are < 3 usable samples, fall back to the workspace default
283
+ `<slug>` as the branch name and tell the user "couldn't detect a clear pattern for
284
+ this repo, using `<slug>` as the branch name."
285
+
286
+ **3. Propose a branch.** Fill the template:
287
+ - `{date}` → today's date in the detected format (the same UTC date used in the
288
+ slug)
289
+ - `{topic}` → the feature's kebab core (the slug minus its `<YYMMDD>-feat-`
290
+ prefix). Preserve non-ASCII if the samples have it; otherwise ASCII-kebab.
291
+ - `{TICKET}` → ask the user: "ticket / component for `<repo>`? (or `skip`)". If
292
+ the user types `skip`, omit the segment cleanly (collapse adjacent separators
293
+ so you don't end up with `feature/--topic`).
294
+
295
+ **4. Show + confirm per repo.** For each repo, print the samples and the
296
+ proposal, then let the user accept (Enter), type a replacement, or `default`:
297
+
298
+ ```
299
+ <repo> — recent branches (last 15):
300
+ feature/<PROJ-CORE>-<YYMMDD>-<topic-a>
301
+ feature/<PROJ-WEB>-<YYMMDD>-<topic-b>
302
+ feature/<PROJ-API>-<YYMMDD>-<topic-c>
303
+ ...
304
+
305
+ Detected pattern: feature/{TICKET}-{YYMMDD}-{topic}
306
+
307
+ Ticket / component for <repo>? (or `skip`)
308
+ > <TICKET>
309
+
310
+ Proposed branch: feature/<TICKET>-<YYMMDD>-<topic>
311
+ [Enter to accept · type to override · `default` for <slug>]
312
+ >
313
+ ```
314
+
315
+ **5. Record** the final branch per repo in an in-memory map
316
+ `branches: { <repo>: <branch>, ... }`. Step 4 reads `<branch[repo]>` from it;
317
+ Step 5 (CLAUDE.md) and the activity log record it.
318
+
319
+ A user-edited branch may coincide with the workspace `<slug>` — that's fine. There
320
+ is no constraint that per-repo branches must differ from the slug.
321
+
322
+ ### Step 4 — Create worktrees (for newly chosen repos only)
323
+
324
+ For each chosen repo *that isn't already a worktree* under `anvil/<slug>/`, use the
325
+ detected base **explicitly** — never trust the current HEAD of `repos/<repo>`:
326
+
327
+ ```bash
328
+ # 1. fetch latest base. Capture the result — do NOT silently swallow failures.
329
+ if git -C repos/<repo> fetch origin <base> --quiet; then
330
+ fetched=ok
331
+ else
332
+ fetched=failed
333
+ fi
334
+
335
+ # 2. create the worktree from origin/<base> if fetch worked,
336
+ # otherwise from the local <base>. The branch name comes from Step 3.5's
337
+ # per-repo map (branches[<repo>]); fall back to <slug> if Step 3.5 was
338
+ # skipped (e.g. additive mode where this repo was already in place).
339
+ if [ "$fetched" = ok ]; then
340
+ git -C repos/<repo> worktree add ../../anvil/<slug>/<repo> -b <branch[repo]> origin/<base>
341
+ else
342
+ # Tell the user the remote is unreachable and ASK before continuing
343
+ # ("worktree will be based on local <base> which may be stale — proceed?")
344
+ git -C repos/<repo> worktree add ../../anvil/<slug>/<repo> -b <branch[repo]> <base>
345
+ fi
346
+ ```
347
+
348
+ If the user declines the stale base, skip this repo (don't substitute silently).
349
+
350
+ If the repo has no `origin` remote at all, base off the local branch and tell the
351
+ user that's what happened.
352
+
353
+ **Conflict handling:**
354
+ - If a branch named `<branch[repo]>` already exists on the repo, ask the user:
355
+ reuse the existing branch (drop the `-b` flag and use the branch directly) /
356
+ edit the proposed branch name / abort. Loop back to Step 3.5's confirm prompt
357
+ if they want to edit.
358
+ - If `anvil/<slug>/<repo>/` already exists but isn't a worktree for the chosen
359
+ branch, ask before doing anything destructive.
360
+ - In additive mode, repos already mapped to `anvil/<slug>/<repo>/` are silently
361
+ skipped — they're not a conflict, they're the current state.
362
+
363
+ Report success or failure per repo with the chosen branch and base:
364
+ ```
365
+ ✓ backend-api → anvil/<slug>/backend-api
366
+ branch: feature/<TICKET>-<YYMMDD>-<topic> (from origin/main)
367
+ ✓ admin-web → anvil/<slug>/admin-web
368
+ branch: feat/<TICKET> (from origin/main)
369
+ ✓ worker-service → anvil/<slug>/worker-service
370
+ branch: <slug> (from origin/main; pattern detection fell back to slug)
371
+ ```
372
+
373
+ ### Partial failure handling
374
+
375
+ If `git worktree add` fails for some repos (auth, disk, conflict, etc.):
376
+
377
+ 1. **Do not silently continue as if all succeeded.** List succeeded vs failed:
378
+ ```
379
+ ✓ a created
380
+ ✗ d failed: <git error message>
381
+ ✓ e created
382
+ ```
383
+ 2. **Only write CLAUDE.md / update the in-scope list with the repos that actually
384
+ succeeded.** Failed repos must not appear there.
385
+ 3. Tell the user how to retry: `agentforge-feature-start d` (additive mode will add
386
+ only d if a and e are already in place).
387
+ 4. Release the lock before returning.
388
+
389
+ ### Step 5 — Write / update the feature CLAUDE.md
390
+
391
+ **New mode** — create `anvil/<slug>/CLAUDE.md`:
392
+
393
+ ```markdown
394
+ # Feature: <original description>
395
+
396
+ - Slug: `<slug>`
397
+ - Started: <YYYY-MM-DD>
398
+ - Repos in scope:
399
+ - `<repo1>` → `anvil/<slug>/<repo1>/` · branch `<branch1>`
400
+ - `<repo2>` → `anvil/<slug>/<repo2>/` · branch `<branch2>`
401
+
402
+ ## Context
403
+
404
+ <5–10 line summary of anything explored / learned / decided in the current
405
+ session BEFORE the user pivoted to "let's start a feature". Examples of what to
406
+ capture:
407
+ - What was the user originally asking about (the exploration prompt)?
408
+ - Which files / functions / endpoints did we look at?
409
+ - What was the discovery that triggered making this a feature
410
+ (e.g. "found that retry count is hardcoded to 5 in foo.ts:42 — that's the bug")?
411
+ - Any hypotheses / decisions already made (e.g. "decision: bump retry to 10
412
+ with backoff, do NOT touch the failover path")?
413
+
414
+ If there was no meaningful exploration before this skill ran (user said
415
+ "start a feature" cold), write `(none — feature started cold)` and skip the
416
+ list.>
417
+
418
+ Work on this feature happens here (`anvil/<slug>/`). Run `claude` from this directory
419
+ to work across all the worktrees above in a single session.
420
+
421
+ > Note: branch names per repo follow each repo's own naming convention (detected at
422
+ > feature-start time). They may differ from the slug. Downstream skills
423
+ > (`pr-create`, `feature-retro`) read the actual branch from each worktree's HEAD,
424
+ > so this metadata is informational — git is the source of truth.
425
+ ```
426
+
427
+ The `## Context` section is what carries forward what you (the parent session)
428
+ already know. The dispatched background session auto-loads this CLAUDE.md, so
429
+ the new session starts with the context instead of asking the user to re-explain.
430
+
431
+ **Be conservative in what you capture.** Five to ten lines. Don't paste full
432
+ file contents or transcripts — link to file paths with line numbers and let
433
+ the next session read for itself.
434
+
435
+ **Additive mode** — read the existing `CLAUDE.md`, then **update** it without losing
436
+ the original description or other user edits:
437
+ - Append newly added repos to the `Repos in scope:` list with their branch names
438
+ (preserve order: existing first, then new). Do not touch the branch line of
439
+ existing entries.
440
+ - Add a `- Expanded: <YYYY-MM-DD>` line under the metadata block if not already there
441
+ for today.
442
+ - Do not rewrite the description or any free-text the user has added.
443
+ - If new exploration happened in this session before deciding to expand the
444
+ feature, **append** to the existing `## Context` section under a sub-heading
445
+ like `### Update <YYYY-MM-DD>` with a 2–5 line note about what was learned
446
+ and why this repo is being added. Never rewrite earlier Context entries.
447
+
448
+ ### Step 6 — Hand off (auto-dispatch when possible)
449
+
450
+ After worktrees are created, get the user into the new `anvil/<slug>/` directory
451
+ with as little friction as possible. The right hand-off depends on which CLI the
452
+ user is running this skill in — detect and branch.
453
+
454
+ **New mode only.** In additive mode the user already has a session for the feature;
455
+ skip the dispatch and just report what was added.
456
+
457
+ #### Detect the CLI
458
+
459
+ Use a single, durable signal: is `claude` on PATH?
460
+
461
+ ```bash
462
+ if command -v claude >/dev/null 2>&1; then echo claude; else echo other; fi
463
+ ```
464
+
465
+ Treat the result as a proxy for "the user is running Claude Code". Cursor and Codex
466
+ CLI users typically don't have `claude` on PATH; if they do (mixed install), the
467
+ dispatch below still works and just sits idle as a parallel option — harmless.
468
+
469
+ #### Branch A — `claude` is available (Claude Code users)
470
+
471
+ Dispatch a background Claude Code session whose working directory is the new
472
+ worktree. The user, still in the parent session, can press `←` on an empty prompt
473
+ to open Agent View and jump straight into it.
474
+
475
+ ```bash
476
+ ( cd anvil/<slug> && claude --bg --name "<slug>" "ready" )
477
+ ```
478
+
479
+ Notes:
480
+ - `claude --bg` requires a prompt; `"ready"` is an innocuous placeholder so the
481
+ session boots and idles waiting for the user.
482
+ - `--name "<slug>"` makes it easy to identify in Agent View.
483
+ - The subshell `( ... )` keeps the parent session's cwd unchanged.
484
+ - If `claude --bg` exits non-zero (older build without `--bg`, etc.), report the
485
+ error and fall through to Branch B — do not retry.
486
+
487
+ Then report:
488
+
489
+ ```
490
+ ✓ Worktrees ready. Dispatched a background Claude session in anvil/<slug>/.
491
+
492
+ → Press ← (left arrow) on an empty prompt here to open Agent View,
493
+ then pick the session named "<slug>".
494
+
495
+ Fallback if Agent View isn't available:
496
+ cd anvil/<slug>/ && claude
497
+ ```
498
+
499
+ #### Branch B — `claude` is not available (Cursor / Codex CLI / other)
500
+
501
+ Do **not** try to dispatch anything. Just tell the user where to point their tool:
502
+
503
+ ```
504
+ ✓ Worktrees ready. Open your editor / CLI on:
505
+
506
+ anvil/<slug>/
507
+
508
+ In Cursor: File → Open Folder… → anvil/<slug>/
509
+ In Codex CLI: cd anvil/<slug>/ && codex
510
+ In a terminal: cd anvil/<slug>/ && <your-CLI>
511
+ ```
512
+
513
+ Pick the one line that matches the user's setup if you know it from
514
+ `agentforge/config.json`'s `agents:` list; otherwise show all three.
515
+
516
+ #### Additive mode (both branches)
517
+
518
+ Before reporting success, check the parent session's cwd against the feature
519
+ root:
520
+
521
+ ```bash
522
+ case "$PWD" in
523
+ */anvil/<slug>) cwd_state=at-root ;;
524
+ */anvil/<slug>/*/*) cwd_state=deeper ;;
525
+ */anvil/<slug>/*) cwd_state=in-subrepo ;;
526
+ *) cwd_state=outside ;;
527
+ esac
528
+ ```
529
+
530
+ If `cwd_state` is `at-root`, the newly added worktrees appear as siblings and
531
+ are visible to the current session — nothing extra to do:
532
+
533
+ ```
534
+ ✓ Added <N> repo(s) to feature `<slug>`:
535
+ - <repo-1>
536
+ - <repo-2>
537
+
538
+ The feature now spans: <repo-A>, <repo-B>, <repo-1>, <repo-2>.
539
+ Continue in your existing anvil/<slug>/ session.
540
+ ```
541
+
542
+ If `cwd_state` is `in-subrepo` (the session is inside one specific repo's
543
+ worktree like `anvil/<slug>/<old-repo>/`), the newly added worktrees are
544
+ siblings of cwd, not visible from this session's working directory. In **Branch
545
+ A** (Claude available), dispatch a fresh background session at the feature root
546
+ so the user can switch to it via Agent View:
547
+
548
+ ```bash
549
+ ( cd anvil/<slug> && claude --bg --name "<slug>" "expanded — read CLAUDE.md and the Context section, then wait for instructions" )
550
+ ```
551
+
552
+ Then report:
553
+
554
+ ```
555
+ ✓ Added <N> repo(s) to feature `<slug>`:
556
+ - <repo-1>
557
+ - <repo-2>
558
+
559
+ You're inside anvil/<slug>/<old-repo>/, but the new worktrees were added as
560
+ siblings under anvil/<slug>/. To work with all of them in one session:
561
+
562
+ → Press ← (left arrow) on an empty prompt here, then pick the session
563
+ named "<slug>" in Agent View (just dispatched at the feature root).
564
+
565
+ Fallback:
566
+ cd anvil/<slug>/ && claude
567
+ ```
568
+
569
+ In **Branch B** (no `claude` on PATH), skip the dispatch and instead instruct:
570
+
571
+ ```
572
+ ✓ Added <N> repo(s) to feature `<slug>`:
573
+ - <repo-1>
574
+ - <repo-2>
575
+
576
+ You're inside anvil/<slug>/<old-repo>/. The new worktrees were added as
577
+ siblings — close this session and reopen at anvil/<slug>/ to see all
578
+ worktrees together:
579
+
580
+ cd anvil/<slug>/ && <your-CLI>
581
+ ```
582
+
583
+ If `cwd_state` is `outside` (unusual — user ran the skill from somewhere not in
584
+ the feature), just report success and let them navigate themselves.
585
+
586
+ Do **not** start a foreground `claude`/`cursor`/`codex` from inside this skill —
587
+ that would block the current session. Background dispatch is only safe for
588
+ Branch A (`claude --bg`), and only in new mode.
589
+
590
+ ## Rules
591
+
592
+ - Always run `git worktree add` from inside the canonical repo (`repos/<name>/`),
593
+ never from `anvil/`.
594
+ - **Always pass an explicit base** to `git worktree add` (e.g. `origin/main`). Do not
595
+ rely on the current HEAD of `repos/<repo>` — the user may be mid-work on another
596
+ branch there.
597
+ - **Never touch `repos/<repo>`'s working tree.** Uncommitted changes there stay where
598
+ they are. Only the new worktree is created.
599
+ - If the slug feels off, re-confirm with the user before creating any worktree.
600
+ Worktrees are cheap to make but annoying to clean up.
601
+ - Never assume a feature spans every repo. Ask, then act.
602
+ - **Step 0's pre-check is a hint, not a decision.** Always show all repos and let the
603
+ user override.
604
+ - **In additive mode, never touch existing worktrees or branches.** Only add new ones.
605
+ - **In additive mode, never overwrite the feature CLAUDE.md.** Append / update in
606
+ place.
607
+
608
+ ## Activity log
609
+
610
+ After each successful destructive action (worktree created, CLAUDE.md updated),
611
+ append a JSONL line to `<workspace>/agentforge/log.jsonl`:
612
+
613
+ ```bash
614
+ mkdir -p <workspace>/agentforge
615
+ printf '%s\n' "$(jq -nc \
616
+ --arg ts "$(date -u +%FT%TZ)" \
617
+ --arg skill agentforge-feature-start \
618
+ --arg slug '<slug>' \
619
+ --arg action '<created|added|noop>' \
620
+ --arg repos '<repo-list-comma-separated>' \
621
+ --arg branches '<repo1>=<branch1>,<repo2>=<branch2>' \
622
+ '{ts:$ts, skill:$skill, slug:$slug, action:$action, repos:$repos, branches:$branches}')" \
623
+ >> <workspace>/agentforge/log.jsonl
624
+ ```
625
+
626
+ If `jq` is unavailable, append a hand-built JSON line. This log is consumed by
627
+ `agentforge-feature-retro` to enrich the RETRO.md timeline.
628
+
629
+ ## Output language
630
+
631
+ {{OUTPUT_LANGUAGE_INSTRUCTION}}