@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.
- package/LICENSE +21 -0
- package/README.md +275 -0
- package/dist/add-agent.js +145 -0
- package/dist/add-skill.js +185 -0
- package/dist/agent-prompt.js +211 -0
- package/dist/agentforge-config.js +106 -0
- package/dist/agents/claude.js +46 -0
- package/dist/agents/codex.js +67 -0
- package/dist/agents/cursor.js +54 -0
- package/dist/agents/index.js +15 -0
- package/dist/agents/io.js +252 -0
- package/dist/agents/types.js +1 -0
- package/dist/cli.js +374 -0
- package/dist/confirm.js +20 -0
- package/dist/doctor.js +223 -0
- package/dist/enter.js +85 -0
- package/dist/init.js +272 -0
- package/dist/lang-prompt.js +88 -0
- package/dist/list-skills.js +120 -0
- package/dist/logo.js +181 -0
- package/dist/path-prompt.js +148 -0
- package/dist/remove-agent.js +63 -0
- package/dist/remove-skill.js +88 -0
- package/dist/rename.js +222 -0
- package/dist/skill-prompt.js +199 -0
- package/dist/skills-data.js +727 -0
- package/dist/sync-skills.js +59 -0
- package/dist/templates/CLAUDE.md.tpl +141 -0
- package/dist/templates/context-handoff.SKILL.md.tpl +222 -0
- package/dist/templates/cross-repo-impact.SKILL.md.tpl +241 -0
- package/dist/templates/feature-retro.SKILL.md.tpl +312 -0
- package/dist/templates/feature-start.SKILL.md.tpl +631 -0
- package/dist/templates/history.SKILL.md.tpl +165 -0
- package/dist/templates/incident-context.SKILL.md.tpl +260 -0
- package/dist/templates/pr-create.SKILL.md.tpl +403 -0
- package/dist/templates/pr-review-analyze.SKILL.md.tpl +303 -0
- package/dist/templates/pre-deploy-check.SKILL.md.tpl +350 -0
- package/dist/templates/project-router.SKILL.md.tpl +55 -0
- package/dist/templates/release-coordinate.SKILL.md.tpl +209 -0
- 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}}
|