@izkac/forgekit 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 (143) hide show
  1. package/bin/forge.mjs +100 -0
  2. package/bin/forgekit.mjs +84 -0
  3. package/bin/review.mjs +82 -0
  4. package/package.json +46 -0
  5. package/scripts/prepack.mjs +78 -0
  6. package/scripts/run-tests.mjs +43 -0
  7. package/src/adr.mjs +236 -0
  8. package/src/adr.test.mjs +170 -0
  9. package/src/change.mjs +234 -0
  10. package/src/change.test.mjs +83 -0
  11. package/src/cleanup-sessions.mjs +70 -0
  12. package/src/config.mjs +103 -0
  13. package/src/defer.mjs +75 -0
  14. package/src/doctor.mjs +341 -0
  15. package/src/doctor.test.mjs +114 -0
  16. package/src/init.mjs +575 -0
  17. package/src/install.mjs +777 -0
  18. package/src/install.test.mjs +104 -0
  19. package/src/integrity-check.mjs +58 -0
  20. package/src/integrity.mjs +317 -0
  21. package/src/integrity.test.mjs +296 -0
  22. package/src/lib/workspaces.mjs +55 -0
  23. package/src/lib.mjs +138 -0
  24. package/src/models.defaults.json +41 -0
  25. package/src/new-session.mjs +82 -0
  26. package/src/openspec-overlays/README.md +19 -0
  27. package/src/openspec-overlays/openspec-apply-change-footer.md +14 -0
  28. package/src/openspec-overlays/opsx-apply-completion-step.md +1 -0
  29. package/src/openspec-overlays/opsx-apply-implement-step.md +11 -0
  30. package/src/paths.mjs +92 -0
  31. package/src/plan-engine.mjs +260 -0
  32. package/src/plan-engine.test.mjs +245 -0
  33. package/src/preferences.defaults.json +78 -0
  34. package/src/preferences.mjs +438 -0
  35. package/src/preferences.test.mjs +174 -0
  36. package/src/record-evidence.mjs +204 -0
  37. package/src/record-evidence.test.mjs +260 -0
  38. package/src/resolve-model.mjs +312 -0
  39. package/src/resolve-model.test.mjs +194 -0
  40. package/src/review/carryforward.mjs +413 -0
  41. package/src/review/carryforward.test.mjs +587 -0
  42. package/src/review/cli.test.mjs +117 -0
  43. package/src/review/export.mjs +172 -0
  44. package/src/review/export.test.mjs +197 -0
  45. package/src/review/fixtures/valid-review.json +42 -0
  46. package/src/review/lib.mjs +894 -0
  47. package/src/review/lib.test.mjs +266 -0
  48. package/src/review/merge-tentative.mjs +292 -0
  49. package/src/review/merge-tentative.test.mjs +363 -0
  50. package/src/review/new-review.mjs +200 -0
  51. package/src/review/render.mjs +108 -0
  52. package/src/review/schema-consistency.test.mjs +83 -0
  53. package/src/review/schema.json +196 -0
  54. package/src/review/signals.mjs +144 -0
  55. package/src/review/signals.test.mjs +62 -0
  56. package/src/score-cli.mjs +68 -0
  57. package/src/score.mjs +489 -0
  58. package/src/score.test.mjs +253 -0
  59. package/src/session-reminder.mjs +168 -0
  60. package/src/session-status.mjs +70 -0
  61. package/src/set-models.mjs +186 -0
  62. package/src/set-phase.mjs +177 -0
  63. package/src/set-phase.test.mjs +317 -0
  64. package/src/set-prefs.mjs +294 -0
  65. package/src/spine.mjs +91 -0
  66. package/src/triage-prompt.mjs +175 -0
  67. package/src/triage-prompt.test.mjs +50 -0
  68. package/src/vendor-openspec-overlays.mjs +176 -0
  69. package/src/vendor-openspec-overlays.test.mjs +62 -0
  70. package/vendor/skills/archive-to-adr/SKILL.md +149 -0
  71. package/vendor/skills/forge/SKILL.md +136 -0
  72. package/vendor/skills/forge/phases/brainstorm.md +23 -0
  73. package/vendor/skills/forge/phases/finish.md +87 -0
  74. package/vendor/skills/forge/phases/implement.md +76 -0
  75. package/vendor/skills/forge/phases/plan-openspec.md +40 -0
  76. package/vendor/skills/forge/phases/plan-specs.md +97 -0
  77. package/vendor/skills/forge/phases/review.md +25 -0
  78. package/vendor/skills/forge/phases/verify.md +120 -0
  79. package/vendor/skills/forge/references/forge-layout.md +85 -0
  80. package/vendor/skills/forge/references/pace.md +115 -0
  81. package/vendor/skills/forge/references/plan-routing.md +51 -0
  82. package/vendor/skills/forge/references/runtime-integrity.md +157 -0
  83. package/vendor/skills/forge/references/substantial-work.md +37 -0
  84. package/vendor/skills/forge/references/tdd-core.md +29 -0
  85. package/vendor/skills/forge/references/test-evidence.md +30 -0
  86. package/vendor/skills/forge/references/test-strategy.md +68 -0
  87. package/vendor/skills/forge/skills/NOTICE.md +17 -0
  88. package/vendor/skills/forge/skills/brainstorming/SKILL.md +120 -0
  89. package/vendor/skills/forge/skills/requesting-code-review/SKILL.md +67 -0
  90. package/vendor/skills/forge/skills/requesting-code-review/code-reviewer.md +146 -0
  91. package/vendor/skills/forge/skills/subagent-driven-development/SKILL.md +87 -0
  92. package/vendor/skills/forge/skills/systematic-debugging/SKILL.md +234 -0
  93. package/vendor/skills/forge/skills/systematic-debugging/condition-based-waiting.md +115 -0
  94. package/vendor/skills/forge/skills/systematic-debugging/defense-in-depth.md +122 -0
  95. package/vendor/skills/forge/skills/systematic-debugging/find-polluter.sh +63 -0
  96. package/vendor/skills/forge/skills/systematic-debugging/root-cause-tracing.md +169 -0
  97. package/vendor/skills/forge/skills/test-driven-development/SKILL.md +290 -0
  98. package/vendor/skills/forge/skills/test-driven-development/testing-anti-patterns.md +299 -0
  99. package/vendor/skills/forge/skills/verification-before-completion/SKILL.md +59 -0
  100. package/vendor/skills/forge/subagents/final-reviewer-prompt.md +53 -0
  101. package/vendor/skills/forge/subagents/implementer-prompt.md +38 -0
  102. package/vendor/skills/forge/subagents/task-reviewer-prompt.md +61 -0
  103. package/vendor/skills/git-resolve-adr-conflict/SKILL.md +132 -0
  104. package/vendor/skills/thorough-code-review/SKILL.md +290 -0
  105. package/vendor/skills/thorough-code-review/examples/accepted-risks-janus.md +32 -0
  106. package/vendor/skills/thorough-code-review/examples.md +133 -0
  107. package/vendor/skills/thorough-code-review/reference/accepted-risks.md +26 -0
  108. package/vendor/skills/thorough-code-review/reference/lenses.md +96 -0
  109. package/vendor/skills/thorough-code-review/reference/phase1-scout.md +62 -0
  110. package/vendor/skills/thorough-code-review/reference/phase1c-coverage.md +44 -0
  111. package/vendor/skills/thorough-code-review/reference/phase2-skeptic.md +105 -0
  112. package/vendor/skills/thorough-code-review/reference/report-schema.json +222 -0
  113. package/vendor/skills/thorough-code-review/reference/report-template.md +115 -0
  114. package/vendor/skills/thorough-code-review/reference/severity-rubric.md +49 -0
  115. package/vendor/skills/thorough-code-review/reference/signals-preflight.md +55 -0
  116. package/vendor/templates/adr/README.md +7 -0
  117. package/vendor/templates/adr/decisions.md +141 -0
  118. package/vendor/templates/adr/hooks/check-pending-adrs.mjs +74 -0
  119. package/vendor/templates/adr/hooks/check-pending-adrs.sh +3 -0
  120. package/vendor/templates/adr/hooks/openspec-archive-agent-message.mjs +52 -0
  121. package/vendor/templates/adr/hooks/openspec-archive-agent-message.sh +3 -0
  122. package/vendor/templates/project/claude/commands/forge-apply.md +75 -0
  123. package/vendor/templates/project/claude/commands/forge-brainstorm.md +7 -0
  124. package/vendor/templates/project/claude/commands/forge-build.md +17 -0
  125. package/vendor/templates/project/claude/commands/forge-plan.md +12 -0
  126. package/vendor/templates/project/claude/commands/forge-skip.md +14 -0
  127. package/vendor/templates/project/claude/commands/forge-status.md +16 -0
  128. package/vendor/templates/project/claude/commands/forge.md +16 -0
  129. package/vendor/templates/project/claude/hooks/forge-prompt-hook.mjs +73 -0
  130. package/vendor/templates/project/claude/hooks/forge-session-start.mjs +19 -0
  131. package/vendor/templates/project/claude/hooks/forge-triage-hook.mjs +77 -0
  132. package/vendor/templates/project/claude/rules/forge.md +16 -0
  133. package/vendor/templates/project/codex/rules/forge.md +10 -0
  134. package/vendor/templates/project/cursor/commands/forge-apply.md +75 -0
  135. package/vendor/templates/project/cursor/commands/forge-brainstorm.md +10 -0
  136. package/vendor/templates/project/cursor/commands/forge-build.md +17 -0
  137. package/vendor/templates/project/cursor/commands/forge-plan.md +15 -0
  138. package/vendor/templates/project/cursor/commands/forge-skip.md +14 -0
  139. package/vendor/templates/project/cursor/commands/forge-status.md +16 -0
  140. package/vendor/templates/project/cursor/commands/forge.md +16 -0
  141. package/vendor/templates/project/cursor/hooks/forge-session-start.mjs +30 -0
  142. package/vendor/templates/project/cursor/hooks/forge-session-start.sh +3 -0
  143. package/vendor/templates/project/cursor/rules/forge.mdc +21 -0
@@ -0,0 +1,141 @@
1
+ # Architecture decision records (ADRs)
2
+
3
+ > How this project captures **architectural** decisions. ADRs live next to OpenSpec
4
+ > archives. Scaffolded by Forgekit (`forge init --adr` / `forgekit install` with ADRs on).
5
+
6
+ ADR directory for this project: **`{{ADR_DIR}}`** (configured in `.forge/config.json`).
7
+
8
+ ---
9
+
10
+ ## 1. Why ADRs *and* OpenSpec archives?
11
+
12
+ They overlap in “why we did something,” but they serve different lookups:
13
+
14
+ | OpenSpec archive (verbose) | ADR (short) |
15
+ | -------------------------- | ----------- |
16
+ | `proposal.md`, `design.md`, `tasks.md`, specs | One file, one sharpened decision |
17
+ | “Replay the implementation story” | “Why is X shaped this way?” |
18
+
19
+ ---
20
+
21
+ ## 2. When to write an ADR
22
+
23
+ | Write an ADR when the change … | Skip the ADR when … |
24
+ | ------------------------------ | ------------------- |
25
+ | Establishes or moves a boundary | Bug fix / copy / docs-only |
26
+ | Chooses among real alternatives | Refactor that changes no decision |
27
+ | Adds a constraint future code must follow | Chore rename without semantics |
28
+ | Picks a costly-to-swap vendor or protocol | Narrow feature inside a prior ADR |
29
+ | Codifies a convention across the repo | Noise would drown readers |
30
+
31
+ If you’re listing code edits, that belongs in `design.md`—not an ADR.
32
+
33
+ ---
34
+
35
+ ## 3. Format (`{{ADR_DIR}}/NNNN-short-topic.md`)
36
+
37
+ ```markdown
38
+ # NNNN. <Short, decision-shaped title>
39
+
40
+ - **Status**: Proposed | Accepted | Superseded by ADR-NNNN (…)
41
+ - **Date**: YYYY-MM-DD
42
+ - **Area**: <product or layer>
43
+ - **Related**: openspec/changes/archive/<change>/, …
44
+
45
+ ## Context
46
+
47
+ One paragraph: pressure or constraint forcing a decision.
48
+
49
+ ## Decision
50
+
51
+ One imperative paragraph stating what this project commits to.
52
+
53
+ ## Alternatives considered
54
+
55
+ - **Option A** — rejected because …
56
+ - **Chosen** — …
57
+
58
+ ## Consequences
59
+
60
+ ### Positive
61
+ ### Negative
62
+ ### Neutral
63
+
64
+ ## References
65
+
66
+ - Archive: openspec/changes/archive/<name>/
67
+ ```
68
+
69
+ Keep ADRs terse (roughly tens to low hundreds of lines each).
70
+
71
+ ---
72
+
73
+ ## 4. Numbering
74
+
75
+ - Sequential `NNNN`; never recycle numbers—supersede with a **new** ADR.
76
+ - Prefer decision-shaped filenames: `0004-outbox-only-on-critical-path.md` not `0004-add-worker.md`.
77
+
78
+ All ADRs sit under **`{{ADR_DIR}}/`** even when scoped to one area—the decision
79
+ usually crosses layers.
80
+
81
+ ---
82
+
83
+ ## 5. Status index (`{{ADR_DIR}}/README.md`)
84
+
85
+ Maintain the table of `#`, Title, Status, Date. Leave placeholder rows until real ADRs land.
86
+
87
+ ---
88
+
89
+ ## 6. Cross-link OpenSpec ↔ ADRs
90
+
91
+ ADR **References** should point at the dated archive folder.
92
+
93
+ Archived `proposal.md` should gain:
94
+
95
+ ```markdown
96
+ ## Decision record
97
+
98
+ This change is recorded as ADR-NNNN ({{ADR_DIR}}/NNNN-short-topic.md).
99
+ ```
100
+
101
+ Or, for non-architectural archives, the one-line stamp:
102
+
103
+ ```text
104
+ No ADR — non-architectural change
105
+ ```
106
+
107
+ Capability specs may cite ADRs as normative “why.”
108
+
109
+ ---
110
+
111
+ ## 7. ADRs in agent retrieval
112
+
113
+ Short, focused ADRs embed well. **Do not** add `{{ADR_DIR}}/` to
114
+ `.cursorindexignore` (or equivalent).
115
+
116
+ ---
117
+
118
+ ## 7a. Hooks: archive → ADR
119
+
120
+ When ADR wiring is enabled, archive hooks remind agents to run **archive-to-adr**
121
+ after `openspec archive` or a move into `openspec/changes/archive/YYYY-MM-DD-…`.
122
+
123
+ Session-start backstops list archives whose `proposal.md` lacks `ADR-[0-9]` **and**
124
+ lacks the `No ADR — non-architectural change` stamp.
125
+
126
+ ---
127
+
128
+ ## 8. Maintenance habit
129
+
130
+ - On each meaningful archive: decide ADR vs stamp.
131
+ - Periodically skim the index for stale status.
132
+ - Supersede with new ADRs—don’t delete old ones.
133
+
134
+ ---
135
+
136
+ ## 9. TL;DR
137
+
138
+ - ADRs **distill** decisions; OpenSpec archives keep the **full** story.
139
+ - Use this file + `{{ADR_DIR}}/README.md` + `{{ADR_DIR}}/NNNN-*.md`.
140
+ - Cross-link archives and ADRs both directions.
141
+ - After archive: run **archive-to-adr** (or stamp “No ADR”).
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Pending-ADR backstop: list archived proposals missing ADR link and No-ADR stamp.
4
+ * Honors .forge/config.json adr.enabled === false.
5
+ *
6
+ * Usage: node check-pending-adrs.mjs [repoRoot]
7
+ */
8
+
9
+ import fs from 'node:fs';
10
+ import path from 'node:path';
11
+ import { spawnSync } from 'node:child_process';
12
+
13
+ function gitRoot() {
14
+ const r = spawnSync('git', ['rev-parse', '--show-toplevel'], {
15
+ encoding: 'utf8',
16
+ shell: process.platform === 'win32',
17
+ });
18
+ if (r.status !== 0) return null;
19
+ return String(r.stdout || '').trim() || null;
20
+ }
21
+
22
+ function loadConfig(cwd) {
23
+ const p = path.join(cwd, '.forge', 'config.json');
24
+ if (!fs.existsSync(p)) return {};
25
+ try {
26
+ return JSON.parse(fs.readFileSync(p, 'utf8'));
27
+ } catch {
28
+ return {};
29
+ }
30
+ }
31
+
32
+ function listProposals(cwd, archiveRoot) {
33
+ const dir = path.join(cwd, ...archiveRoot.split('/'));
34
+ if (!fs.existsSync(dir)) return [];
35
+ /** @type {string[]} */
36
+ const out = [];
37
+ for (const name of fs.readdirSync(dir)) {
38
+ const proposal = path.join(dir, name, 'proposal.md');
39
+ if (fs.existsSync(proposal)) out.push(proposal);
40
+ }
41
+ return out;
42
+ }
43
+
44
+ const cwd = process.argv[2] || gitRoot();
45
+ if (!cwd) process.exit(0);
46
+
47
+ const cfg = loadConfig(cwd);
48
+ if (cfg.adr && cfg.adr.enabled === false) process.exit(0);
49
+
50
+ const archives = [
51
+ 'openspec/changes/archive',
52
+ `${(cfg.plan && typeof cfg.plan === 'object' && cfg.plan.dir) || 'specs'}/changes/archive`,
53
+ ];
54
+ /** @type {string[]} */
55
+ const pending = [];
56
+ for (const root of archives) {
57
+ for (const proposal of listProposals(cwd, root)) {
58
+ const body = fs.readFileSync(proposal, 'utf8');
59
+ if (/ADR-[0-9]/.test(body)) continue;
60
+ if (body.includes('No ADR — non-architectural change')) continue;
61
+ pending.push(path.relative(cwd, proposal).replace(/\\/g, '/'));
62
+ }
63
+ }
64
+
65
+ if (pending.length === 0) process.exit(0);
66
+
67
+ const shown = pending.slice(0, 10).join('\n');
68
+ process.stdout.write(
69
+ `Archived changes whose proposal.md does not reference an ADR yet:\n\n${shown}\n\n` +
70
+ `If any had architectural impact, run the archive-to-adr skill.\n` +
71
+ `Otherwise add a one-line stamp to each proposal.md:\n` +
72
+ ` 'No ADR — non-architectural change'\n`,
73
+ );
74
+ process.exit(0);
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+ # Thin wrapper around the Node implementation.
3
+ exec node "$(dirname "$0")/check-pending-adrs.mjs" "$@"
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Agent reminder after a successful change archive (stdout only).
4
+ * Usage: node openspec-archive-agent-message.mjs <change-slug>
5
+ */
6
+
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+
10
+ const changeName = process.argv[2];
11
+ if (!changeName) {
12
+ process.stderr.write('Usage: openspec-archive-agent-message.mjs <change-slug>\n');
13
+ process.exit(1);
14
+ }
15
+
16
+ let adrDir = 'docs/adr';
17
+ let decisionsDoc = 'docs/decisions.md';
18
+ let archiveRoot = 'openspec/changes/archive';
19
+ let adrEnabled = true;
20
+
21
+ const cfgPath = path.join(process.cwd(), '.forge', 'config.json');
22
+ if (fs.existsSync(cfgPath)) {
23
+ try {
24
+ const c = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
25
+ if (c.plan?.engine === 'specs') {
26
+ archiveRoot = `${c.plan.dir || 'specs'}/changes/archive`;
27
+ }
28
+ if (c.adr?.enabled === false) adrEnabled = false;
29
+ if (c.adr?.dir) adrDir = c.adr.dir;
30
+ if (c.adr?.decisionsDoc) decisionsDoc = c.adr.decisionsDoc;
31
+ } catch {
32
+ // keep defaults
33
+ }
34
+ }
35
+
36
+ if (!adrEnabled) {
37
+ process.stdout.write(
38
+ `Change '${changeName}' was archived. ADRs are disabled for this project\n` +
39
+ `(\`.forge/config.json\` → adr.enabled: false). No archive-to-adr follow-up.\n\n` +
40
+ `Suggested commit (display only — do NOT commit unless the user asks):\n\n` +
41
+ `openspec: archive ${changeName}\n`,
42
+ );
43
+ process.exit(0);
44
+ }
45
+
46
+ process.stdout.write(
47
+ `Change '${changeName}' was just archived.\n\n` +
48
+ `1. archive-to-adr: locate ${archiveRoot}/YYYY-MM-DD-${changeName}/, open proposal.md, and evaluate an ADR (${decisionsDoc}). If yes: ${adrDir}/NNNN-<topic>.md, update ${adrDir}/README.md, add a ## Decision record to proposal.md. If no: add one line to proposal.md: No ADR — non-architectural change.\n\n` +
49
+ `2. Suggested commit (display only — do NOT run git commit / push / gh pr create unless the user explicitly asks):\n\n` +
50
+ `openspec: archive ${changeName}\n`,
51
+ );
52
+ process.exit(0);
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+ # Thin wrapper around the Node implementation.
3
+ exec node "$(dirname "$0")/openspec-archive-agent-message.mjs" "$@"
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: /forge:apply
3
+ description: Forge — apply a tracked change with subagent TDD, verify, and review
4
+ category: Workflow
5
+ tags: [workflow, forge, openspec]
6
+ ---
7
+
8
+ **Forge-owned command.** Use this instead of bare `/opsx:apply` for disciplined implementation of a tracked change (OpenSpec or built-in specs engine — `.forge/config.json` → `plan.engine`).
9
+
10
+ Read the Forge skill (`~/.claude/skills/forge/SKILL.md`) and forgekit `docs/forge.md`.
11
+
12
+ **Input**: Optionally specify a change name (e.g., `/forge:apply add-auth`). If omitted, infer from context or active Forge session.
13
+
14
+ ## 0. Forge session
15
+
16
+ 1. Announce: "Using Forge apply."
17
+ 2. Resume `.forge/active.json` or bootstrap: `forge new <slug>`
18
+ 3. Set phase (use the project's engine as plan-type):
19
+ ```bash
20
+ forge phase implement --plan-type openspec|specs --openspec "<change>"
21
+ ```
22
+
23
+ ## 1–5. Load the change
24
+
25
+ **OpenSpec engine** — vendor CLI, follow `openspec-apply-change` (same as `/opsx:apply` steps 1–5):
26
+
27
+ 1. **Select the change** — announce "Using change: \<name\>"
28
+ 2. `openspec status --change "<name>" --json`
29
+ 3. `openspec instructions apply --change "<name>" --json`
30
+ 4. Read all `contextFiles` from CLI output
31
+ 5. Show progress (N/M tasks, schema, remaining tasks)
32
+
33
+ Handle blocked / all_done states per vendor skill before implementing.
34
+
35
+ **Specs engine** — no CLI:
36
+
37
+ 1. **Select the change** under `specs/changes/<name>/` — announce "Using change: \<name\>"
38
+ 2. Read `proposal.md`, `design.md` (if present), `tasks.md`
39
+ 3. Show progress (N/M checkboxes, remaining tasks)
40
+
41
+ ## 6. Implement (Forge — REQUIRED)
42
+
43
+ Follow ~/.claude/skills/forge/phases/implement.md`:
44
+
45
+ - **Do not** implement all tasks inline in coordinator context
46
+ - Per pending task: brief → **implementer** subagent (TDD first) → **spec reviewer** → **quality reviewer** → mark `- [x]` in `tasks.md`
47
+ - Bundled skills: `skills/subagent-driven-development` + `skills/test-driven-development`
48
+
49
+ Pause on unclear tasks, design issues, errors, or user interrupt.
50
+
51
+ ## 7. Verify (Forge — REQUIRED when all tasks done)
52
+
53
+ Follow ~/.claude/skills/forge/phases/verify.md`:
54
+
55
+ ```bash
56
+ forge phase verify
57
+ ```
58
+
59
+ Run affected workspace tests — **audit per-task `test-evidence.md`**; do not re-run the same commands if subagents already recorded passing runs (see verify phase).
60
+
61
+ ## 8. Review (Forge — REQUIRED)
62
+
63
+ Follow ~/.claude/skills/forge/phases/review.md`:
64
+
65
+ ```bash
66
+ forge phase review
67
+ ```
68
+
69
+ Final reviewer; save to `.forge/sessions/<id>/reviews/final-review.md`.
70
+
71
+ ## 9. Finish
72
+
73
+ When verify + review pass: suggest archive — `/opsx:archive` (OpenSpec) or the dated move into `specs/changes/archive/` (specs) — per [finish phase](~/.claude/skills/forge/phases/finish.md).
74
+
75
+ **Skip Forge for this task only:** `/forge:skip` (runs work without brainstorm/plan/verify chain).
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: Forge — brainstorm phase only
3
+ ---
4
+
5
+ Brainstorm phase only. Follow ~/.claude/skills/forge/phases/brainstorm.md`.
6
+
7
+ Invoke bundled **skills/brainstorming**. Save notes to `.forge/sessions/<id>/brainstorm/`. Terminal state: **OpenSpec propose** (`/opsx:propose`) — do not implement until artefacts are approved.
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: /forge:build
3
+ description: Forge — implement phase (subagent-driven + TDD)
4
+ category: Workflow
5
+ tags: [workflow, forge, openspec]
6
+ ---
7
+
8
+ Implement phase. Follow ~/.claude/skills/forge/phases/implement.md`.
9
+
10
+ **REQUIRED:** forge `skills/subagent-driven-development` + `skills/test-driven-development` per task.
11
+
12
+ - OpenSpec plan → **`/forge:apply`** (preferred) or `openspec-apply-change` / `/opsx:apply` wrapped in subagent loop
13
+ - Specs plan (`planType: specs`) → **`/forge:apply`** — tasks from `specs/changes/<name>/tasks.md`, no vendor CLI steps
14
+ - Throwaway plan → tasks from `.forge/.../plan.md`
15
+ - Direct → brief from `.forge/.../brainstorm/notes.md` + `decisions.md`
16
+
17
+ Then verify and review phases.
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: Forge — plan phase (tracked change propose)
3
+ ---
4
+
5
+ Plan phase. Follow ~/.claude/skills/forge/references/plan-routing.md`.
6
+
7
+ **Engine from `.forge/config.json` → `plan.engine`** — do not ask for a plan mode:
8
+
9
+ - `openspec` → run `/opsx:propose <prefix>-<slug>` or the `openspec-propose` skill per [plan-openspec.md](~/.claude/skills/forge/phases/plan-openspec.md)
10
+ - `specs` → author `specs/changes/<name>/{proposal,tasks}.md` per [plan-specs.md](~/.claude/skills/forge/phases/plan-specs.md)
11
+
12
+ Get user approval on the change artefacts before `/forge:build` or `/forge:apply`.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: /forge:skip
3
+ description: Explicitly skip Forge for this task
4
+ category: Workflow
5
+ tags: [workflow, forge]
6
+ ---
7
+
8
+ User opted out of Forge for **this task only**.
9
+
10
+ 1. If active session exists: `forge phase skipped`
11
+ 2. Do **not** brainstorm or plan
12
+ 3. Execute the request under normal project rules
13
+
14
+ Triage defaults to Forge; `/forge:skip` is the explicit override.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: /forge:status
3
+ description: Forge — show active session progress
4
+ category: Workflow
5
+ tags: [workflow, forge]
6
+ ---
7
+
8
+ Show Forge session status:
9
+
10
+ ```bash
11
+ forge status
12
+ ```
13
+
14
+ Summarize `phase`, `planType`, `openspecChange`, and task progress for the user.
15
+
16
+ Reference: forgekit `docs/forge.md`
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: /forge
3
+ description: Forge — start or resume disciplined development (brainstorm → plan → build → review)
4
+ category: Workflow
5
+ tags: [workflow, forge, openspec]
6
+ ---
7
+
8
+ Run the **Forge** workflow for substantial work.
9
+
10
+ Read and follow the Forge skill (`~/.claude/skills/forge/SKILL.md`) and forgekit `docs/forge.md`.
11
+
12
+ 1. Triage — substantial work? (skip only if user said `/forge:skip`)
13
+ 2. Resume from `.forge/active.json` or `forge new <slug>`
14
+ 3. Continue from current `phase` in `session.json`
15
+
16
+ Subcommands: `/forge:brainstorm`, `/forge:plan`, `/forge:apply`, `/forge:build`, `/forge:status`, `/forge:skip`
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * UserPromptSubmit: when the user invokes /forge or /forge:*, inject session context.
4
+ * Requires `forge` on PATH.
5
+ */
6
+
7
+ import { spawnSync } from 'node:child_process';
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+
11
+ const REPO_ROOT = process.env.CLAUDE_PROJECT_DIR || process.cwd();
12
+ const ACTIVE_FILE = path.join(REPO_ROOT, '.forge', 'active.json');
13
+
14
+ function readStdin() {
15
+ return new Promise((resolve) => {
16
+ let data = '';
17
+ if (process.stdin.isTTY) return resolve('');
18
+ process.stdin.setEncoding('utf8');
19
+ process.stdin.on('data', (chunk) => {
20
+ data += chunk;
21
+ });
22
+ process.stdin.on('end', () => resolve(data));
23
+ process.stdin.on('error', () => resolve(data));
24
+ setTimeout(() => resolve(data), 1500);
25
+ });
26
+ }
27
+
28
+ function extractPrompt(raw) {
29
+ if (!raw) return '';
30
+ try {
31
+ const j = JSON.parse(raw);
32
+ return (
33
+ (typeof j?.prompt === 'string' && j.prompt) ||
34
+ (typeof j?.user_prompt === 'string' && j.user_prompt) ||
35
+ (typeof j?.message === 'string' && j.message) ||
36
+ ''
37
+ );
38
+ } catch {
39
+ return raw;
40
+ }
41
+ }
42
+
43
+ function isForgeInvocation(prompt) {
44
+ return /^\s*\/forge(?::|\s|$)/i.test(prompt);
45
+ }
46
+
47
+ function emit(message) {
48
+ process.stdout.write(`<system-reminder>\n${message}\n</system-reminder>\n`);
49
+ }
50
+
51
+ const raw = await readStdin();
52
+ const prompt = extractPrompt(raw);
53
+
54
+ if (!isForgeInvocation(prompt)) {
55
+ process.exit(0);
56
+ }
57
+
58
+ if (!fs.existsSync(ACTIVE_FILE)) {
59
+ emit(
60
+ '[forge] No active session. Bootstrap with `forge new <slug>` then follow the Forge skill.',
61
+ );
62
+ process.exit(0);
63
+ }
64
+
65
+ const r = spawnSync('forge', ['reminder', '--format', 'plain', '--prompt', prompt], {
66
+ encoding: 'utf8',
67
+ cwd: REPO_ROOT,
68
+ shell: true,
69
+ });
70
+
71
+ if (r.status === 0 && r.stdout.trim()) {
72
+ emit(r.stdout.trim());
73
+ }
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Claude Code SessionStart: inject active Forge session when present.
4
+ * Requires `forge` on PATH (npm link @izkac/forgekit or global install).
5
+ */
6
+
7
+ import { spawnSync } from 'node:child_process';
8
+
9
+ const REPO_ROOT = process.env.CLAUDE_PROJECT_DIR || process.cwd();
10
+
11
+ const r = spawnSync('forge', ['reminder', '--format', 'claude-session-start'], {
12
+ encoding: 'utf8',
13
+ cwd: REPO_ROOT,
14
+ shell: true,
15
+ });
16
+
17
+ if (r.status === 0 && r.stdout.trim()) {
18
+ process.stdout.write(r.stdout);
19
+ }
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * UserPromptSubmit: auto-triage substantial work into Forge (Claude Code).
4
+ * Requires `forge` on PATH.
5
+ */
6
+
7
+ import { spawnSync } from 'node:child_process';
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+
11
+ const REPO_ROOT = process.env.CLAUDE_PROJECT_DIR || process.cwd();
12
+ const ACTIVE_FILE = path.join(REPO_ROOT, '.forge', 'active.json');
13
+
14
+ function readStdin() {
15
+ return new Promise((resolve) => {
16
+ let data = '';
17
+ if (process.stdin.isTTY) return resolve('');
18
+ process.stdin.setEncoding('utf8');
19
+ process.stdin.on('data', (chunk) => {
20
+ data += chunk;
21
+ });
22
+ process.stdin.on('end', () => resolve(data));
23
+ process.stdin.on('error', () => resolve(data));
24
+ setTimeout(() => resolve(data), 1500);
25
+ });
26
+ }
27
+
28
+ function extractPrompt(raw) {
29
+ if (!raw) return '';
30
+ try {
31
+ const j = JSON.parse(raw);
32
+ return (
33
+ (typeof j?.prompt === 'string' && j.prompt) ||
34
+ (typeof j?.user_prompt === 'string' && j.user_prompt) ||
35
+ (typeof j?.message === 'string' && j.message) ||
36
+ ''
37
+ );
38
+ } catch {
39
+ return raw;
40
+ }
41
+ }
42
+
43
+ function emit(message) {
44
+ process.stdout.write(`<system-reminder>\n${message}\n</system-reminder>\n`);
45
+ }
46
+
47
+ function runForge(args) {
48
+ return spawnSync('forge', args, {
49
+ encoding: 'utf8',
50
+ cwd: REPO_ROOT,
51
+ shell: true,
52
+ });
53
+ }
54
+
55
+ const raw = await readStdin();
56
+ const prompt = extractPrompt(raw);
57
+ if (!prompt) process.exit(0);
58
+
59
+ const check = runForge(['triage', '--check', prompt]);
60
+ if (check.status !== 0) process.exit(0);
61
+
62
+ const hasSession = fs.existsSync(ACTIVE_FILE);
63
+ const args = ['triage', '--message'];
64
+ if (hasSession) args.push('--has-session');
65
+ args.push(prompt);
66
+
67
+ const msg = runForge(args);
68
+ if (msg.status === 0 && msg.stdout.trim()) {
69
+ if (hasSession) {
70
+ const rem = runForge(['reminder', '--format', 'plain']);
71
+ if (rem.status === 0 && rem.stdout.trim()) {
72
+ emit(`${msg.stdout.trim()}\n\nActive session:\n${rem.stdout.trim()}`);
73
+ process.exit(0);
74
+ }
75
+ }
76
+ emit(msg.stdout.trim());
77
+ }
@@ -0,0 +1,16 @@
1
+ # Forge (thin rule)
2
+
3
+ Full workflow: forgekit `docs/forge.md` · Skill: user-installed **Forge** (`~/.claude/skills/forge/SKILL.md` after `forge install`).
4
+
5
+ **Default:** triage before implementation. Substantial work → **Forge**
6
+ (brainstorm → OpenSpec → subagent TDD implement → review).
7
+
8
+ **Forge = OpenSpec:** after brainstorm, proceed directly to `/opsx:propose` — do not ask for a plan mode. Work too small for OpenSpec should skip Forge (`/forge:skip` or direct execution).
9
+
10
+ **Skip Forge** only when work is trivial OR user sends **`/forge:skip`**.
11
+
12
+ Scratch sessions: `.forge/sessions/` (14-day retention). Active pointer: `.forge/active.json`.
13
+
14
+ CLI: `forge new`, `forge status`, `forge prefs`, `forge models`, `forge phase`, `forge doctor`.
15
+
16
+ Do not edit vendor OpenSpec skills — Forge orchestrates them. Workflow skills are bundled under the Forge skill’s `skills/` folder.
@@ -0,0 +1,10 @@
1
+ # Forge (thin rule)
2
+
3
+ Full workflow: forgekit `docs/forge.md` · Skill: user-installed **Forge** (`~/.codex/skills/forge/SKILL.md` after `forge install`).
4
+
5
+ **Default:** triage before implementation. Substantial work → **Forge**
6
+ (brainstorm → OpenSpec → subagent TDD implement → review).
7
+
8
+ **Forge = OpenSpec:** after brainstorm, proceed directly to OpenSpec propose. Skip with `/forge:skip` or when work is trivial.
9
+
10
+ Scratch: `.forge/` · CLI: `forge new|status|prefs|models|phase|doctor`