@jamie-tam/forge 6.1.0 → 6.2.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/README.md +33 -29
- package/agents/dreamer.md +10 -6
- package/commands/discover.md +2 -0
- package/commands/dream.md +71 -0
- package/commands/feature.md +7 -2
- package/commands/wrap.md +130 -0
- package/dist/init.js +1 -1
- package/hooks/config/gate-requirements.json +1 -1
- package/hooks/scripts/gate-enforcer.sh +51 -6
- package/hooks/scripts/pre-compact.sh +120 -52
- package/hooks/scripts/session-start.sh +42 -3
- package/hooks/scripts/telemetry.sh +32 -2
- package/package.json +1 -1
- package/rules/common/forge-system.md +31 -11
- package/rules/common/quality-gates.md +2 -0
- package/skills/deliver-deploy/SKILL.md +9 -0
- package/skills/harden/SKILL.md +16 -2
- package/skills/iterate-prototype/SKILL.md +22 -0
- package/skills/support-dream/SKILL.md +8 -7
- package/templates/aiwiki/CLAUDE.md.template +48 -22
- package/templates/aiwiki/schemas/session.md +133 -49
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ The v6 schema (`templates/manifests/v6/SCHEMA.md`) adds `phase_plan:` at the top
|
|
|
28
28
|
## Key Features
|
|
29
29
|
|
|
30
30
|
- **31 skills** spanning the prototype-driven pipeline plus production-grade quality gates
|
|
31
|
-
- **
|
|
31
|
+
- **15 commands** for discovery, setup, workflows, knowledge capture, evolution, and validation
|
|
32
32
|
- **17 specialized agents** with explicit phase-context (prototype-builder for Phase 3-4, builder for Phase 6, plus architects, reviewers, hunters, dreamers)
|
|
33
33
|
- **8 common rules** auto-loaded every session (one — `testing.md` — is paths-conditional, loading only on test files and source code) + **8 common references** for skill authoring, agent coordination, and workflow protocol
|
|
34
34
|
- **Work manifests** with `phase_plan` (preflight intent), `phases` (gate state), `slice_graph` (build decomposition), and `artifacts` (phase outputs + lock signals)
|
|
@@ -47,7 +47,7 @@ npx @jamie-tam/forge init
|
|
|
47
47
|
This installs everything into your project's `.claude/` directory:
|
|
48
48
|
- **Rules** — 8 common rules auto-loaded every session (one is paths-conditional) + language-specific rules layered per detected stack
|
|
49
49
|
- **Skills** — 31 atomic skills covering the prototype-driven pipeline + production gates
|
|
50
|
-
- **Commands** —
|
|
50
|
+
- **Commands** — 15 slash commands for discovery, setup, workflows, knowledge capture, evolution, and validation
|
|
51
51
|
- **Agents** — 17 specialized subagents with MCP server access (context7, playwright)
|
|
52
52
|
- **Hooks** — gate-enforcer, wiki-lint, telemetry, state preservation, session checkpoints
|
|
53
53
|
- **CLAUDE.md** — project configuration template
|
|
@@ -157,33 +157,35 @@ Commands (workflows) Skills (prefix-grouped) Rules (auto-l
|
|
|
157
157
|
/refactor build-scaffold common/quality-gates
|
|
158
158
|
/hotfix build-tdd [Phase 6] common/git-workflow
|
|
159
159
|
/note (capture) build-pr-workflow common/testing (paths-conditional)
|
|
160
|
-
/
|
|
161
|
-
/
|
|
162
|
-
/
|
|
163
|
-
/
|
|
164
|
-
/
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
160
|
+
/dream (capture) quality-code-review
|
|
161
|
+
/wrap (capture) quality-test-plan
|
|
162
|
+
/parallel (parallel) quality-test-execution References (load on demand)
|
|
163
|
+
/status quality-security-audit ----------------------------
|
|
164
|
+
/resume quality-uiux common/
|
|
165
|
+
/forge-evolve deliver-deploy [Phase 7] agent-coordination
|
|
166
|
+
/validate deliver-db-migration io-protocol
|
|
167
|
+
deliver-onboarding skill-authoring
|
|
168
|
+
Work Manifests (v6) discover-requirements skill-compliance
|
|
169
|
+
------------------- discover-codebase-analysis phases (canonical vocab)
|
|
170
|
+
.forge/work/ plan-brainstorm coding-standards
|
|
171
|
+
{type}/ plan-architecture quality-gates
|
|
172
|
+
{name}/ plan-design-system feature-tracking
|
|
173
|
+
manifest.yaml plan-task-decompose typescript/ python/ react/
|
|
174
|
+
schema_version: "6" support-system-guide [extensible]
|
|
175
|
+
phase_plan: {…} support-debug
|
|
176
|
+
phases: {…} support-gotcha Protocols (read on demand)
|
|
177
|
+
slice_graph: {…} support-wiki-lint --------------------------
|
|
178
|
+
artifacts: {…} support-wiki-bootstrap protocols/codex.md
|
|
179
|
+
support-dream protocols/graphify.md
|
|
180
|
+
aiwiki/ (knowledge layer) support-parallel
|
|
181
|
+
------------------------- support-runtime-reachability Hooks
|
|
182
|
+
decisions/ support-skill-validator ------
|
|
183
|
+
gotchas/ gate-enforcer
|
|
184
|
+
conventions/ wiki-lint
|
|
185
|
+
architecture/ session-start / pre-compact
|
|
186
|
+
sessions/ (per-session) telemetry
|
|
187
|
+
raw/ (free-form notes)
|
|
188
|
+
oracles/ (prototype contracts)
|
|
187
189
|
proposed/ (dream queue)
|
|
188
190
|
schemas/
|
|
189
191
|
CLAUDE.md (usage rules)
|
|
@@ -203,6 +205,8 @@ aiwiki/ (knowledge layer) support-dream protocols/gra
|
|
|
203
205
|
| `/refactor` | Analyze, plan approach, restructure with tests, PR | Code needs cleanup without new functionality |
|
|
204
206
|
| `/hotfix` | Emergency compressed flow -- debug, minimal test, deploy | Production is down, need a fix now |
|
|
205
207
|
| `/note` | Append an ad-hoc research note or brainstorm to `aiwiki/raw/{date}.md` | Phase 1-2 research, half-formed thoughts, anything that doesn't yet fit a typed page |
|
|
208
|
+
| `/dream` | Manually trigger aiwiki consolidation (merge duplicates, promote raw → typed, prune stale) | After a refactor, branch merge, or whenever `aiwiki/` feels noisy. Auto-fires at phase-close + PreCompact too. |
|
|
209
|
+
| `/wrap` | Capture & finalize the current Claude session — fills `aiwiki/sessions/{date}-{id}.md` with Files touched / Decisions / Gotchas / Open questions / Next steps | At the natural end of a working session, before a long break, or before switching focus mid-day. Next session-start hook reads it. |
|
|
206
210
|
| `/parallel` | Dispatch parallel agents for a punch list of ad-hoc tasks; phase-aware sizing | Multiple independent small tasks to crunch in one pass |
|
|
207
211
|
| `/status` | List in-flight `.forge/work` items and their current phase | Check what's open before starting new work |
|
|
208
212
|
| `/resume` | Continue a paused work item from its current phase | Pick up a `.forge/work` item left mid-flow |
|
package/agents/dreamer.md
CHANGED
|
@@ -61,10 +61,14 @@ Apply operations in this order:
|
|
|
61
61
|
3. **Prune stale** — for each entry whose cited code no longer exists OR whose decision is superseded:
|
|
62
62
|
- Mark for deletion in the manifest's `operations` (`op: prune`)
|
|
63
63
|
- Do NOT write a "tombstone" file; absence in proposed/ means delete on accept
|
|
64
|
-
4. **
|
|
65
|
-
- **
|
|
66
|
-
- If it
|
|
67
|
-
-
|
|
64
|
+
4. **Refine the active session file (PreCompact and phase-close triggers)** — locate `aiwiki/sessions/{date}-{session_id_short}.md`:
|
|
65
|
+
- **The file is expected to be present.** `hooks/scripts/pre-compact.sh` creates it lazily on first PreCompact fire; `/wrap`, `/dream`, and `harden` also create it lazily if absent. By the time you run, one of those has fired during this session — so the file exists.
|
|
66
|
+
- **If it is truly missing** (no in-session writer fired before you, no `aiwiki/sessions/{today}-*.md` matches), this is a non-fatal anomaly: log it in the dream manifest's `lint_warnings` as `session_file_missing: true` and proceed with raw + typed page consolidation only. Do NOT fabricate a session file — let the next writer (pre-compact, /wrap, harden) create it cleanly.
|
|
67
|
+
- **If it exists**: read it. The `## Checkpoints` section is append-only event log written by pre-compact and dream itself. Your refinement work targets:
|
|
68
|
+
- **Trim `## Checkpoints`**: if more than 10 entries, summarize older ones into a single "## Checkpoint summary {date-range}" entry. Preserve any `Status: unconsumed` entries as-is.
|
|
69
|
+
- **Pre-populate index sections** (`## Files touched`, `## Decisions made`, `## Gotchas surfaced`, `## Open questions`, `## Next steps`) from git diff + aiwiki writes during this session. Mark each line with a `<!-- dream-suggested -->` HTML comment so `/wrap` knows what dream proposed vs what the user wrote.
|
|
70
|
+
- **Do NOT set `status: done`** — that's `/wrap`'s responsibility. Leave `status: active`.
|
|
71
|
+
- Write the refined version to `aiwiki/proposed/{dream_id}/sessions/{date}-{session_id_short}.md`.
|
|
68
72
|
|
|
69
73
|
### Phase 4: Prune & index
|
|
70
74
|
|
|
@@ -93,7 +97,7 @@ Apply operations in this order:
|
|
|
93
97
|
- ANY file in `aiwiki/` (input store untouched)
|
|
94
98
|
- ANY file in `.forge/work/` (operational state, not knowledge)
|
|
95
99
|
- Tombstone files for prunes (manifest's `operations` log records the prune; absence in proposed/ means delete on accept)
|
|
96
|
-
- A fresh `aiwiki/sessions/{
|
|
100
|
+
- A fresh `aiwiki/sessions/{date}-{session_id_short}.md` if it doesn't exist — let the next pre-compact / /wrap / harden writer create it cleanly. If it's truly missing when you run, log `session_file_missing: true` in the dream manifest's `lint_warnings` and skip session-file refinement (no failure, no speculation-write)
|
|
97
101
|
- Any file outside `aiwiki/proposed/{dream_id}/`
|
|
98
102
|
|
|
99
103
|
## Provider Mode (for `anthropic-managed` only)
|
|
@@ -110,7 +114,7 @@ If dispatched with `provider: anthropic-managed`:
|
|
|
110
114
|
|
|
111
115
|
| Mistake | Fix |
|
|
112
116
|
|---|---|
|
|
113
|
-
| Recreating `aiwiki/sessions/{
|
|
117
|
+
| Recreating `aiwiki/sessions/{date}-{session_id_short}.md` instead of refining the existing one | The session file is expected to exist (pre-compact / /wrap / harden creates it lazily). If absent when you run, log `session_file_missing: true` in the manifest and skip session refinement — don't fabricate a session file. The next writer will create it cleanly. |
|
|
114
118
|
| Promoting a raw entry that doesn't satisfy the target schema | Validate against schema first; failures go into `lint_warnings`, not into `aiwiki/proposed/{type}/` |
|
|
115
119
|
| Merging unrelated typed pages because they share a keyword | Merge requires shared root cause / topic, not surface-level term overlap |
|
|
116
120
|
| Pruning an entry without checking if the citation still resolves | Re-check the cited file/symbol before marking prune; LINT staleness != prune trigger |
|
package/commands/discover.md
CHANGED
|
@@ -70,6 +70,8 @@ State commands
|
|
|
70
70
|
|
|
71
71
|
Knowledge commands
|
|
72
72
|
/note <text> append a research note / brainstorm to aiwiki/raw/{date}.md
|
|
73
|
+
/dream [scope] consolidate aiwiki — merge duplicates, promote raw → typed, prune stale
|
|
74
|
+
/wrap [focus] capture & finalize current session into aiwiki/sessions/{date}-{id}.md
|
|
73
75
|
|
|
74
76
|
System commands
|
|
75
77
|
/setup detect stack, fill project profile, scaffold .forge/ + aiwiki/
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dream
|
|
3
|
+
description: "Manually trigger aiwiki consolidation. Merges duplicate notes, promotes raw → typed pages, prunes stale entries. Output is written to aiwiki/proposed/{dream_id}/ for review — input store is never modified. Use after a major refactor, a long session, or whenever aiwiki/ feels noisy. Optional argument: scope (default = full aiwiki/; alternatives = aiwiki/raw/, aiwiki/gotchas/, etc.)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /dream — Consolidate aiwiki
|
|
7
|
+
|
|
8
|
+
Manual trigger for `support-dream`. Produces a reviewable consolidation proposal in `aiwiki/proposed/{dream_id}/`; you accept or reject via the web view (`forge wiki ui`) or CLI (`forge wiki review {dream_id}`).
|
|
9
|
+
|
|
10
|
+
This is the user-driven trigger. Dream also fires automatically:
|
|
11
|
+
- **PreCompact** — `hooks/scripts/pre-compact.sh` appends a `**Dream directive (unconsumed)**` block to the active session file's `## Checkpoints` section (`aiwiki/sessions/{date}-{session_id_short}.md`, created lazily). The post-compact agent reads the session file, finds the directive, and invokes `support-dream`.
|
|
12
|
+
- **Phase-close** — `iterate-prototype`, `harden`, `build-pr-workflow`, and `deliver-deploy` dispatch `support-dream` after writing their respective `artifacts.{phase}.locked_at` lock signal.
|
|
13
|
+
|
|
14
|
+
The manual `/dream` invocation is the escape hatch for between-trigger consolidation.
|
|
15
|
+
|
|
16
|
+
## Steps
|
|
17
|
+
|
|
18
|
+
1. **Parse scope** from the user's argument:
|
|
19
|
+
- No argument → scope is the full `aiwiki/` tree.
|
|
20
|
+
- One token (`raw`, `gotchas`, `decisions`, `conventions`, `architecture`, `sessions`) → scope is `aiwiki/{token}/`.
|
|
21
|
+
- Multiple tokens or explicit path → scope is the union of those paths.
|
|
22
|
+
2. **Verify aiwiki exists.** If `aiwiki/` is missing, dispatch `support-wiki-bootstrap` first.
|
|
23
|
+
3. **Check for pending dreams.** If `aiwiki/proposed/{dream_id}/` directories already exist with `review_status: pending` in their manifest, surface them to the user and ask whether to queue a new dream or review the pending ones first. Do not silently overwrite.
|
|
24
|
+
4. **Invoke `support-dream` skill** with the parsed scope and `trigger: manual`. The skill dispatches the `dreamer` subagent and writes the proposed output.
|
|
25
|
+
5. **Report to the user**: new `dream_id`, list of `changed_pages` / `new_pages` / `deleted_pages` counts, lint status, and the path to review:
|
|
26
|
+
```
|
|
27
|
+
Dream complete: 2026-05-18-1742-manual
|
|
28
|
+
Proposals: aiwiki/proposed/2026-05-18-1742-manual/
|
|
29
|
+
Changed: 3 New: 1 Deleted: 0 Lint: passed
|
|
30
|
+
Review: `forge wiki review 2026-05-18-1742-manual` or open `forge wiki ui`
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Example
|
|
34
|
+
|
|
35
|
+
User: `/dream`
|
|
36
|
+
→ Full aiwiki consolidation, dispatched as `trigger: manual`.
|
|
37
|
+
|
|
38
|
+
User: `/dream raw gotchas`
|
|
39
|
+
→ Scope limited to `aiwiki/raw/` + `aiwiki/gotchas/`.
|
|
40
|
+
|
|
41
|
+
User: `/dream after the auth refactor`
|
|
42
|
+
→ Free-form description folded into `trigger_detail`; scope defaults to full aiwiki.
|
|
43
|
+
|
|
44
|
+
## When to use
|
|
45
|
+
|
|
46
|
+
- After a **major refactor** or **branch merge** brought in lots of new wiki entries.
|
|
47
|
+
- When `aiwiki/raw/` has accumulated unclassified notes from `/note` invocations.
|
|
48
|
+
- When you suspect **duplicate gotchas** across recent debugging sessions.
|
|
49
|
+
- Before **handoff** to a new contributor — get the wiki into curated shape first.
|
|
50
|
+
- When `forge wiki status` shows no pending dreams but the aiwiki feels noisy.
|
|
51
|
+
|
|
52
|
+
## When NOT to use
|
|
53
|
+
|
|
54
|
+
- A dream is already pending review (`forge wiki status` lists it). Review the existing one first; queueing a new dream against the same source state produces overlapping proposals.
|
|
55
|
+
- `aiwiki/` has no recent activity — there's nothing to consolidate; the cycle would no-op.
|
|
56
|
+
- You want to **edit a single page**. Edit it directly. Dream is for *merging / promoting / pruning across pages*, not per-page revision.
|
|
57
|
+
|
|
58
|
+
## I/O Contract
|
|
59
|
+
|
|
60
|
+
| Field | Value |
|
|
61
|
+
|---|---|
|
|
62
|
+
| **Requires** | `aiwiki/` (scaffolded by `/setup`), `aiwiki/schemas/` |
|
|
63
|
+
| **Produces** | `aiwiki/proposed/{dream_id}/` (mirror structure) + `.dream-manifest.json` |
|
|
64
|
+
| **Dispatches** | `support-dream` skill → `dreamer` subagent |
|
|
65
|
+
| **Review surface** | `forge wiki ui` (web view at 127.0.0.1:8765) or `forge wiki review/accept/reject` CLI |
|
|
66
|
+
|
|
67
|
+
## Do NOT
|
|
68
|
+
|
|
69
|
+
- Do NOT modify `aiwiki/` directly inside this flow — that is `support-dream`'s invariant.
|
|
70
|
+
- Do NOT queue a new dream while one is pending review against the same source state.
|
|
71
|
+
- Do NOT skip the lint pass — `support-dream` runs lint on the proposed output before marking the dream complete.
|
package/commands/feature.md
CHANGED
|
@@ -206,7 +206,12 @@ Execute the slice graph from Phase 5. Per slice:
|
|
|
206
206
|
2. REQUIRED SUB-SKILL: Use **quality-code-review**
|
|
207
207
|
3. Fix any Critical or Important findings
|
|
208
208
|
4. Per-slice user-confirm
|
|
209
|
-
5. Per-slice dream
|
|
209
|
+
5. **Per-slice dream (auto-fire on slice close).** After the slice's gates pass (`gate-passed: true` on the slice's `code-review` + `runtime-reach`), invoke the **support-dream** skill with:
|
|
210
|
+
- **scope:** `aiwiki/gotchas/`, `aiwiki/conventions/` (any subfolders the slice's builder + reviewer subagents wrote to; check git diff on `aiwiki/` since the slice started for a precise list)
|
|
211
|
+
- **trigger:** `phase-close`
|
|
212
|
+
- **trigger_detail:** `"Phase 6 per-slice — {slice_id}"`
|
|
213
|
+
Dream output goes to `aiwiki/proposed/{dream_id}/`. Surface the id + review path to the user. The next slice can start while the proposal is pending review (per-slice dreams do NOT block forward motion — only phase-close gates do).
|
|
214
|
+
**Skip when:** the slice's build wrote nothing to `aiwiki/` (pure code change with no new gotcha or convention). No-op dreams add noise.
|
|
210
215
|
|
|
211
216
|
For `--size major` features: also escalate to `quality-security-audit` on slices that touch auth/payments/PII.
|
|
212
217
|
|
|
@@ -214,7 +219,7 @@ Optional: `/autopilot production` for Ralph-loop hands-off slice execution *(pla
|
|
|
214
219
|
|
|
215
220
|
### GATE: All Slices Complete
|
|
216
221
|
|
|
217
|
-
All slices `gate-passed: true`. Update manifest: `artifacts.production-build.locked_at` (the slice terminal state + the production code ARE the production-build artifacts).
|
|
222
|
+
All slices `gate-passed: true`. Update manifest: `artifacts.production-build.locked_at` (the slice terminal state + the production code ARE the production-build artifacts). Any pending per-slice dream proposals from Step 8.5 must be reviewed before Phase 7 (deliver) starts — Phase 7's retrospective dream depends on a consolidated wiki state.
|
|
218
223
|
|
|
219
224
|
## Step 9: Test Plan + Execution
|
|
220
225
|
|
package/commands/wrap.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wrap
|
|
3
|
+
description: "Capture and finalize the current Claude session. Writes ## Files touched / ## Decisions made / ## Gotchas surfaced / ## Open questions / ## Next steps into aiwiki/sessions/{date}-{session_id_short}.md, then sets status: done. Use at the natural end of a working session so the next session-start hook can surface a meaningful handoff. Optional argument: a one-line focus statement (otherwise inferred from the active manifest)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /wrap — Capture and finalize the current session
|
|
7
|
+
|
|
8
|
+
Finalize this Claude session's handoff artifact. Writes the index sections (Files touched / Decisions / Gotchas / Open questions / Next steps) into `aiwiki/sessions/{date}-{session_id_short}.md` so the next session-start hook can surface a meaningful handoff.
|
|
9
|
+
|
|
10
|
+
**Distinct from `/dream`:** `/wrap` captures *this session's* knowledge (what was worked on, what was decided). `/dream` consolidates *the whole aiwiki* (merges duplicates, promotes raw → typed). The two can be run sequentially at session end (`/wrap` first, then `/dream`) but they answer different questions.
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. **Determine session file path.**
|
|
15
|
+
- Read `session_id` from the most recent SessionStart context (Claude Code provides this in the hook payload; if running standalone, ask the user or read from `aiwiki/sessions/*.md` mtime).
|
|
16
|
+
- Path: `aiwiki/sessions/{ISO-date}-{session_id_short7}.md` (the same path pre-compact would have used). If the file already exists (created by pre-compact), append to it. If not, create it lazily here.
|
|
17
|
+
|
|
18
|
+
2. **Determine focus.**
|
|
19
|
+
- If `/wrap <focus statement>` was supplied, use that.
|
|
20
|
+
- Else: read the active work item from `.forge/work/*/*/manifest.yaml` where `status: in-progress`. Focus = `{type}/{name}` (e.g. `feature/wire-dream`).
|
|
21
|
+
- Else: ask the user "What was this session about?" — one-line answer.
|
|
22
|
+
|
|
23
|
+
3. **Read the session file** (if it already has content from pre-compact).
|
|
24
|
+
- The `## Checkpoints` section stays as-is — that's event log, not user-facing summary.
|
|
25
|
+
- The index sections (`## Files touched`, etc.) are what you fill.
|
|
26
|
+
|
|
27
|
+
4. **Capture `## Files touched`.**
|
|
28
|
+
- Run `git diff --name-only $(git merge-base HEAD main)..HEAD` (or `HEAD~10..HEAD` for non-branch work) to find files changed during the session.
|
|
29
|
+
- For each: cite as `[path](path:line)` if a specific line range was the focus; else `[path](path)`.
|
|
30
|
+
- LINT will auto-fill `@<sha7>` on save.
|
|
31
|
+
- Skip generated files, dependency lockfiles, build artifacts.
|
|
32
|
+
|
|
33
|
+
5. **Capture `## Decisions made`.**
|
|
34
|
+
- List ADRs in `aiwiki/decisions/` written or modified during this session.
|
|
35
|
+
- Format: `- [decision-NNNN: short title](aiwiki/decisions/NNNN-slug.md)`.
|
|
36
|
+
- If none were written but a decision-worthy choice was made conversationally, note: "DEFERRED: {one-line description} — should become an ADR but wasn't written this session."
|
|
37
|
+
|
|
38
|
+
6. **Capture `## Gotchas surfaced`.**
|
|
39
|
+
- List gotchas in `aiwiki/gotchas/` created or updated this session.
|
|
40
|
+
- Same link format.
|
|
41
|
+
- If a gotcha was hit but not captured, note it as DEFERRED.
|
|
42
|
+
|
|
43
|
+
7. **Capture `## Open questions`.**
|
|
44
|
+
- List raw notes in `aiwiki/raw/{today}.md` that represent unresolved questions (entries starting with "TBD", "open", "?", or that were /note'd as questions).
|
|
45
|
+
- Format: `- [HH:MM question title](aiwiki/raw/{date}.md#anchor)`.
|
|
46
|
+
- If no /note questions were captured but threads are open, list them as bare bullets.
|
|
47
|
+
|
|
48
|
+
8. **Capture `## Next steps`.**
|
|
49
|
+
- 2-5 bullets: what the next session should do.
|
|
50
|
+
- Each bullet should reference a file/manifest/issue. No vague "continue working on X."
|
|
51
|
+
- Examples:
|
|
52
|
+
- "Resume `feature/wire-dream` at Phase 6 (slice graph in manifest) — first slice: `wire-pre-compact-hook`."
|
|
53
|
+
- "Review pending dream `aiwiki/proposed/2026-05-18-1742-manual/` before next phase."
|
|
54
|
+
- "Address open question on token rotation policy — see `aiwiki/raw/2026-05-18.md#14-23`."
|
|
55
|
+
|
|
56
|
+
9. **Update frontmatter.**
|
|
57
|
+
- Set `focus: {focus}` (from Step 2).
|
|
58
|
+
- Set `status: done`.
|
|
59
|
+
- Set `date_end: {today ISO date}`.
|
|
60
|
+
- Set `last_commit: {git rev-parse --short HEAD}` if in a git repo with commits.
|
|
61
|
+
|
|
62
|
+
10. **Confirm with the user.**
|
|
63
|
+
- Surface the drafted session file content.
|
|
64
|
+
- Ask: "Save this as your session handoff?" — yes / edit / skip.
|
|
65
|
+
- If edit: take inline edits, re-render, ask again.
|
|
66
|
+
- If skip: leave the file's `status: active` (next session-start will surface it as unfinalized).
|
|
67
|
+
|
|
68
|
+
11. **Save and lint.**
|
|
69
|
+
- Write the file.
|
|
70
|
+
- `wiki-lint` runs automatically on save (PostToolUse hook).
|
|
71
|
+
- If lint surfaces warnings (missing citations, stale `@<sha7>`, etc.), address before considering /wrap complete.
|
|
72
|
+
|
|
73
|
+
12. **Suggest follow-ups.**
|
|
74
|
+
- If `aiwiki/raw/{today}.md` has unconsolidated entries, suggest: "You have N raw notes from this session — consider `/dream raw` to consolidate before next session."
|
|
75
|
+
- If a pending dream proposal exists in `aiwiki/proposed/`, surface: "N pending dream proposals — review via `forge wiki ui` before next session."
|
|
76
|
+
|
|
77
|
+
## Example
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
User: /wrap
|
|
81
|
+
|
|
82
|
+
Agent: Session 2026-05-18-7e8a3f2 (focus: feature/wire-dream).
|
|
83
|
+
Drafted handoff with:
|
|
84
|
+
- 11 files touched (skills/, hooks/, commands/, templates/)
|
|
85
|
+
- 1 decision (consolidate notepad → sessions/)
|
|
86
|
+
- 0 new gotchas this session
|
|
87
|
+
- 2 open questions
|
|
88
|
+
- 4 next-step bullets
|
|
89
|
+
|
|
90
|
+
[Renders the proposed file content]
|
|
91
|
+
|
|
92
|
+
Save?
|
|
93
|
+
|
|
94
|
+
User: yes
|
|
95
|
+
|
|
96
|
+
Agent: Saved aiwiki/sessions/2026-05-18-7e8a3f2.md (status: done).
|
|
97
|
+
Suggestion: 3 raw notes from /note today — consider /dream raw to
|
|
98
|
+
consolidate before next session.
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## When to use
|
|
102
|
+
|
|
103
|
+
- **At the natural end of a working session** before exiting Claude Code. Even a 30-second wrap-up preserves the handoff signal.
|
|
104
|
+
- **Before a long break** (overnight, end of day). The next session-start surfaces this file so you don't lose context.
|
|
105
|
+
- **Before a major context shift** (switching to a different feature mid-day). Wrap the current focus, then start fresh.
|
|
106
|
+
- **After a phase locks** if the natural pause is also a session end. (Phase-close already triggers a dream — `/wrap` is the complementary capture for what *you* did, while dream consolidates the *wiki state*.)
|
|
107
|
+
|
|
108
|
+
## When NOT to use
|
|
109
|
+
|
|
110
|
+
- **Trivial sessions** (a single read, a one-line edit). No handoff signal — skip /wrap and let the next session-start surface "no recent session" (silence is fine).
|
|
111
|
+
- **Mid-task interruptions** where you'll be right back. /wrap is for genuine session boundaries.
|
|
112
|
+
- **As a substitute for typed-page writes.** Decisions belong in `aiwiki/decisions/` directly; gotchas in `aiwiki/gotchas/`. /wrap is the *index* of what was written elsewhere — it doesn't replace writing the artifacts themselves.
|
|
113
|
+
- **As a substitute for `/dream`.** /wrap captures this session's work; /dream consolidates the whole aiwiki. Use both at the right times.
|
|
114
|
+
|
|
115
|
+
## I/O Contract
|
|
116
|
+
|
|
117
|
+
| Field | Value |
|
|
118
|
+
|---|---|
|
|
119
|
+
| **Requires** | `aiwiki/sessions/` (scaffolded by `/setup`), Claude Code's hook context for `session_id` (or interactive fallback) |
|
|
120
|
+
| **Produces** | `aiwiki/sessions/{date}-{session_id_short}.md` with index sections filled and `status: done` |
|
|
121
|
+
| **Triggers** | `wiki-lint` PostToolUse hook on save |
|
|
122
|
+
| **Feeds into** | `session-start.sh` (next session reads it), `support-dream` (refines on next dream cycle) |
|
|
123
|
+
|
|
124
|
+
## Do NOT
|
|
125
|
+
|
|
126
|
+
- Do NOT auto-fire `/dream` from inside `/wrap`. The two are separate concerns; user decides which to run. /wrap can SUGGEST /dream when raw notes accumulated, but does not invoke it.
|
|
127
|
+
- Do NOT overwrite the `## Checkpoints` section if pre-compact wrote to it during the session — that's append-only event log, preserved as-is.
|
|
128
|
+
- Do NOT write vague prose. Index of links, not narrative. Future sessions follow the links to actual artifacts.
|
|
129
|
+
- Do NOT capture every file diff. Skip dependency lockfiles, build artifacts, anything ≤2 lines of cosmetic change. Index the meaningful work.
|
|
130
|
+
- Do NOT set `status: done` if the user said "skip" at Step 10 — leave `status: active` so the next session-start surfaces it.
|
package/dist/init.js
CHANGED
|
@@ -12,7 +12,7 @@ import { hasForgeMarkers, mergeForgeBlock } from "./merge.js";
|
|
|
12
12
|
* entries the user does not already have. Creates .gitignore if absent.
|
|
13
13
|
*
|
|
14
14
|
* Entries:
|
|
15
|
-
* .forge/state/ — operational state (
|
|
15
|
+
* .forge/state/ — operational state (telemetry, dream history; session handoff lives in aiwiki/sessions/)
|
|
16
16
|
* .forge/local.yaml — per-user preferences (Codex/Graphify consent, etc.)
|
|
17
17
|
*
|
|
18
18
|
* Why at install time: pre-compact.sh used to add `.forge/state/` from the
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "Maps manifest gate names to required skill and agent invocations. Used by gate-enforcer.sh to verify prerequisites before allowing gate-passed: true. Agents are dispatched by skills internally — listed here so the enforcer can verify they were invoked via telemetry.",
|
|
2
|
+
"_comment": "Maps manifest gate names to required skill and agent invocations. Used by gate-enforcer.sh to verify prerequisites before allowing gate-passed: true. Enforcement is work_id-scoped (v6.2+): the enforcer filters .forge/state/telemetry.jsonl to records whose work_id matches the manifest being edited (extracted from .forge/work/{type}/{name}/manifest.yaml). A stale invocation from another work item, or a legacy record written before work_id was added, does NOT satisfy a fresh gate. Agents are dispatched by skills internally — listed here so the enforcer can verify they were invoked via telemetry.",
|
|
3
3
|
"requirements": {
|
|
4
4
|
"skill": "discover-requirements",
|
|
5
5
|
"agent": null
|
|
@@ -83,6 +83,14 @@ if [ ! -f "$CONFIG" ]; then
|
|
|
83
83
|
exit 0
|
|
84
84
|
fi
|
|
85
85
|
|
|
86
|
+
# Extract work_id from the manifest path: .forge/work/{type}/{name}/manifest.yaml
|
|
87
|
+
# Used to filter telemetry by work item so a stale invocation from another work
|
|
88
|
+
# item cannot satisfy this gate (closes P0-5 from v6.1-beta audit).
|
|
89
|
+
WORK_ID=""
|
|
90
|
+
if [[ "$FILE_PATH" =~ \.forge/work/([^/]+)/([^/]+)/manifest\.yaml$ ]]; then
|
|
91
|
+
WORK_ID="${BASH_REMATCH[1]}/${BASH_REMATCH[2]}"
|
|
92
|
+
fi
|
|
93
|
+
|
|
86
94
|
# Check each gate being passed against requirements
|
|
87
95
|
BLOCKED_REASONS=""
|
|
88
96
|
|
|
@@ -126,18 +134,55 @@ for GATE in $(jq -r 'keys[] | select(. != "_comment")' "$CONFIG"); do
|
|
|
126
134
|
# Resolve required agents: agents array first, then single agent field
|
|
127
135
|
REQUIRED_AGENTS=$(jq -r "if .\"$GATE\".agents then .\"$GATE\".agents[] else .\"$GATE\".agent // empty end" "$CONFIG" 2>/dev/null)
|
|
128
136
|
|
|
129
|
-
#
|
|
137
|
+
# Telemetry check is work_id-scoped (closes P0-5 cross-work-item bypass).
|
|
138
|
+
# Records without work_id (legacy or no-active-work) are NOT counted —
|
|
139
|
+
# an untagged invocation can't satisfy a gate on a specific work item.
|
|
140
|
+
# Records lacking jq-parsable shape are also ignored (jq returns null per line;
|
|
141
|
+
# `select(...)` filters them out).
|
|
142
|
+
check_invocation() {
|
|
143
|
+
local NAME="$1"
|
|
144
|
+
if [ ! -f "$TELEMETRY" ]; then
|
|
145
|
+
return 1
|
|
146
|
+
fi
|
|
147
|
+
if [ -z "$WORK_ID" ]; then
|
|
148
|
+
# No work_id resolved from path — should be rare; fall back to bare-name
|
|
149
|
+
# check so we don't accidentally hard-block manifest edits made outside
|
|
150
|
+
# the .forge/work/{type}/{name}/ tree (unlikely given the path filter
|
|
151
|
+
# at line ~43 already excluded non-manifest paths, but defensive).
|
|
152
|
+
grep -q "\"name\":\"$NAME\"" "$TELEMETRY" 2>/dev/null
|
|
153
|
+
else
|
|
154
|
+
# jq -s collects all JSONL lines into an array. select() narrows to the
|
|
155
|
+
# exact work_id + name pair. length > 0 means at least one invocation
|
|
156
|
+
# in this work item. The 2>/dev/null swallows parse errors on
|
|
157
|
+
# malformed records (treated as no match — correct behavior).
|
|
158
|
+
local COUNT
|
|
159
|
+
COUNT=$(jq -s --arg work_id "$WORK_ID" --arg name "$NAME" \
|
|
160
|
+
'map(select(.work_id == $work_id and .name == $name)) | length' \
|
|
161
|
+
"$TELEMETRY" 2>/dev/null || echo 0)
|
|
162
|
+
[ "$COUNT" != "0" ] && [ -n "$COUNT" ]
|
|
163
|
+
fi
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
# Check skill invocation in telemetry (work_id-scoped)
|
|
130
167
|
if [ -n "$REQUIRED_SKILL" ]; then
|
|
131
|
-
if
|
|
132
|
-
|
|
168
|
+
if ! check_invocation "$REQUIRED_SKILL"; then
|
|
169
|
+
if [ -n "$WORK_ID" ]; then
|
|
170
|
+
BLOCKED_REASONS="${BLOCKED_REASONS}Gate '$GATE' requires skill '$REQUIRED_SKILL' (not invoked for work_id '$WORK_ID'). "
|
|
171
|
+
else
|
|
172
|
+
BLOCKED_REASONS="${BLOCKED_REASONS}Gate '$GATE' requires skill '$REQUIRED_SKILL' (not found in telemetry). "
|
|
173
|
+
fi
|
|
133
174
|
fi
|
|
134
175
|
fi
|
|
135
176
|
|
|
136
|
-
# Check agent dispatch in telemetry
|
|
177
|
+
# Check agent dispatch in telemetry (work_id-scoped)
|
|
137
178
|
for AGENT in $REQUIRED_AGENTS; do
|
|
138
179
|
if [ -n "$AGENT" ] && [ "$AGENT" != "null" ]; then
|
|
139
|
-
if
|
|
140
|
-
|
|
180
|
+
if ! check_invocation "$AGENT"; then
|
|
181
|
+
if [ -n "$WORK_ID" ]; then
|
|
182
|
+
BLOCKED_REASONS="${BLOCKED_REASONS}Gate '$GATE' requires agent '$AGENT' (not dispatched for work_id '$WORK_ID'). "
|
|
183
|
+
else
|
|
184
|
+
BLOCKED_REASONS="${BLOCKED_REASONS}Gate '$GATE' requires agent '$AGENT' (not found in telemetry). "
|
|
185
|
+
fi
|
|
141
186
|
fi
|
|
142
187
|
fi
|
|
143
188
|
done
|