@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,176 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Re-apply Forge overlays to vendor OpenSpec skills and opsx:apply commands.
4
+ *
5
+ * forge overlay
6
+ */
7
+
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import { fileURLToPath, pathToFileURL } from 'node:url';
11
+
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+
14
+ export function resolveOverlayDir() {
15
+ const fromEnv = process.env.FORGEKIT_ROOT
16
+ ? path.join(process.env.FORGEKIT_ROOT, 'packages', 'cli', 'src', 'openspec-overlays')
17
+ : null;
18
+ const nextToSrc = path.join(__dirname, 'openspec-overlays');
19
+ for (const c of [fromEnv, nextToSrc].filter(Boolean)) {
20
+ if (c && fs.existsSync(c)) return c;
21
+ }
22
+ throw new Error('openspec-overlays directory not found');
23
+ }
24
+
25
+ const OVERLAY_START = '<!-- forgekit:openspec-overlay:start -->';
26
+ const OVERLAY_END = '<!-- forgekit:openspec-overlay:end -->';
27
+ const LEGACY_START = '<!-- janus-forge:openspec-overlay:start -->';
28
+ const LEGACY_END = '<!-- janus-forge:openspec-overlay:end -->';
29
+ const STEP_MARKER = 'REQUIRED (Forge):';
30
+ const LEGACY_STEP_MARKER = 'REQUIRED (Janus Forge):';
31
+
32
+ const AGENT_PATHS = {
33
+ cursor: {
34
+ skillRoot: '.cursor/skills/forge',
35
+ opsxApply: '.cursor/commands/opsx-apply.md',
36
+ applySkill: '.cursor/skills/openspec-apply-change/SKILL.md',
37
+ },
38
+ claude: {
39
+ skillRoot: '.claude/skills/forge',
40
+ opsxApply: '.claude/commands/opsx/apply.md',
41
+ applySkill: '.claude/skills/openspec-apply-change/SKILL.md',
42
+ },
43
+ codex: {
44
+ skillRoot: '.codex/skills/forge',
45
+ opsxApply: null,
46
+ applySkill: '.codex/skills/openspec-apply-change/SKILL.md',
47
+ },
48
+ };
49
+
50
+ function readOverlay(overlayDir, name) {
51
+ return fs.readFileSync(path.join(overlayDir, name), 'utf8');
52
+ }
53
+
54
+ export function renderOverlay(template, agentKey) {
55
+ const root = AGENT_PATHS[agentKey].skillRoot;
56
+ return template
57
+ .replaceAll('{{PHASES_IMPLEMENT}}', `${root}/phases/implement.md`)
58
+ .replaceAll('{{PHASES_VERIFY}}', `${root}/phases/verify.md`)
59
+ .replaceAll('{{PHASES_REVIEW}}', `${root}/phases/review.md`)
60
+ .replaceAll('{{SKILL_ROOT}}', root);
61
+ }
62
+
63
+ export function stripOverlayBlock(content) {
64
+ let out = content;
65
+ for (const [start, end] of [
66
+ [OVERLAY_START, OVERLAY_END],
67
+ [LEGACY_START, LEGACY_END],
68
+ ]) {
69
+ const blockRe = new RegExp(
70
+ `(\\r?\\n---\\r?\\n\\r?\\n)?${escapeRegExp(start)}[\\s\\S]*?${escapeRegExp(end)}\\r?\\n?`,
71
+ 'g',
72
+ );
73
+ out = out.replace(blockRe, '\n');
74
+ }
75
+ return `${out.replace(/\n{3,}/g, '\n\n').trimEnd()}\n`;
76
+ }
77
+
78
+ function escapeRegExp(s) {
79
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
80
+ }
81
+
82
+ export function applySkillFooter(content, agentKey, overlayDir = resolveOverlayDir()) {
83
+ const footer = renderOverlay(
84
+ readOverlay(overlayDir, 'openspec-apply-change-footer.md'),
85
+ agentKey,
86
+ );
87
+ let out = stripOverlayBlock(content);
88
+ if (!out.endsWith('\n')) out += '\n';
89
+ return out + footer;
90
+ }
91
+
92
+ const STEP6_RE =
93
+ /(6\. \*\*Implement tasks \(loop until done or blocked\)\*\*\r?\n\r?\n)([\s\S]*?)(\r?\n\r?\n \*\*Pause if:\*\*)/;
94
+
95
+ export function patchOpsxApplyContent(content, agentKey, overlayDir = resolveOverlayDir()) {
96
+ if (!STEP6_RE.test(content)) {
97
+ return { content, status: 'no-match' };
98
+ }
99
+
100
+ const implementStep = renderOverlay(
101
+ readOverlay(overlayDir, 'opsx-apply-implement-step.md'),
102
+ agentKey,
103
+ );
104
+ let out = content.replace(STEP6_RE, `$1${implementStep}$3`);
105
+
106
+ const completionLine = renderOverlay(
107
+ readOverlay(overlayDir, 'opsx-apply-completion-step.md'),
108
+ agentKey,
109
+ ).trimEnd();
110
+
111
+ if (/ - If all done:.*\r?\n/.test(out)) {
112
+ out = out.replace(/ - If all done:.*\r?\n/, `${completionLine}\r\n`);
113
+ } else {
114
+ out = out.replace(
115
+ /(7\. \*\*On completion or pause, show status\*\*\r?\n\r?\n Display:\r?\n)/,
116
+ `$1${completionLine}\r\n`,
117
+ );
118
+ }
119
+
120
+ const already =
121
+ content.includes(STEP_MARKER) || content.includes(LEGACY_STEP_MARKER);
122
+ const status = already ? 're-patched' : 'patched';
123
+ return { content: out, status };
124
+ }
125
+
126
+ function patchFile(relPath, transform, label) {
127
+ const abs = path.join(process.cwd(), relPath);
128
+ if (!fs.existsSync(abs)) {
129
+ process.stdout.write(`skip (missing): ${relPath}\n`);
130
+ return 'missing';
131
+ }
132
+ const before = fs.readFileSync(abs, 'utf8');
133
+ const after = transform(before);
134
+ if (after === before) {
135
+ process.stdout.write(`unchanged: ${relPath}\n`);
136
+ return 'unchanged';
137
+ }
138
+ fs.writeFileSync(abs, after, 'utf8');
139
+ process.stdout.write(`${label}: ${relPath}\n`);
140
+ return label;
141
+ }
142
+
143
+ function main() {
144
+ const overlayDir = resolveOverlayDir();
145
+
146
+ for (const [agentKey, paths] of Object.entries(AGENT_PATHS)) {
147
+ if (paths.opsxApply) {
148
+ patchFile(
149
+ paths.opsxApply,
150
+ (content) => patchOpsxApplyContent(content, agentKey, overlayDir).content,
151
+ 'patched-opsx-apply',
152
+ );
153
+ }
154
+
155
+ patchFile(
156
+ paths.applySkill,
157
+ (content) => applySkillFooter(content, agentKey, overlayDir),
158
+ 'patched-skill-footer',
159
+ );
160
+ }
161
+
162
+ process.stdout.write('\nDone. Forge-owned /forge:apply commands are not modified.\n');
163
+ process.stdout.write('After OpenSpec upgrade: forge overlay\n');
164
+ }
165
+
166
+ const isDirect =
167
+ process.argv[1] && pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url;
168
+
169
+ if (isDirect) {
170
+ try {
171
+ main();
172
+ } catch (err) {
173
+ process.stderr.write(`${err.message || err}\n`);
174
+ process.exit(1);
175
+ }
176
+ }
@@ -0,0 +1,62 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {
4
+ applySkillFooter,
5
+ patchOpsxApplyContent,
6
+ stripOverlayBlock,
7
+ } from './vendor-openspec-overlays.mjs';
8
+
9
+ const VANILLA = `---
10
+ name: test
11
+ ---
12
+
13
+ 6. **Implement tasks (loop until done or blocked)**
14
+
15
+ For each pending task:
16
+ - Show which task is being worked on
17
+ - Make the code changes required
18
+ - Keep changes minimal and focused
19
+ - Mark task complete in the tasks file: \`- [ ]\` → \`- [x]\`
20
+ - Continue to next task
21
+
22
+ **Pause if:**
23
+ - Task is unclear
24
+
25
+ 7. **On completion or pause, show status**
26
+
27
+ Display:
28
+ - Tasks completed this session
29
+ - Overall progress: "N/M tasks complete"
30
+ - If all done: suggest archive
31
+ `;
32
+
33
+ test('patchOpsxApplyContent injects Forge implement step', () => {
34
+ const { content, status } = patchOpsxApplyContent(VANILLA, 'cursor');
35
+ assert.equal(status, 'patched');
36
+ assert.match(content, /REQUIRED \(Forge\):/);
37
+ assert.match(content, /\.cursor\/skills\/forge\/phases\/implement\.md/);
38
+ assert.match(content, /Dispatch \*\*implementer\*\* subagent/);
39
+ assert.doesNotMatch(content, /Make the code changes required/);
40
+ });
41
+
42
+ test('patchOpsxApplyContent is idempotent on re-run', () => {
43
+ const first = patchOpsxApplyContent(VANILLA, 'claude');
44
+ const second = patchOpsxApplyContent(first.content, 'claude');
45
+ assert.equal(second.status, 're-patched');
46
+ assert.match(second.content, /\.claude\/skills\/forge\/phases\/verify\.md/);
47
+ });
48
+
49
+ test('applySkillFooter adds overlay block once', () => {
50
+ const skill = '---\nname: openspec-apply-change\n---\n\nBody.\n';
51
+ const once = applySkillFooter(skill, 'codex');
52
+ assert.match(once, /forgekit:openspec-overlay:start/);
53
+ assert.match(once, /\/forge:apply/);
54
+ const twice = applySkillFooter(once, 'codex');
55
+ assert.equal((twice.match(/## Forge overlay/g) || []).length, 1);
56
+ });
57
+
58
+ test('stripOverlayBlock removes footer', () => {
59
+ const withFooter = applySkillFooter('body\n', 'cursor');
60
+ const stripped = stripOverlayBlock(withFooter);
61
+ assert.doesNotMatch(stripped, /forgekit:openspec-overlay/);
62
+ });
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: archive-to-adr
3
+ description: >-
4
+ Create or update Architecture Decision Records (ADRs) from an archived OpenSpec
5
+ change. Fire after archive-shaped Bash completes (hooks wrap `openspec archive`
6
+ plus `mv` into dated `openspec/changes/archive/…`). Also use when sessionStart
7
+ reports pending archives, the user says `/archive-to-adr`, or they ask to
8
+ generate ADRs from an archive. Skip entirely when the project has ADRs disabled
9
+ (`.forge/config.json` → `adr.enabled: false`).
10
+ disable-model-invocation: false
11
+ ---
12
+
13
+ # Archive to ADR
14
+
15
+ Turn a **completed and archived** OpenSpec change into one or more ADRs, following
16
+ the project's decisions doc (scaffolded as `docs/decisions.md` by default via
17
+ `forge init --adr`).
18
+
19
+ This skill is **decoupled** from OpenSpec itself: archive hooks inject a reminder
20
+ after successful archive-shaped shells; you judge whether an ADR is warranted.
21
+
22
+ ## Project config
23
+
24
+ Read **`.forge/config.json`** at the repo root (written by `forge init` / optional
25
+ `forgekit install` project scaffold):
26
+
27
+ ```json
28
+ {
29
+ "adr": {
30
+ "enabled": true,
31
+ "dir": "docs/adr",
32
+ "decisionsDoc": "docs/decisions.md"
33
+ }
34
+ }
35
+ ```
36
+
37
+ | Field | Default | Meaning |
38
+ |-------|---------|---------|
39
+ | `adr.enabled` | `true` if file missing and `docs/adr/` exists; else follow install | When `false`, do **not** run this skill — no ADR, no "No ADR" stamp |
40
+ | `adr.dir` | `docs/adr` | Directory for `NNNN-short-topic.md` + status `README.md` |
41
+ | `adr.decisionsDoc` | sibling `decisions.md` of `adr.dir` | Process / template (when to write, format, hooks) |
42
+ | `plan.engine` | `openspec` | `specs` = built-in engine; archives live under `<plan.dir>/changes/archive/` instead of `openspec/changes/archive/` |
43
+
44
+ Below, **`{adrDir}`** and **`{decisionsDoc}`** mean those configured paths, and
45
+ **`{archiveRoot}`** means `openspec/changes/archive` (OpenSpec engine) or
46
+ `<plan.dir>/changes/archive` (specs engine, default `specs/changes/archive`).
47
+
48
+ If `adr.enabled` is `false`, stop and tell the user ADRs are disabled for this project.
49
+
50
+ ## When to skip entirely (ADRs enabled)
51
+
52
+ If the change is a bug fix, copy tweak, docs-only edit, or refactor with no
53
+ architectural choice, **do not** create an ADR. Instead add this **single line**
54
+ to the archived `proposal.md`:
55
+
56
+ ```text
57
+ No ADR — non-architectural change
58
+ ```
59
+
60
+ That silences the session-start pending-ADR backstop.
61
+
62
+ ## Input
63
+
64
+ **Required:** the archive directory path, e.g.
65
+ `{archiveRoot}/2026-05-15-payment-add-service/`.
66
+
67
+ If the user only gives the change name, resolve it: list `{archiveRoot}/`
68
+ and pick the matching dated folder.
69
+
70
+ ## Steps
71
+
72
+ 1. **Confirm ADRs are enabled** — read `.forge/config.json` as above.
73
+
74
+ 2. **Read the archived artifacts**
75
+ - `proposal.md` — Why, What Changes, Capabilities, Impact
76
+ - `design.md` — Context, Decisions, Risks, Migration
77
+ - `specs/**/*.md` in the archive (capability deltas)
78
+
79
+ 3. **Apply the ADR gate** (`{decisionsDoc}` § "When to write an ADR")
80
+ - Write an ADR when the change establishes/revises a **boundary**, picks one
81
+ approach over a **real** alternative, introduces a **constraint** future code
82
+ must respect, picks a **vendor/protocol/library** that is expensive to swap,
83
+ or codifies a **repo-wide** convention.
84
+ - Skip when it's purely implementation detail inside an existing decision.
85
+
86
+ 4. **Pick the next ADR number**
87
+ - List `{adrDir}/*.md` (four-digit prefix pattern `NNNN-*.md`).
88
+ - Use **the next sequential integer**; never reuse a number.
89
+ - If multiple distinct architectural decisions warrant separate ADRs in one
90
+ archive, create multiple files (`NNNN-…`, `NNNN+1-…`), each with one sharp decision.
91
+
92
+ 5. **Author the ADR file** at `{adrDir}/NNNN-short-topic.md` using the **exact
93
+ section structure** from `{decisionsDoc}`:
94
+ - Title: `# NNNN. <Short, decision-shaped title>`
95
+ - Frontmatter lines: **Status**, **Date**, **Area**, **Related** (link the
96
+ archive path, sibling ADRs)
97
+ - Body: Context, Decision, Alternatives considered, Consequences
98
+ (Positive / Negative / Neutral), References
99
+
100
+ Keep it terse (target ~80–200 lines total across all new ADRs for the change).
101
+ Link to the archive for forensic detail; don't paste the whole design.
102
+
103
+ 6. **Update the status index** `{adrDir}/README.md` — add or amend the table
104
+ row(s). If `README.md` is missing, create it with the table scaffold from
105
+ `{decisionsDoc}`.
106
+
107
+ 7. **Cross-reference from the archive**
108
+ - In `{archiveRoot}/<dated-change>/proposal.md`, add (or extend):
109
+
110
+ ```markdown
111
+ ## Decision record
112
+
113
+ This change is recorded as ADR-NNNN ({adrDir}/NNNN-short-topic.md).
114
+ ```
115
+
116
+ Use `ADR-NNNN` text so pending-ADR hooks (`grep 'ADR-[0-9]'`) recognize the link.
117
+
118
+ 8. **If capability specs were promoted** during archive: consider a one-line
119
+ pointer in the ADR **References** to `openspec/specs/<capability>/spec.md`
120
+ (optional but valuable).
121
+
122
+ ## Output
123
+
124
+ - Paths of created/updated `{adrDir}/*.md`
125
+ - Confirmation `{adrDir}/README.md` was updated
126
+ - Confirmation the archived `proposal.md` now references `ADR-NNNN`
127
+ - One-sentence summary per ADR written
128
+
129
+ ## Guardrails
130
+
131
+ - Naming: **`NNNN-short-topic.md`**, not date-only filenames.
132
+ - **Never** add `{adrDir}/` to `.cursorindexignore` (or equivalent ignore that
133
+ blocks agent retrieval).
134
+ - Don't duplicate content that belongs only in OpenSpec — the archive remains
135
+ the verbose record; the ADR is the distilled "why."
136
+ - If unsure whether to write an ADR, re-read the decisions gate; when still
137
+ ambiguous, ask the user once rather than inventing ceremony.
138
+
139
+ ## Relationship to hooks
140
+
141
+ Project hooks (from `forge init --adr`) may:
142
+
143
+ - Remind agents to run **archive-to-adr** after `openspec archive` / an archive
144
+ move (either engine)
145
+ - At session start, list archives (both `openspec/changes/archive/` and
146
+ `specs/changes/archive/`) whose `proposal.md` lacks `ADR-*` **and** lacks
147
+ the `No ADR — non-architectural change` stamp
148
+
149
+ Neither hook writes ADR files; **this skill** does.
@@ -0,0 +1,136 @@
1
+ ---
2
+ name: forge
3
+ description: >-
4
+ Forge — self-contained disciplined development workflow. Triage substantial work,
5
+ brainstorm, tracked plan (OpenSpec or built-in specs engine), subagent-driven TDD
6
+ implementation, verify, review, and finish.
7
+ Use when building features, fixing non-trivial bugs, or when the user invokes /forge.
8
+ Skip only when user says /forge:skip or work is trivial.
9
+ disable-model-invocation: false
10
+ ---
11
+
12
+ # Forge
13
+
14
+ Spec-tracked development pipeline. Planning engine is per-project
15
+ (`.forge/config.json` → `plan.engine`): **OpenSpec** (vendor CLI) or the
16
+ **built-in specs engine** (`specs/changes/`, same layout). **Self-contained** —
17
+ all workflow skills live under `./skills/` (vendored from Superpowers MIT; see
18
+ [skills/NOTICE.md](./skills/NOTICE.md)).
19
+
20
+ Full reference: forgekit `docs/forge.md` (shipped with this skill’s source repo).
21
+
22
+ **Announce at start:** "Using Forge for this work." Include effective pace from
23
+ `forge status` (e.g. `Pace: auto → brisk (…)`) — see [references/pace.md](./references/pace.md).
24
+
25
+ ## Instruction priority
26
+
27
+ 1. User explicit instructions (including `/forge:skip` and pace overrides)
28
+ 2. This skill + `./phases/`, `./references/`, and `./skills/`
29
+ 3. Project OpenSpec skills (`openspec-propose`, `openspec-apply-change`) — do not edit vendor copies (OpenSpec-engine projects only)
30
+
31
+ ## Pace (thoroughness)
32
+
33
+ Checkout-local prefs control review/verify ceremony. Default pace is **`auto`**
34
+ (resolves once per session from risk signals).
35
+
36
+ ```bash
37
+ forge prefs # print effective pace (does NOT write a file)
38
+ forge prefs brisk # WRITE .forge/preferences.local.json
39
+ forge prefs --session-set lite
40
+ forge models # print billing (does NOT write); set: included|metered
41
+ forge doctor # plan-engine readiness (OpenSpec CLI or specs/ layout)
42
+ ```
43
+
44
+ Honor [references/pace.md](./references/pace.md) in implement / verify / review.
45
+ Hard floor: money/auth/contracts/migrations always get per-task review (even under `standard` mid-group / `brisk` / `lite`).
46
+ Local overlays: forgekit `docs/forge.md` § Checkout-local overrides.
47
+
48
+ ## Bundled skills
49
+
50
+ | Skill | Path | When |
51
+ | ----- | ---- | ---- |
52
+ | Brainstorming | [skills/brainstorming/SKILL.md](./skills/brainstorming/SKILL.md) | brainstorm phase |
53
+ | TDD | [skills/test-driven-development/SKILL.md](./skills/test-driven-development/SKILL.md) | every implement task |
54
+ | Subagent-driven dev | [skills/subagent-driven-development/SKILL.md](./skills/subagent-driven-development/SKILL.md) | implement phase |
55
+ | Systematic debugging | [skills/systematic-debugging/SKILL.md](./skills/systematic-debugging/SKILL.md) | blockers / test failures |
56
+ | Verification | [skills/verification-before-completion/SKILL.md](./skills/verification-before-completion/SKILL.md) | verify phase |
57
+ | Code review | [skills/requesting-code-review/SKILL.md](./skills/requesting-code-review/SKILL.md) | review phase |
58
+
59
+ ## Step 0 — Triage (default)
60
+
61
+ Before coding on any non-trivial request, run triage per
62
+ [references/substantial-work.md](./references/substantial-work.md).
63
+
64
+ - **Substantial (tracked-change-worthy)** → continue Forge (bootstrap session if needed)
65
+ - **Too small for a tracked change** → execute directly, no session
66
+ - **`/forge:skip`** → mark session `phase: skipped` if one exists; execute directly
67
+
68
+ Bootstrap session when entering Forge:
69
+
70
+ ```bash
71
+ forge new <kebab-slug>
72
+ # optional: forge new <slug> --signal "add stripe refund"
73
+ ```
74
+
75
+ `forge new` resolves pace (default `auto`) onto the session and runs the
76
+ plan-engine doctor in warn-only mode (missing OpenSpec CLI does not block
77
+ session creation; specs-engine projects skip the CLI check).
78
+
79
+ Resume: read `.forge/active.json` → `forge status`.
80
+
81
+ Update phase as you progress:
82
+
83
+ ```bash
84
+ forge phase <phase> [--plan-type openspec|specs] [--openspec <change>]
85
+ ```
86
+
87
+ Valid phases: `triage`, `brainstorm`, `plan`, `implement`, `verify`, `review`, `finish`, `done`, `skipped`.
88
+
89
+ ## Phase flow
90
+
91
+ | Phase | Action |
92
+ | ----- | ------ |
93
+ | brainstorm | [phases/brainstorm.md](./phases/brainstorm.md) → **skills/brainstorming** |
94
+ | plan | [references/plan-routing.md](./references/plan-routing.md) → engine from `.forge/config.json`: **OpenSpec** ([plan-openspec.md](./phases/plan-openspec.md)) or **specs** ([plan-specs.md](./phases/plan-specs.md)) |
95
+ | implement | [phases/implement.md](./phases/implement.md) → **subagent-driven-development** + **TDD** |
96
+ | verify | [phases/verify.md](./phases/verify.md) → **verification-before-completion** |
97
+ | review | [phases/review.md](./phases/review.md) → **requesting-code-review** |
98
+ | finish | [phases/finish.md](./phases/finish.md) |
99
+
100
+ <HARD-GATE>
101
+ Do NOT write implementation code during brainstorm or plan phases until the user approves the tracked change (OpenSpec or specs).
102
+ </HARD-GATE>
103
+
104
+ <HARD-GATE>
105
+ Subagent dispatch: NEVER pass a model slug you picked yourself (including any from the host's model list). Run `forge resolve-model --tier <fast|standard|capable>` and honor its JSON — omit the `model` parameter when `omitModel` is true, else pass `model` exactly. Metered/API models only on explicit user request. This applies to retries and fallbacks too: if a dispatch fails, re-resolve — do not hand-pick a replacement slug.
106
+ </HARD-GATE>
107
+
108
+ ## Session artefacts
109
+
110
+ Layout: [references/forge-layout.md](./references/forge-layout.md)
111
+
112
+ Testing: [references/test-strategy.md](./references/test-strategy.md) — tier 1 scoped TDD per task, tier 2 narrow evidence per task, tier 3 full workspace once at verify.
113
+
114
+ ## Guardrails (every phase)
115
+
116
+ - No autonomous `git commit` / push unless the user explicitly asks
117
+ - Tests required for behavior changes
118
+ - Trace ecosystem consumers when contracts change
119
+ - Honor `openspec/config.yaml` prefixes when the project uses them (OpenSpec engine)
120
+ - **Runtime integrity** — [references/runtime-integrity.md](./references/runtime-integrity.md): **spine.json mandatory every change** (rows or `notApplicable` — not keyword-gated); no stubs / false success; capability specs beat narrow task wording; every claimed capability needs a named production caller; product-loop when spine has rows (or BLOCKED); deferred wiring only via `forge defer` — `forge phase done` mechanically refuses on `forge integrity-check` failures
121
+
122
+ ## Agent surfaces
123
+
124
+ | Agent | Skill (after `forgekit install`) | Project wiring (`forge init`) |
125
+ | ----- | ----------------------------- | ----------------------------- |
126
+ | **Cursor** | `~/.cursor/skills/forge/` | commands, `forge.mdc`, SessionStart hook |
127
+ | **Claude Code** | `~/.claude/skills/forge/` | commands, `forge.md`, SessionStart + prompt hooks |
128
+ | **Codex CLI** | `~/.codex/skills/forge/` | thin rule |
129
+
130
+ **Planning (all agents):** after brainstorm, proceed directly to the configured engine — no plan-mode prompt. See [references/plan-routing.md](./references/plan-routing.md). Hooks remind agents to run the propose flow when `planType` is unset.
131
+
132
+ **Distribute:** edit `skills/forge/` in forgekit, then `forgekit install --skills forge --force` on each machine. The bundled skills are a maintained fork (see [skills/NOTICE.md](./skills/NOTICE.md)) — do not re-vendor from Superpowers.
133
+
134
+ ## Do not edit vendor OpenSpec skills
135
+
136
+ OpenSpec vendor skills upgrade in place. Forge behaviour lives in this tree and forgekit `docs/forge.md`. Re-apply vendor patches with `forge overlay` after OpenSpec upgrades.
@@ -0,0 +1,23 @@
1
+ # Brainstorm phase
2
+
3
+ Read and follow [../skills/brainstorming/SKILL.md](../skills/brainstorming/SKILL.md) in full.
4
+
5
+ **Pace:** Honor `brainstorm.depth` from [../references/pace.md](../references/pace.md) / `forge status` — `full` (default skill), `short` (≤2–3 approaches), or `minimal` (confirm intent + one approach when design is obvious).
6
+
7
+ ## Terminal state
8
+
9
+ After user approves the design:
10
+
11
+ 1. Save to `.forge/sessions/<id>/brainstorm/notes.md` and `decisions.md`
12
+ 2. Read [../references/plan-routing.md](../references/plan-routing.md) and **proceed to OpenSpec propose** — do not ask for a plan mode
13
+ 3. Follow [plan-openspec.md](./plan-openspec.md) — **not** implementation until OpenSpec artefacts are approved
14
+
15
+ ```bash
16
+ forge phase brainstorm
17
+ # after OpenSpec propose:
18
+ forge phase plan --plan-type openspec --openspec <name>
19
+ ```
20
+
21
+ <HARD-GATE>
22
+ Do NOT invoke implement phase or write production code until OpenSpec plan phase completes and user approves.
23
+ </HARD-GATE>
@@ -0,0 +1,87 @@
1
+ # Finish phase
2
+
3
+ Before marking done, integrity must pass (or the user must approve an incomplete finish):
4
+
5
+ ```bash
6
+ forge integrity-check # spine + deferrals + product-loop / BLOCKED
7
+ forge score # preview L2 scorecard (optional)
8
+ forge phase done # runs integrity checks + writes scorecard.md/json
9
+ # escape hatch only with an honest reason:
10
+ # forge phase done --allow-incomplete "E2E blocked: no Compose in this environment"
11
+ ```
12
+
13
+ `forge phase done|finish` always writes `.forge/sessions/<id>/scorecard.md` (and
14
+ `.json`) — an L2 grade of session artifacts. Answer the **human ship-check**
15
+ questions in that file for platform/async work (L3). See [usage.md](../../../docs/usage.md)
16
+ § Session success.
17
+
18
+ ## OpenSpec path (`planType: openspec`)
19
+
20
+ 1. Confirm all tasks complete in `tasks.md`.
21
+ 2. User runs or approves `/opsx:archive` / `openspec archive`.
22
+ 3. **ADR follow-up (optional):** if `.forge/config.json` has `adr.enabled: true`
23
+ (or the project uses ADRs), follow the **`archive-to-adr`** skill using
24
+ `adr.dir` / `adr.decisionsDoc`. If ADRs are disabled, skip.
25
+ 4. End with **Suggested commit** block (display only — do not commit).
26
+
27
+ ```bash
28
+ forge phase done
29
+ forge cleanup
30
+ ```
31
+
32
+ ## Specs path (`planType: specs`)
33
+
34
+ 1. Confirm all tasks complete in `<specsDir>/changes/<name>/tasks.md`.
35
+ 2. **Archive** (with user approval) — prefer the CLI:
36
+
37
+ ```bash
38
+ forge change archive <name>
39
+ # → <specsDir>/changes/archive/YYYY-MM-DD-<name>
40
+ ```
41
+
42
+ Or move manually:
43
+
44
+ ```bash
45
+ git mv <specsDir>/changes/<name> <specsDir>/changes/archive/<YYYY-MM-DD>-<name>
46
+ ```
47
+
48
+ (plain `mv` if the dir is untracked).
49
+ 3. **ADR follow-up (optional):** same rule as OpenSpec — if `adr.enabled`,
50
+ follow **`archive-to-adr`** on the archived change; otherwise skip.
51
+ 4. End with **Suggested commit** block (display only — do not commit).
52
+
53
+ ```bash
54
+ forge phase done
55
+ forge cleanup
56
+ ```
57
+
58
+ ## Throwaway path (`planType: throwaway`)
59
+
60
+ 1. Confirm all tasks in `plan.md` checked off.
61
+ 2. Summarize what shipped.
62
+ 3. Mark session done and cleanup:
63
+
64
+ ```bash
65
+ forge phase done
66
+ forge cleanup
67
+ ```
68
+
69
+ ## Direct path (`planType: direct`)
70
+
71
+ 1. Confirm implementation matches brainstorm `notes.md` / `decisions.md`.
72
+ 2. Summarize what shipped.
73
+ 3. Mark session done and cleanup:
74
+
75
+ ```bash
76
+ forge phase done
77
+ forge cleanup
78
+ ```
79
+
80
+ ## Skipped path (`/forge:skip`)
81
+
82
+ Session already at `phase: skipped`. No finish steps.
83
+
84
+ ## Hand-off
85
+
86
+ Leave implementation files staged/unstaged per user preference. Never commit unless
87
+ explicitly asked (project git policy).