@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,165 @@
1
+ ---
2
+ name: agentforge-history
3
+ description: Queries past features in the workspace — searches every artifacts/<YYYYMMDD>/<slug>/ for retrospectives, decisions, PR/commit pointers, and Claude session transcripts, plus in-progress features under anvil/. Triggers when the user asks about earlier work, like "how did we handle X last time?", "which feature added Y?", "find that PR about Z", "show me past features touching a specific repo", "what did we decide about A previously?". Read-only.
4
+ ---
5
+
6
+ # agentforge-history
7
+
8
+ When the user has a question about something done before — a past decision, a
9
+ shipped PR, a feature that touched a particular repo — this skill scans the
10
+ workspace's accumulated history and answers with grounded references (file paths,
11
+ commit hashes, PR URLs) instead of guesses.
12
+
13
+ **Read-only.** Reports only; never modifies anything.
14
+
15
+ ## When to apply
16
+
17
+ Trigger phrases:
18
+ - "How did we handle `<X>` last time?"
19
+ - "Which feature added `<Y>`?"
20
+ - "Find that PR about `<Z>`."
21
+ - "Show me past features that touched `<repo>`."
22
+ - "What did we decide about `<topic>`?"
23
+ - "Pull up retros from the last three months."
24
+ - "Anything similar to this we've done before?"
25
+
26
+ If the question is clearly about live code or current work, route to `project-router`
27
+ or `feature-start` instead. Use this skill specifically for **looking back**.
28
+
29
+ ## Data sources
30
+
31
+ Finished features live under `artifacts/<YYYYMMDD>/<slug>/` (the close date is the
32
+ first directory). All of these files may be present per feature:
33
+
34
+ | Source | What it gives you |
35
+ |---|---|
36
+ | `artifacts/<YYYYMMDD>/<slug>/CLAUDE.md` | Original feature description, repos in scope, start date |
37
+ | `artifacts/<YYYYMMDD>/<slug>/RETRO.md` | What was asked, decisions, what was built, lessons |
38
+ | `artifacts/<YYYYMMDD>/<slug>/refs.json` | Per-repo `{branch, head, merged_into, pr}` pointers |
39
+ | `artifacts/<YYYYMMDD>/<slug>/plans/*.md` | Plan files captured during the work |
40
+ | `artifacts/<YYYYMMDD>/<slug>/sessions/*.jsonl` | Full Claude Code transcripts (large; query last) |
41
+ | `agentforge/log.jsonl` | Append-only activity log (start / archive / PR events) |
42
+
43
+ In-progress features (not yet archived) live under `anvil/<slug>/` with their
44
+ `CLAUDE.md` describing scope; the rest of the artifacts only exist after
45
+ `feature-retro` runs. Don't confuse the two: `anvil/` = active, `artifacts/` = done.
46
+
47
+ A feature folder may not have all of the above files — older features may
48
+ pre-date some fields. Handle missing files gracefully.
49
+
50
+ ## How to do it
51
+
52
+ ### Step 1 — Enumerate features
53
+
54
+ Walk both archive and in-progress:
55
+
56
+ ```bash
57
+ ls -1 artifacts/ 2>/dev/null # YYYYMMDD directories of close dates
58
+ ls -1 anvil/ 2>/dev/null # in-progress features (no archive yet)
59
+ ```
60
+
61
+ For archive, recurse one more level: `artifacts/<YYYYMMDD>/<slug>/`.
62
+
63
+ For each feature directory, capture:
64
+ - the slug (last directory component)
65
+ - the **close date** for archived features (the `YYYYMMDD` parent directory)
66
+ - the **start date** parsed from the slug's `YYMMDD-` prefix
67
+ - the original description (first heading in `CLAUDE.md`)
68
+ - the in-scope repos (from `CLAUDE.md` or `refs.json`)
69
+ - whether the feature is closed (lives in `artifacts/`) or in-progress (lives in
70
+ `anvil/`)
71
+
72
+ Sorting:
73
+ - Archive features: by close date (parent directory), newest first.
74
+ - In-progress features: by slug `YYMMDD-` prefix, newest first.
75
+
76
+ Skip directories that aren't features (no `CLAUDE.md`).
77
+
78
+ ### Step 2 — Narrow by the user's question
79
+
80
+ Extract intent + keywords from the question. Then filter:
81
+
82
+ - **By keyword** — grep `CLAUDE.md`, `RETRO.md`, plan files for the terms. Skip
83
+ `sessions/` directories on this pass (they're large; query them only after
84
+ the answer needs more depth).
85
+ - **By repo** — match against the `Repos in scope:` list / `refs.json` repos.
86
+ - **By date window** — when the user says "last 3 months", "this quarter",
87
+ "since the deploy migration", filter on the `YYYYMMDD` archive parent dir
88
+ (close date) or the `YYMMDD` slug prefix (start date), depending on which
89
+ the user meant.
90
+ - **By PR / commit** — if the user mentions a PR number or partial commit hash,
91
+ grep every `refs.json` for it.
92
+
93
+ Rank candidates by signal strength (keyword hit count, recency, repo match).
94
+
95
+ ### Step 3 — Compose the answer
96
+
97
+ Lead with the **most relevant feature**. For each match, include just enough to
98
+ let the user open the right file next:
99
+
100
+ ```markdown
101
+ ## 260418-feat-retry-logic (closed 2026-05-09, ~3 weeks ago)
102
+ *Retry logic refactor across services* · scope: backend-api, admin-web
103
+
104
+ **Decisions** (from RETRO.md):
105
+ - Retry policy enforced at the API layer, not the client (so all callers behave consistently).
106
+ - Kept the old endpoint, added v2 alongside for a deprecation window.
107
+
108
+ **Built** (from refs.json):
109
+ - backend-api: branch `260418-feat-retry-logic`, head `abc1234`, merged into `main` — PR acme/backend-api#412
110
+ - admin-web: branch `260418-feat-retry-logic`, head `def5678`, merged into `main` — PR acme/admin-web#88
111
+
112
+ **More**: open `artifacts/20260509/260418-feat-retry-logic/RETRO.md` for the full
113
+ retro; session transcripts are under `sessions/`.
114
+ ```
115
+
116
+ If multiple features match strongly, list the top 3–5 in this format. Don't dump
117
+ every feature — narrow to ones that actually answer the question.
118
+
119
+ If there's one clear match and the user asked something specific (e.g. "what was
120
+ the rationale?"), **answer the specific question** by quoting the relevant lines
121
+ from RETRO.md, then point to the file for the rest. Don't paraphrase invisibly —
122
+ quote the source so the user can verify.
123
+
124
+ ### Step 4 — Drill into sessions (only if needed)
125
+
126
+ `artifacts/<YYYYMMDD>/<slug>/sessions/*.jsonl` files are large (each line is a
127
+ message). Only open
128
+ them when:
129
+ - The RETRO doesn't have the answer the user is looking for.
130
+ - The user explicitly asks for the original conversation ("what exactly did I ask
131
+ back then?").
132
+
133
+ When you do, grep the jsonl for the keyword first; only read the surrounding
134
+ messages for context.
135
+
136
+ ## Cross-feature questions
137
+
138
+ For "anything similar we've done?" or "show me patterns":
139
+
140
+ 1. Pull the user's current intent or current diff (if they're in a worktree).
141
+ 2. Search across **all** RETROs for similar problem statements / decisions.
142
+ 3. Group the matches and surface the recurring themes (e.g. "we've tackled cache
143
+ invalidation 3 times — each retro chose a slightly different invalidation
144
+ scope; here's the contrast").
145
+
146
+ Be explicit when you're synthesizing across multiple features vs. quoting one.
147
+
148
+ ## Rules
149
+
150
+ - **Always cite the source file.** Every claim should be traceable to a path the
151
+ user can open: `artifacts/<YYYYMMDD>/<slug>/RETRO.md:L42` or `refs.json` etc.
152
+ - **Don't fabricate decisions or PR numbers.** If the source data doesn't contain
153
+ it, say so.
154
+ - **Respect privacy.** Old session transcripts may contain incidentally pasted
155
+ alerts with customer identifiers. Apply the same redaction conventions as the
156
+ `agentforge-incident-context` skill if you find any (Bearer tokens, JWTs,
157
+ emails, etc.) before echoing them.
158
+ - **Sessions are heavy.** Never open all of them in bulk. Always go RETRO/plans
159
+ first, then drop into sessions only for specific lookups.
160
+ - **Read-only.** This skill never edits a RETRO, plan, refs.json, or log entry.
161
+ If the user wants to correct an old record, they edit the file themselves.
162
+
163
+ ## Output language
164
+
165
+ {{OUTPUT_LANGUAGE_INSTRUCTION}}
@@ -0,0 +1,260 @@
1
+ ---
2
+ name: agentforge-incident-context
3
+ description: First-responder context for a production incident in a multi-repo workspace. Given a clue from an alert — error message, stack trace line, HTTP path, metric name, exception class, or timestamp — searches every repo in the workspace for matching code, identifies recent merged PRs that touched it, names the last committers, traces the call path, and returns a single briefing optimized for "I just got paged, what changed?". Triggers on "incident context", "got an alert about X", "production error", "what changed recently around X", "page-out for …". Read-only.
4
+ ---
5
+
6
+ # incident-context
7
+
8
+ Optimized for the moment an alert fires. Instead of grepping six repos one by one,
9
+ this skill takes the alert's clue, walks the whole workspace, and returns a single
10
+ briefing: where the keyword lives, what changed there recently, who touched it last,
11
+ and what to look at next.
12
+
13
+ **Read-only.** Reports only; never modifies code.
14
+
15
+ ## When to apply
16
+
17
+ Trigger phrases:
18
+ - "Incident context for `<keyword>`."
19
+ - "Got an alert about `<X>` — what could be causing it?"
20
+ - "Production error: `<stack trace line>`."
21
+ - "What changed recently around `<symbol or path>`?"
22
+ - "Page-out — please pull context."
23
+
24
+ If the user's clue is overly generic (`null`, `error`, `failed`), ask for a more
25
+ specific signal (the surrounding class name, a unique substring of the error message,
26
+ the HTTP path) before searching — false positives at 4am help nobody.
27
+
28
+ ## Redact secrets from the clue (do this FIRST, before any analysis)
29
+
30
+ Alert payloads pasted by an on-call engineer commonly contain tokens, customer
31
+ identifiers, or credentials. Before you echo, log, or quote any part of the clue
32
+ back to the user — and before any of it lands in your output — scrub it.
33
+
34
+ **Pattern checks to apply** (regex-level, conservative):
35
+
36
+ | Pattern | Example | Action |
37
+ |---|---|---|
38
+ | `Bearer\s+[A-Za-z0-9._\-]{20,}` | `Bearer eyJhbGc...` | replace with `Bearer <REDACTED>` |
39
+ | `Basic\s+[A-Za-z0-9+/=]{16,}` | `Basic YWRtaW46...` | `Basic <REDACTED>` |
40
+ | AWS access key `AKIA[0-9A-Z]{16}` | `AKIAIOSFODNN7EXAMPLE` | `<AWS_KEY>` |
41
+ | AWS secret `[A-Za-z0-9/+=]{40}` next to a key context | `aws_secret=...` | `<AWS_SECRET>` |
42
+ | GitHub PAT `gh[pousr]_[A-Za-z0-9]{36,}` | `ghp_xxxxx` | `<GH_TOKEN>` |
43
+ | Slack token `xox[abprs]-[A-Za-z0-9-]+` | `xoxb-...` | `<SLACK_TOKEN>` |
44
+ | JWT `eyJ[A-Za-z0-9_\-]+\.eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+` | full JWTs | `<JWT>` |
45
+ | Long hex secret `\b[a-f0-9]{32,64}\b` near `key=`/`secret=`/`token=` | hashes/keys | `<SECRET>` |
46
+ | Email `[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}` | customer email | `<email>` (only inside log/error text, not from the user's own message) |
47
+ | Phone `\+?\d[\d \-]{7,}` near `phone=` / `tel=` | customer phone | `<phone>` |
48
+ | Credit card-like `\b(?:\d[ \-]?){13,19}\b` | numeric runs | `<CC>` |
49
+
50
+ If any pattern matched, **tell the user once**:
51
+
52
+ ```
53
+ ⚠ Redacted from the clue: 2 tokens, 1 JWT, 1 customer ID
54
+ ```
55
+
56
+ Continue analysis with the redacted version. Never include the original values in any
57
+ output, file, or subsequent tool call.
58
+
59
+ ## What the user provides
60
+
61
+ Accept one or more of (the clue can come from any stack — backend, frontend, mobile,
62
+ worker, CLI):
63
+ - **Error message / exception text**, e.g.
64
+ - JS/TS: `TypeError: Cannot read properties of undefined (reading 'foo')`
65
+ - Java/Kotlin: `NullPointerException at Foo.process`
66
+ - Python: `KeyError: 'foo'` / `AttributeError: 'NoneType' object has no attribute 'bar'`
67
+ - Go: `runtime error: invalid memory address or nil pointer dereference`
68
+ - Swift: `Fatal error: Unexpectedly found nil while unwrapping an Optional value`
69
+ - **Stack trace line**, e.g.
70
+ - JS: `at fetchData (src/api/things.ts:42:13)`
71
+ - Kotlin: `at com.example.app.JobRunner.process(JobRunner.kt:88)`
72
+ - Python: `File "src/foo.py", line 142, in process`
73
+ - Go: `src/foo/handler.go:88 +0x4c`
74
+ - **HTTP request path** (e.g. `POST /v1/things/<id>`, `GET /api/users/:id`)
75
+ - **Symbol name** — function, class, method, component, hook
76
+ - **Metric or log key** (e.g. `things.process.failure.count`, `feature.search-ranking.enabled`)
77
+ - **Time window** (e.g. "starting 30 min ago", "since yesterday's deploy") — scopes
78
+ the "recent PRs" search.
79
+
80
+ If a time window is missing, default to **last 7 days** for PR scanning, but tell the
81
+ user so they can narrow it.
82
+
83
+ ## Locate the workspace
84
+
85
+ Walk up from cwd to find a directory containing `repos/`. The search set is every
86
+ `repos/<name>/`. If no agentforge workspace is detected, fall back to cwd as the
87
+ single repo and say so.
88
+
89
+ ## Normalize the clue
90
+
91
+ Extract searchable tokens from whatever the user pasted:
92
+
93
+ - **Stack trace** → pull the fully-qualified type + method + file:line. The file:line
94
+ is the highest-signal anchor; search for the file basename first.
95
+ - **Error message** → extract the unique substring (skip framework boilerplate like
96
+ "Exception in thread"). A class name + a noun phrase is usually enough.
97
+ - **HTTP path** → keep both the literal path and the path with `:id` style
98
+ placeholders. Search both forms.
99
+ - **Metric / log key** → search the literal key as a string.
100
+
101
+ If multiple anchors are available, search for all of them and intersect results.
102
+
103
+ ## Search every repo
104
+
105
+ For each `repos/<name>/`:
106
+
107
+ ```bash
108
+ # code search for the most specific anchor first
109
+ git -C repos/<name> grep -nE "<anchor-regex>" -- ':!*.lock' ':!node_modules' ':!dist' ':!build'
110
+ ```
111
+
112
+ Track:
113
+ - File paths and line numbers that match.
114
+ - The function / method enclosing each match (read a few lines of context).
115
+ - Whether the hit is in production code or in a test file (`*test*`, `__tests__`,
116
+ `*_test.go`, `*Test.kt`, etc.) — test hits are usually noise during an incident.
117
+
118
+ If a repo has zero hits, mention it briefly ("`mobile-app`: no matches"). Don't hide
119
+ it — the responder needs to know what was searched.
120
+
121
+ ## Pull recent PRs per repo
122
+
123
+ For each repo that has matches, find PRs merged in the time window that touched any
124
+ of the matching files:
125
+
126
+ ```bash
127
+ # PRs merged in window (default: 7d)
128
+ gh -R <owner>/<repo> pr list --state merged --search "merged:>=$(date -u -v-7d '+%Y-%m-%d')" --json number,title,url,mergedAt,author,files --limit 50
129
+ ```
130
+
131
+ Filter the result to PRs whose `files[]` list intersects the matching file paths.
132
+
133
+ If `gh` isn't available or the repo has no remote, fall back to git:
134
+
135
+ ```bash
136
+ git -C repos/<name> log --merges --since="7 days ago" --pretty='%h %ci %s' -- <matched-files...>
137
+ ```
138
+
139
+ For each PR / commit, capture:
140
+ - PR number + title + URL (or commit hash + subject)
141
+ - Merged-at timestamp
142
+ - Author handle
143
+ - Which of the matching files it changed (just the count)
144
+
145
+ **Rank by suspicion**:
146
+ 1. Merged inside the user's time window (if given) — strongest signal.
147
+ 2. Merged most recently.
148
+ 3. Touched the highest-signal file (the one matching the stack trace line).
149
+
150
+ ## Identify the last committers
151
+
152
+ For each matching file, `git -C <repo> log -1 --format='%an <%ae> %ai' -- <file>` to get
153
+ the most recent author. Optionally also list the top 2–3 historical committers
154
+ (`git -C <repo> shortlog -sne -- <file> | head -3`) — they're the people who
155
+ understand the code best.
156
+
157
+ ## Trace the call path (light)
158
+
159
+ For the strongest single match (the most specific anchor — usually the stack trace
160
+ line), do a one-hop call site search using the language-appropriate idiom:
161
+
162
+ | Language | Caller pattern |
163
+ |---|---|
164
+ | TS / JS | `\.X\(` , `\bX\(` |
165
+ | Kotlin / Java | `\.X\(` |
166
+ | Python | `\bX\(` |
167
+ | Go | `\.X\(` |
168
+ | Rust | `::X\(` , `\.X\(` |
169
+
170
+ Show up to 10 call sites grouped by repo. This is enough to know "is this called from
171
+ a sync HTTP handler, a Kafka listener, or a cron?" — which often determines blast
172
+ radius.
173
+
174
+ ## Output format
175
+
176
+ Lead with the **most actionable** sections (suspects, recent PRs) and push general
177
+ context lower. Make it scannable in 30 seconds.
178
+
179
+ ```markdown
180
+ # 🚨 Incident context: <keyword>
181
+
182
+ > Searched: 4 repos (backend-api, mobile-app, admin-web, worker-service)
183
+ > Time window: last 7 days (override by specifying a window)
184
+ > Anchors: `Foo.process` · `things.process.failure.count`
185
+
186
+ ---
187
+
188
+ ## 🎯 Primary suspects
189
+
190
+ ### `backend-api` · `Foo.kt:142` — `process()`
191
+ - 📞 Reached via:
192
+ - `FooController.handleRequest` (sync HTTP `POST /v1/things/:id`)
193
+ - `SomeConsumer.onMessage` (Kafka, `things.event.requested`) ⚡ async — no request transaction
194
+ - 🕒 Last touched: 2 hours ago by `alice <s@example.com>`
195
+ - 📜 Recent PRs touching this file:
196
+ - **#412** "Refactor error handling" — merged 2h ago by @alice
197
+ [link]
198
+ - **#398** "Add `reason` column" — merged 3d ago by @bob [link]
199
+
200
+ ---
201
+
202
+ ## 📜 Recent merged PRs (in window, ranked)
203
+
204
+ | Repo | PR | When | Author | Matched files | Title |
205
+ |---|---|---|---|---|---|
206
+ | backend-api | #412 | 2h ago | @alice | 3 | Refactor error handling |
207
+ | backend-api | #398 | 3d ago | @bob | 1 | Add `reason` column |
208
+ | worker-service | #71 | 1d ago | @carol | 1 | Bump webhook version |
209
+
210
+ ---
211
+
212
+ ## 🔍 Other matches (older / lower signal)
213
+
214
+ - `admin-web` · `src/api/things.ts:18` — display layer; last touched 6 weeks ago.
215
+ - `mobile-app`: no matches.
216
+
217
+ ---
218
+
219
+ ## 👥 Who knows this code
220
+
221
+ - `Foo.kt` — alice (last touch), colleague (most commits), legacy-dev
222
+ (original author)
223
+ - `SomeConsumer.kt` — colleague
224
+
225
+ ---
226
+
227
+ ## 📋 Next steps
228
+
229
+ 1. Read **PR #412** diff — it's the most recent change to the suspect file.
230
+ 2. Check logs for the time window — search by `request_id` and the exception class.
231
+ 3. Confirm whether the failures are on the sync path or the Kafka consumer (call
232
+ path shows both).
233
+ 4. If async, confirm transaction / MDC propagation in `SomeConsumer.onMessage`.
234
+ 5. If you need a wider search, re-run with a longer time window or a broader anchor.
235
+ ```
236
+
237
+ Always include "Next steps" — a context dump without a path forward isn't useful at
238
+ 4am. Limit it to 3–5 concrete actions.
239
+
240
+ ## Rules
241
+
242
+ - **Workspace-bounded**: only search `repos/*` (and explicitly included worktrees).
243
+ Don't escape to unrelated directories.
244
+ - **Don't claim a root cause.** Report what was found and what is most suspicious;
245
+ let the user decide.
246
+ - **Distinguish sync vs async entry points.** When a Kafka listener / scheduled job /
247
+ webhook handler is in the call path, flag it — incidents often hide there.
248
+ - **Distinguish production vs test hits.** Test hits go to the "other matches"
249
+ section, not the suspects list.
250
+ - **Acknowledge silence.** A repo with no hits is information — list it.
251
+ - **No data exfiltration.** If a user pastes a stack trace containing customer
252
+ identifiers (emails, account IDs), do not echo those identifiers in your response —
253
+ use placeholders like `<id>`. Redact tokens / passwords if they appear.
254
+ - **No edits, ever.** Reporting only.
255
+ - **Time-boxed.** The user is under pressure. Aim to deliver the first useful version
256
+ of the briefing fast; offer to drill deeper afterwards.
257
+
258
+ ## Output language
259
+
260
+ {{OUTPUT_LANGUAGE_INSTRUCTION}}