@guidobuilds/forge-ai 0.1.0 → 0.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 CHANGED
@@ -77,7 +77,7 @@ The same operating model is shared across all supported agents so the workflow s
77
77
  The primary installer is the npm CLI:
78
78
 
79
79
  ```sh
80
- npx forge-ai install
80
+ npx @guidobuilds/forge-ai install
81
81
  ```
82
82
 
83
83
  The installer prompts for the target agent platform and whether Forge should be installed globally for your user or locally for the current project.
@@ -85,25 +85,25 @@ The installer prompts for the target agent platform and whether Forge should be
85
85
  To update an existing install:
86
86
 
87
87
  ```sh
88
- npx forge-ai update
88
+ npx @guidobuilds/forge-ai update
89
89
  ```
90
90
 
91
91
  For non-interactive environments:
92
92
 
93
93
  ```sh
94
- npx forge-ai install --platform all --scope user --yes
94
+ npx @guidobuilds/forge-ai install --platform all --scope user --yes
95
95
  ```
96
96
 
97
97
  Preview the files without writing them:
98
98
 
99
99
  ```sh
100
- npx forge-ai install --platform all --scope user --dry-run
100
+ npx @guidobuilds/forge-ai install --platform all --scope user --dry-run
101
101
  ```
102
102
 
103
103
  Validate a local Forge source tree:
104
104
 
105
105
  ```sh
106
- npx forge-ai validate --source .
106
+ npx @guidobuilds/forge-ai validate --source .
107
107
  ```
108
108
 
109
109
  ## Local Development
@@ -127,11 +127,13 @@ node bin/forge-ai.mjs install --source . --platform all --scope project --dry-ru
127
127
  Run the npm updater:
128
128
 
129
129
  ```sh
130
- npx forge-ai update
130
+ npx @guidobuilds/forge-ai update
131
131
  ```
132
132
 
133
133
  Forge replaces its managed agent and skill definitions in your supported agent configuration directories.
134
134
 
135
+ Forge records installed files in manifests under `~/.forge-ai/` so updates can safely remove files that are no longer bundled. `update` prunes stale managed files by default only when the current file still matches the recorded checksum; use `--no-prune` to keep stale managed files. `--dry-run` previews writes and deletes without changing files or manifests.
136
+
135
137
  ## Uninstalling
136
138
 
137
139
  Remove Forge from the agent configuration directories for OpenCode, Codex, or Claude Code by deleting the installed Forge agent and skill entries.
package/dist/src/cli.js CHANGED
@@ -2,9 +2,11 @@
2
2
  import * as p from '@clack/prompts';
3
3
  import pc from 'picocolors';
4
4
  import { readFileSync } from 'node:fs';
5
+ import os from 'node:os';
5
6
  import path from 'node:path';
6
7
  import { fileURLToPath } from 'node:url';
7
8
  import { formatDiagnostic, hasErrors } from './diagnostics.js';
9
+ import { buildManifest, classifyPruneEntries, loadManifest, pruneEntries, resolveManifestLocation, saveManifest, staleEntries } from './manifest.js';
8
10
  import { buildWritePlan, parsePlatform, parseScope } from './processor.js';
9
11
  import { writeOutputs } from './writer.js';
10
12
  export async function main(argv = process.argv.slice(2), promptIO = {}) {
@@ -44,7 +46,9 @@ export async function main(argv = process.argv.slice(2), promptIO = {}) {
44
46
  return 1;
45
47
  }
46
48
  }
47
- let plan = await buildWritePlan({ source: options.source, platform: options.platform, scope: options.scope, checkCollisions: install && !options.dryRun, force: options.force });
49
+ const cwd = process.cwd();
50
+ const home = resolveHome(promptIO);
51
+ let plan = await buildWritePlan({ source: options.source, platform: options.platform, scope: options.scope, cwd, home, checkCollisions: install && !options.dryRun, force: options.force });
48
52
  if (install && !options.dryRun && !options.force && canOfferUpdate(plan.diagnostics)) {
49
53
  const accepted = await promptForUpdate(plan, promptIO);
50
54
  if (accepted === undefined) {
@@ -54,10 +58,18 @@ export async function main(argv = process.argv.slice(2), promptIO = {}) {
54
58
  }
55
59
  if (accepted) {
56
60
  options.force = true;
57
- plan = await buildWritePlan({ source: options.source, platform: options.platform, scope: options.scope, checkCollisions: true, force: true });
61
+ plan = await buildWritePlan({ source: options.source, platform: options.platform, scope: options.scope, cwd, home, checkCollisions: true, force: true });
58
62
  }
59
63
  }
60
- printPlan(command, plan.sourceCount, plan.files, plan.diagnostics);
64
+ let prunePlan = { deletable: [], skipped: [] };
65
+ let manifestLocation;
66
+ if (install) {
67
+ manifestLocation = await resolveManifestLocation(options.scope, cwd, home);
68
+ const oldManifest = await loadManifest(manifestLocation.manifestPath);
69
+ if (command === 'update' && options.prune)
70
+ prunePlan = await classifyPruneEntries(staleEntries(oldManifest, plan.files));
71
+ }
72
+ printPlan(command, plan.sourceCount, plan.files, plan.diagnostics, prunePlan);
61
73
  if (hasErrors(plan.diagnostics)) {
62
74
  if (interactive)
63
75
  p.outro(pc.red('Forge was not installed.'), clackIO(promptIO));
@@ -69,6 +81,9 @@ export async function main(argv = process.argv.slice(2), promptIO = {}) {
69
81
  spinner.start(options.force ? 'Updating Forge files' : 'Installing Forge files');
70
82
  try {
71
83
  await writeOutputs(plan.files);
84
+ if (command === 'update' && options.prune)
85
+ await pruneEntries(prunePlan.deletable);
86
+ await saveManifest(manifestLocation.manifestPath, buildManifest(manifestLocation, plan.files));
72
87
  spinner.stop(`Wrote ${plan.files.length} file(s).`);
73
88
  }
74
89
  catch (error) {
@@ -78,7 +93,13 @@ export async function main(argv = process.argv.slice(2), promptIO = {}) {
78
93
  }
79
94
  else {
80
95
  await writeOutputs(plan.files);
96
+ if (command === 'update' && options.prune)
97
+ await pruneEntries(prunePlan.deletable);
98
+ await saveManifest(manifestLocation.manifestPath, buildManifest(manifestLocation, plan.files));
81
99
  console.log(`Wrote ${plan.files.length} file(s).`);
100
+ if (command === 'update' && options.prune && prunePlan.deletable.length > 0)
101
+ console.log(`Deleted ${prunePlan.deletable.length} stale file(s).`);
102
+ console.log(`Updated manifest ${manifestLocation.manifestPath}.`);
82
103
  }
83
104
  }
84
105
  else if (install && interactive) {
@@ -90,13 +111,15 @@ export async function main(argv = process.argv.slice(2), promptIO = {}) {
90
111
  return 0;
91
112
  }
92
113
  function parseArgs(argv) {
93
- const options = { command: argv[0], platform: 'all', scope: 'user', source: '.', dryRun: false, force: false, yes: false, platformExplicit: false, scopeExplicit: false, sourceExplicit: false };
114
+ const options = { command: argv[0], platform: 'all', scope: 'user', source: '.', dryRun: false, force: false, prune: true, yes: false, platformExplicit: false, scopeExplicit: false, sourceExplicit: false };
94
115
  for (let index = 1; index < argv.length; index += 1) {
95
116
  const arg = argv[index];
96
117
  if (arg === '--dry-run')
97
118
  options.dryRun = true;
98
119
  else if (arg === '--force')
99
120
  options.force = true;
121
+ else if (arg === '--no-prune')
122
+ options.prune = false;
100
123
  else if (arg === '--yes' || arg === '-y')
101
124
  options.yes = true;
102
125
  else if (arg === '--platform') {
@@ -127,6 +150,8 @@ function parseArgs(argv) {
127
150
  }
128
151
  }
129
152
  const command = normalizeCommand(options.command);
153
+ if (command !== 'update' && !options.prune)
154
+ return { error: '--no-prune is only accepted for update' };
130
155
  if (command === 'validate' && (options.dryRun || options.force || options.yes || options.scopeExplicit))
131
156
  return { error: 'validate only accepts --platform and --source' };
132
157
  return { options };
@@ -209,6 +234,9 @@ function isInteractivePrompt(promptIO) {
209
234
  function clackIO(promptIO) {
210
235
  return { input: promptIO.input, output: promptIO.output };
211
236
  }
237
+ function resolveHome(promptIO) {
238
+ return promptIO.env?.HOME || os.homedir();
239
+ }
212
240
  function bundledSourceRoot() {
213
241
  return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
214
242
  }
@@ -223,13 +251,19 @@ function readPackageVersion() {
223
251
  }
224
252
  function showUsage() {
225
253
  console.log('Usage: forge-ai install [--platform opencode|claude|codex|all] [--scope user|project] [--source <dir>] [--dry-run] [--force] [--yes]');
226
- console.log(' forge-ai update [--platform opencode|claude|codex|all] [--scope user|project] [--source <dir>] [--dry-run] [--yes]');
254
+ console.log(' forge-ai update [--platform opencode|claude|codex|all] [--scope user|project] [--source <dir>] [--dry-run] [--no-prune] [--yes]');
227
255
  console.log(' forge-ai validate [--platform opencode|claude|codex|all] [--source <dir>]');
228
256
  }
229
- function printPlan(command, sourceCount, files, diagnostics) {
257
+ function printPlan(command, sourceCount, files, diagnostics, prunePlan = { deletable: [], skipped: [] }) {
230
258
  console.log(`${command}: ${sourceCount} source(s), ${files.length} output(s)`);
231
259
  for (const file of files)
232
260
  console.log(`- ${file.platform} ${file.kind} ${file.name} -> ${file.path}`);
261
+ for (const file of prunePlan.deletable)
262
+ console.log(`- delete stale ${file.platform} ${file.kind} ${file.name} -> ${file.path}`);
263
+ for (const file of prunePlan.skipped) {
264
+ if (file.reason === 'checksum-mismatch')
265
+ console.log(`warning CHECKSUM_MISMATCH: Skipping stale managed file with local changes ${file.path}`);
266
+ }
233
267
  for (const item of diagnostics)
234
268
  console.log(formatDiagnostic(item));
235
269
  }
@@ -0,0 +1,101 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { constants } from 'node:fs';
3
+ import { access, mkdir, readFile, realpath, rm, writeFile } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ export async function resolveManifestLocation(scope, cwd = process.cwd(), home) {
6
+ const stateRoot = path.join(home, '.forge-ai');
7
+ if (scope === 'user')
8
+ return { stateRoot, manifestPath: path.join(stateRoot, 'user-manifest.json'), scope };
9
+ const projectPath = await canonicalProjectPath(cwd);
10
+ const projectPathHash = hashProjectPath(projectPath);
11
+ return { stateRoot, manifestPath: path.join(stateRoot, 'projects', projectPathHash, 'manifest.json'), scope, projectPath, projectPathHash };
12
+ }
13
+ export async function loadManifest(manifestPath) {
14
+ try {
15
+ return JSON.parse(await readFile(manifestPath, 'utf8'));
16
+ }
17
+ catch (error) {
18
+ if (error.code === 'ENOENT')
19
+ return undefined;
20
+ throw error;
21
+ }
22
+ }
23
+ export function buildManifest(location, files, now = new Date()) {
24
+ return {
25
+ schemaVersion: 1,
26
+ scope: location.scope,
27
+ projectPath: location.projectPath,
28
+ projectPathHash: location.projectPathHash,
29
+ updatedAt: now.toISOString(),
30
+ entries: files.map((file) => ({
31
+ platform: file.platform,
32
+ kind: file.kind,
33
+ name: file.name,
34
+ path: file.path,
35
+ sourcePath: file.sourcePath,
36
+ checksum: sha256(file.content)
37
+ }))
38
+ };
39
+ }
40
+ export async function saveManifest(manifestPath, manifest) {
41
+ await mkdir(path.dirname(manifestPath), { recursive: true });
42
+ await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
43
+ }
44
+ export function staleEntries(oldManifest, files) {
45
+ if (!oldManifest)
46
+ return [];
47
+ const currentPaths = new Set(files.map((file) => file.path));
48
+ return oldManifest.entries.filter((entry) => !currentPaths.has(entry.path));
49
+ }
50
+ export async function classifyPruneEntries(entries) {
51
+ const deletable = [];
52
+ const skipped = [];
53
+ for (const entry of entries) {
54
+ let content;
55
+ try {
56
+ content = await readFile(entry.path, 'utf8');
57
+ }
58
+ catch (error) {
59
+ if (error.code === 'ENOENT')
60
+ skipped.push({ ...entry, reason: 'missing' });
61
+ else
62
+ throw error;
63
+ continue;
64
+ }
65
+ if (sha256(content) === entry.checksum)
66
+ deletable.push(entry);
67
+ else
68
+ skipped.push({ ...entry, reason: 'checksum-mismatch' });
69
+ }
70
+ return { deletable, skipped };
71
+ }
72
+ export async function pruneEntries(entries) {
73
+ for (const entry of entries) {
74
+ await rm(entry.path, { force: true });
75
+ if (entry.kind === 'skill')
76
+ await removeEmptyParent(path.dirname(entry.path));
77
+ }
78
+ }
79
+ export function sha256(content) {
80
+ return createHash('sha256').update(content).digest('hex');
81
+ }
82
+ export function hashProjectPath(projectPath) {
83
+ return sha256(projectPath).slice(0, 32);
84
+ }
85
+ async function canonicalProjectPath(cwd) {
86
+ try {
87
+ return await realpath(cwd);
88
+ }
89
+ catch {
90
+ return path.resolve(cwd);
91
+ }
92
+ }
93
+ async function removeEmptyParent(directory) {
94
+ try {
95
+ await access(directory, constants.F_OK);
96
+ await rm(directory);
97
+ }
98
+ catch {
99
+ // Directory does not exist or is not empty; both are safe to ignore.
100
+ }
101
+ }
@@ -1,5 +1,6 @@
1
1
  import { access } from 'node:fs/promises';
2
2
  import { constants } from 'node:fs';
3
+ import path from 'node:path';
3
4
  import { renderClaudeAgent, renderClaudeSkill } from './adapters/claude.js';
4
5
  import { renderCodexAgent, renderCodexSkill } from './adapters/codex.js';
5
6
  import { renderOpenCodeAgent, renderOpenCodeSkill } from './adapters/opencode.js';
@@ -29,7 +30,7 @@ export async function buildWritePlan(options) {
29
30
  const seenAgents = new Set();
30
31
  const seenSkills = new Set();
31
32
  for (const source of sources) {
32
- const converted = convertSource(source);
33
+ const converted = convertSource(source, options.source);
33
34
  diagnostics.push(...converted.diagnostics);
34
35
  if (!converted.item)
35
36
  continue;
@@ -58,7 +59,7 @@ export async function buildWritePlan(options) {
58
59
  }
59
60
  return { files, diagnostics, sourceCount: sources.length };
60
61
  }
61
- function convertSource(source) {
62
+ function convertSource(source, sourceRoot) {
62
63
  const diagnostics = [];
63
64
  const data = source.data;
64
65
  const name = typeof data.name === 'string' ? data.name : undefined;
@@ -99,7 +100,7 @@ function convertSource(source) {
99
100
  diagnostics.push(diagnostic('error', 'EMPTY_BODY', `${source.kind} body is required`, { sourcePath: source.sourcePath }));
100
101
  if (!name || !description || !source.body.trim() || diagnostics.some((item) => item.severity === 'error'))
101
102
  return { diagnostics };
102
- const base = { name, description, claude: productConfig(data.claude), opencode: productConfig(data.opencode), codex: productConfig(data.codex) };
103
+ const base = { name, description, sourcePath: path.relative(path.resolve(sourceRoot), source.sourcePath), claude: productConfig(data.claude), opencode: productConfig(data.opencode), codex: productConfig(data.codex) };
103
104
  return { diagnostics, item: source.kind === 'agent' ? { ...base, definition: source.body } : { ...base, instructions: source.body } };
104
105
  }
105
106
  function productConfig(value) {
@@ -110,7 +111,7 @@ function renderFile(platform, kind, item, options, diagnostics) {
110
111
  ? platform === 'opencode' ? renderOpenCodeAgent(item) : platform === 'claude' ? renderClaudeAgent(item) : renderCodexAgent(item)
111
112
  : platform === 'opencode' ? renderOpenCodeSkill(item) : platform === 'claude' ? renderClaudeSkill(item) : renderCodexSkill(item);
112
113
  diagnostics.push(...rendered.diagnostics);
113
- return { platform, kind, scope: options.scope, name: item.name, path: resolveOutputPath(platform, kind, options.scope, item.name, options.cwd, options.home), content: rendered.content };
114
+ return { platform, kind, scope: options.scope, name: item.name, sourcePath: item.sourcePath ?? '', path: resolveOutputPath(platform, kind, options.scope, item.name, options.cwd, options.home), content: rendered.content };
114
115
  }
115
116
  async function collisionDiagnostics(files, force) {
116
117
  const diagnostics = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guidobuilds/forge-ai",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Forge AI framework",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: forge-grill
3
+ description: Stress-test a plan or design through Forge orchestration, batching user questions while delegating codebase-answerable work to forge-worker.
4
+ ---
5
+
6
+ # Forge Grill Skill
7
+
8
+ ## Role
9
+
10
+ Use this skill when the user wants Forge to stress-test, challenge, or "grill" a plan, design, proposal, or implementation approach.
11
+
12
+ You are still the Forge orchestrator: keep the user thread thin, delegate technical and operational work to `forge-worker`, and use the lightest safe workflow that reaches shared understanding.
13
+
14
+ ## Core behavior
15
+
16
+ - Build a decision tree for the plan or design under review.
17
+ - Resolve dependencies between decisions in an order that prevents rework.
18
+ - Challenge assumptions, edge cases, scope boundaries, sequencing, risks, and validation strategy.
19
+ - Prefer shared understanding over volume: ask the fewest high-leverage questions that close the next meaningful branch.
20
+ - Do not perform worker work inline.
21
+
22
+ ## Question policy
23
+
24
+ - Use the `question` tool for questions that require the user's judgment, preference, product intent, approval, or risk tolerance.
25
+ - Group related questions into small batches, usually 2-4 questions, instead of asking one question at a time.
26
+ - For each question or option, include Forge's recommended answer and a brief rationale so the user can accept or correct it quickly.
27
+ - Keep each batch focused on one decision branch or tightly related set of branches.
28
+ - Do not ask the user questions that can be answered by inspecting the repository, existing artifacts, logs, tests, or documentation available in the workspace.
29
+
30
+ ## Delegation policy
31
+
32
+ When a question can be answered by exploring the codebase or existing Forge artifacts, launch `forge-worker` instead of asking the user.
33
+
34
+ Use `forge-worker` for:
35
+
36
+ - repository inspection
37
+ - artifact review
38
+ - validation checks
39
+ - feasibility or integration discovery
40
+ - implementation-plan consistency checks
41
+ - technical risk investigation
42
+
43
+ Keep each worker prompt bounded and explicit about:
44
+
45
+ - the plan/design branch being tested
46
+ - what facts to inspect
47
+ - what is out of scope
48
+ - expected validation or evidence
49
+ - that the worker must not ask the user directly
50
+
51
+ ## Worker contract enforcement
52
+
53
+ Every delegated worker run must return exactly the Forge worker contract:
54
+
55
+ ```text
56
+ STATUS: success|partial|blocked
57
+ WORK_TYPE: inspect|design|plan|build|operate|verify|mixed
58
+ FEATURE_SLUG: <kebab-case>
59
+ ARTIFACTS:
60
+ - <path or None>
61
+ SUMMARY:
62
+ - <point>
63
+ NEXT_RECOMMENDED: inspect|design|plan|build|operate|verify|ask-user|none
64
+ RISKS:
65
+ - <risk or None>
66
+ QUESTIONS:
67
+ 1) <question>
68
+ ```
69
+
70
+ `QUESTIONS` must appear only when `STATUS: blocked`.
71
+
72
+ If a worker response is malformed, request one reformat retry for the same task. If it is malformed again, stop and surface an actionable orchestration error.
73
+
74
+ ## Grill workflow
75
+
76
+ 1. Restate the goal, known constraints, and the plan/design surface being grilled.
77
+ 2. Identify decision branches and separate them into:
78
+ - repo-answerable facts for `forge-worker`
79
+ - user-owned decisions for the `question` tool
80
+ - safe assumptions that can be stated and revisited
81
+ 3. Delegate repo-answerable inspection before asking the user about the same branch.
82
+ 4. Ask small batches of user-owned questions with a recommended answer for each.
83
+ 5. After each batch or worker result, update the decision tree and resolve dependent branches.
84
+ 6. Stop when the remaining unknowns are either resolved, explicitly accepted as risks, or safely deferred.
85
+
86
+ ## Output style to the user
87
+
88
+ - Be direct and rigorous, but not performative.
89
+ - Explain why each question matters.
90
+ - Include recommendations in actionable language, such as "Recommended: choose A because...".
91
+ - Make unresolved risk visible before moving to build, plan, or approval-seeking work.
92
+ - If grilling reveals implementation work is needed, route it through the normal Forge worker model instead of doing it inline.
@@ -1,80 +0,0 @@
1
- ---
2
- name: forge-build
3
- description: Implement approved scope from design and plan artifacts, then write build-log.md.
4
- ---
5
-
6
- # Forge Build Skill
7
-
8
- ## Role
9
- Implement only approved scope.
10
-
11
- Build is for approved code implementation only.
12
-
13
- ## Inputs
14
-
15
- - Orchestrator prompt with the approved implementation scope
16
- - Optional: `.forge/<feature-slug>/explore.md`
17
- - Optional: `.forge/<feature-slug>/design.md`
18
- - Optional: `.forge/<feature-slug>/plan.md`
19
-
20
- ## Required output file
21
-
22
- `.forge/<feature-slug>/build-log.md`
23
-
24
- ## Build log format
25
-
26
- - Executed plan steps
27
- - Files changed
28
- - Validation run and result
29
- - Deviations from plan and rationale
30
- - Follow-ups
31
-
32
- ## Build rules
33
-
34
- - If a plan exists, do not expand scope beyond plan.
35
- - Before implementing, check whether `.forge/<feature-slug>/plan.md` exists.
36
- - If a plan exists, review it critically before touching code.
37
- - If a plan exists, require the orchestrator prompt to include evidence that the user explicitly approved starting build for that planned scope.
38
- - If a plan exists and that approval is absent or ambiguous, stop and return `STATUS: blocked` with approval questions instead of implementing.
39
- - If a plan exists and contains placeholders, missing dependencies, or non-buildable tasks, stop and return `STATUS: blocked` instead of guessing.
40
- - If no plan exists, treat the orchestrator prompt as the approved scope and keep the change tightly bounded.
41
- - If no plan exists, the direct-build path is allowed only when the orchestrator prompt clearly marks the request as a lightweight implementation.
42
- - Non-development operational tasks are out of scope for build.
43
- - Route non-development execution tasks such as git commit or git push to `forge-helper`.
44
- - If a step is materially ambiguous during execution, stop and return blocked with questions.
45
- - When a plan exists, record build-log progress against the reviewed plan rather than silently reshaping it.
46
- - Implement the minimum code necessary to satisfy the approved design and plan.
47
- - Do not perform adjacent refactors, cleanup passes, or abstraction work unless explicitly approved or required to complete the approved scope.
48
- - Prefer existing patterns over introducing new layers, frameworks, or indirection.
49
-
50
- ## Pre-implementation checklist
51
-
52
- Before editing files, confirm:
53
-
54
- - the goal being implemented
55
- - the files expected to change
56
- - the validation that should prove the goal
57
-
58
- Apply this checklist on both plan-backed builds and lightweight direct-build paths.
59
-
60
- ## Contract (strict)
61
-
62
- Return only:
63
-
64
- ```text
65
- STATUS: success|partial|blocked
66
- PHASE: BUILD
67
- FEATURE_SLUG: <kebab-case>
68
- ARTIFACTS:
69
- - .forge/<feature-slug>/build-log.md
70
- SUMMARY:
71
- - <brief point>
72
- NEXT_RECOMMENDED: none
73
- RISKS:
74
- - <risk or None>
75
- QUESTIONS:
76
- 1) <question>
77
- 2) <question>
78
- ```
79
-
80
- Include `QUESTIONS` only when blocked.
@@ -1,104 +0,0 @@
1
- ---
2
- name: forge-design
3
- description: Create the canonical design artifact that merges product and technical design into design.md.
4
- ---
5
-
6
- # Forge Design Skill
7
-
8
- ## Role
9
- Close critical design decisions and then produce the single design artifact for the work item.
10
-
11
- `design.md` is the default source of truth for both intended behavior and technical shape. There is no separate `tech.md` in this flow.
12
-
13
- ## Inputs
14
-
15
- - `.forge/<feature-slug>/explore.md`
16
- - Feature request and user clarifications
17
-
18
- ## Required output file
19
-
20
- `.forge/<feature-slug>/design.md`, but only after the clarification gate is fully closed.
21
-
22
- ## Clarification gate
23
-
24
- Before writing `design.md`, review:
25
-
26
- - `.forge/<feature-slug>/explore.md`
27
- - the user request
28
- - prior user clarifications in the current thread
29
-
30
- Classify open questions into:
31
-
32
- - critical decisions that materially change behavior, scope, interface, or technical shape
33
- - non-critical details that can be fixed by a reasonable default
34
-
35
- Rules:
36
-
37
- - Resolve all critical decisions before writing `design.md`.
38
- - Do not ask questions that can be answered from the repo, existing artifacts, or docs.
39
- - Ask the smallest useful batch of independent questions.
40
- - Every question must include:
41
- - the decision to resolve
42
- - a recommended answer
43
- - brief impact of that recommendation
44
- - If critical decisions remain, return `STATUS: blocked`, `NEXT_RECOMMENDED: design`, and do not write `design.md` yet.
45
-
46
- ## Design format
47
-
48
- The document must stay compact and optimized for LLM consumption.
49
-
50
- Expected content:
51
- - Objective
52
- - Non-objectives
53
- - Decision Log
54
- - Requirements with stable `TASK-*` identifiers
55
- - Technical shape for those same `TASK-*` items
56
- - Constraints and dependencies that materially affect implementation
57
- - Acceptance checks
58
-
59
- ## Design rules
60
-
61
- - Merge product and technical design into one artifact, but keep those concerns clearly separated by section.
62
- - Include only resolved design-relevant decisions in the `Decision Log`.
63
- - Reuse stable `TASK-*` identifiers across the artifact.
64
- - Be concrete about files, modules, integration points, and constraints when they materially shape implementation.
65
- - Do not turn `design.md` into an execution checklist; sequencing belongs in `plan.md`.
66
- - Use reasonable defaults only for non-critical details.
67
- - Do not write `design.md` with unresolved critical decisions.
68
- - Prefer the simplest design that satisfies the requested outcome and acceptance checks.
69
- - Avoid speculative abstractions or new indirection unless the request or current architecture requires them.
70
- - Record the important tradeoffs and defaults that downstream planning and build must preserve.
71
- - Escalate only decisions that materially change behavior, scope, interface, or technical shape.
72
- - If a heavier alternative was considered and rejected because it would expand scope or complexity, note that briefly when it helps preserve the approved shape.
73
-
74
- ## Phase intent
75
-
76
- - `design.md` answers: what should change, and what is the intended technical shape?
77
- - It is the design source of truth for downstream planning and implementation after the clarification gate has been closed.
78
-
79
- ## Contract (strict)
80
-
81
- Return only:
82
-
83
- ```text
84
- STATUS: success|partial|blocked
85
- PHASE: DESIGN
86
- FEATURE_SLUG: <kebab-case>
87
- ARTIFACTS:
88
- - .forge/<feature-slug>/design.md | None
89
- SUMMARY:
90
- - <brief point>
91
- NEXT_RECOMMENDED: design|plan
92
- RISKS:
93
- - <risk or None>
94
- QUESTIONS:
95
- 1) Decision: <decision>
96
- Recommendation: <recommended answer>
97
- Impact: <brief why>
98
- 2) Decision: <decision>
99
- Recommendation: <recommended answer>
100
- Impact: <brief why>
101
- ```
102
-
103
- Use `STATUS: blocked` when critical decisions still require user input.
104
- Include `QUESTIONS` only when blocked.
@@ -1,65 +0,0 @@
1
- ---
2
- name: forge-explore
3
- description: Explore the requested feature and write the baseline exploration artifact.
4
- ---
5
-
6
- # Forge Explore Skill
7
-
8
- ## Role
9
- Explore the repository and produce a compact baseline for downstream design, planning, or build work.
10
-
11
- ## Inputs
12
-
13
- - Work item request from the orchestrator prompt
14
- - Repository code and docs
15
-
16
- ## Required output file
17
-
18
- `.forge/<feature-slug>/explore.md`
19
-
20
- ## Exploration rules
21
-
22
- - Think before broadening the search. Prefer narrow reading and searching around likely files and symbols before wider repo scans.
23
- - Distinguish observed facts from inferred conclusions.
24
- - Capture assumptions, unknowns, tradeoffs, and critical decisions explicitly.
25
- - Record only the repo intersections that materially shape later design or implementation.
26
- - Escalate only missing information that meaningfully blocks design or safe execution.
27
- - Do not redesign the solution in `explore`; identify what exists, what is missing, and what decisions remain.
28
-
29
- ## Explore format
30
-
31
- Keep the artifact compact and optimized for downstream LLM consumption.
32
-
33
- Expected content:
34
- - Problem framing
35
- - What already exists and current state
36
- - Relevant codepaths, modules, systems, and docs
37
- - Intersections with adjacent areas that may be affected
38
- - Assumptions
39
- - Unknowns
40
- - Tradeoffs
41
- - Critical decisions
42
- - Non-critical unknowns
43
-
44
- ## Contract (strict)
45
-
46
- Return only:
47
-
48
- ```text
49
- STATUS: success|partial|blocked
50
- PHASE: EXPLORE
51
- FEATURE_SLUG: <kebab-case>
52
- ARTIFACTS:
53
- - .forge/<feature-slug>/explore.md
54
- SUMMARY:
55
- - <brief point>
56
- NEXT_RECOMMENDED: design
57
- RISKS:
58
- - <risk or None>
59
- QUESTIONS:
60
- 1) <question>
61
- 2) <question>
62
- ```
63
-
64
- Use `STATUS: blocked` only if missing information blocks meaningful exploration.
65
- Include `QUESTIONS` only when blocked.
@@ -1,46 +0,0 @@
1
- ---
2
- name: forge-helper
3
- description: Execute non-development helper tasks for the orchestrator.
4
- ---
5
-
6
- # Forge Helper Skill
7
-
8
- ## Role
9
- Execute bounded non-development tasks for the orchestrator.
10
-
11
- ## Scope rules
12
-
13
- - Do only the requested operational action.
14
- - Do not write code, edit source files, or broaden into software-development implementation work.
15
- - If the request is actually explore, design, plan, or build work, stop and tell the orchestrator to route it to the appropriate phase agent.
16
- - Keep execution tightly bounded to the requested helper task.
17
- - If the action could mutate protected or remote state, require explicit confirmation unless the orchestrator prompt already contains clear user intent for that exact action.
18
- - Do not broaden into workflow advice or extra repo operations unless asked.
19
-
20
- ## Typical examples
21
-
22
- - create a git commit
23
- - push a branch
24
- - inspect non-development execution status needed by the orchestrator
25
-
26
- ## Contract (strict)
27
-
28
- Return only:
29
-
30
- ```text
31
- STATUS: success|partial|blocked
32
- PHASE: HELPER
33
- FEATURE_SLUG: <kebab-case>
34
- ARTIFACTS:
35
- - <path or None>
36
- SUMMARY:
37
- - <brief point>
38
- NEXT_RECOMMENDED: none
39
- RISKS:
40
- - <risk or None>
41
- QUESTIONS:
42
- 1) <question>
43
- 2) <question>
44
- ```
45
-
46
- Include `QUESTIONS` only when blocked.
@@ -1,81 +0,0 @@
1
- ---
2
- name: forge-plan
3
- description: Create an execution plan from explore and design artifacts.
4
- ---
5
-
6
- # Forge Plan Skill
7
-
8
- ## Role
9
- Create the execution plan from the approved design work.
10
-
11
- ## Inputs
12
-
13
- - `.forge/<feature-slug>/explore.md`
14
- - `.forge/<feature-slug>/design.md`
15
-
16
- ## Required output file
17
-
18
- `.forge/<feature-slug>/plan.md`
19
-
20
- ## Plan format
21
-
22
- The plan defines execution order using building tasks.
23
-
24
- A building task is a unit of work that must be implementable and testable.
25
-
26
- The plan must include:
27
- - Scope for the current delivery
28
- - File Map covering the likely files or modules to touch and why
29
- - Building tasks to execute
30
- - Execution order of those building tasks
31
- - Expected result of each building task
32
- - Files or components touched by each building task
33
- - Verification for each building task
34
- - References to relevant `TASK-*` items when they clarify scope, sequencing, or dependencies
35
-
36
- The plan must not include:
37
- - Design definitions that belong in `design.md`
38
- - Rationale for why a solution was chosen over another
39
- - Code blocks
40
- - Unresolved questions inside the plan document
41
- - Placeholder language such as `TBD`, `TODO`, `implement later`, `adjust as needed`, or catch-all steps that hide concrete work
42
-
43
- ## Planning rules
44
-
45
- - Use `design.md` as the source of truth for behavior and technical shape.
46
- - Do not plan from a design artifact that still has unresolved critical decisions.
47
- - Sequence delivery work without redefining the design.
48
- - Make each building task buildable without guesswork.
49
- - Prefer finer-grained tasks than the current format, but do not break work into trivial micro-steps.
50
- - Ask questions only when uncertainty materially changes execution strategy or task ordering.
51
- - A completed plan does not authorize implementation by itself.
52
- - Default to `NEXT_RECOMMENDED: plan` when the plan is ready but waiting for user approval to build.
53
- - Return `NEXT_RECOMMENDED: build` only when the orchestrator prompt explicitly states that the user has already approved implementation.
54
- - Keep tasks surgically scoped to the approved goal; optional cleanup belongs outside the plan unless explicitly requested.
55
- - The file map must justify why each listed file or module is expected to be touched.
56
- - Prefer existing patterns and minimum necessary changes over broader structural rewrites.
57
- - Each task must include minimal verification tied to the requested goal, not just a generic test step.
58
- - If execution would require guesswork about assumptions, unknowns, or missing dependencies, stop and block instead of padding the plan with placeholders.
59
-
60
- ## Contract (strict)
61
-
62
- Return only:
63
-
64
- ```text
65
- STATUS: success|partial|blocked
66
- PHASE: PLAN
67
- FEATURE_SLUG: <kebab-case>
68
- ARTIFACTS:
69
- - .forge/<feature-slug>/plan.md
70
- SUMMARY:
71
- - <brief point>
72
- NEXT_RECOMMENDED: plan|build
73
- RISKS:
74
- - <risk or None>
75
- QUESTIONS:
76
- 1) <question>
77
- 2) <question>
78
- ```
79
-
80
- Use `STATUS: blocked` when planning cannot continue due to missing critical decisions.
81
- Include `QUESTIONS` only when blocked.