@firatcand/forge 0.1.0 → 0.2.1
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 +25 -12
- package/bin/forge.js +97 -7
- package/lib/tools.js +102 -0
- package/package.json +1 -1
- package/skills/forge/SKILL.md +2 -2
- package/templates/CLAUDE.project.template.md +1 -1
package/README.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+

|
|
1
2
|
# 🔨 Forge
|
|
2
3
|
|
|
3
4
|
> A lightweight Claude Code framework that takes you from idea to production with structure, not friction.
|
|
@@ -8,7 +9,7 @@ Forge is for solo founders and small teams who want to ship real products with C
|
|
|
8
9
|
|
|
9
10
|
Forge ships:
|
|
10
11
|
|
|
11
|
-
- **21
|
|
12
|
+
- **21 skills** covering the full product lifecycle from raw idea to production (typed as slash commands in Claude Code; invoked by description in Codex CLI — see [Cross-tool support](#cross-tool-support))
|
|
12
13
|
- **12 specialist subagents** — frontend, backend, db, qa, security, devops, design, plus orchestrators
|
|
13
14
|
- **13 templates** for PRD, SPEC, DESIGN, phases.yaml, GitHub workflows, and more
|
|
14
15
|
- **8 best practices baked in** — Boil the Lake, Iron Law of Investigation, Compound Learning, Test-or-die, Multi-model Second Opinion, and more
|
|
@@ -44,6 +45,8 @@ PROD ← /phase-gate phase-3 ← (manual PR dev → main)
|
|
|
44
45
|
|
|
45
46
|
~90-120 minutes from raw idea to first task ready to implement.
|
|
46
47
|
|
|
48
|
+
> The `/`-prefixed names above are the Claude Code experience — typed slash commands. In other hosts (Codex CLI, Cursor, Gemini CLI), the same skills are available but invoked differently. See [Cross-tool support](#cross-tool-support) below.
|
|
49
|
+
|
|
47
50
|
## Install
|
|
48
51
|
|
|
49
52
|
One command. No git clone, no setup script.
|
|
@@ -69,9 +72,9 @@ npx @firatcand/forge
|
|
|
69
72
|
mkdir my-product && cd my-product
|
|
70
73
|
npx @firatcand/forge init
|
|
71
74
|
|
|
72
|
-
# Open your AI coding tool
|
|
73
|
-
claude
|
|
74
|
-
> /forge #
|
|
75
|
+
# Open your AI coding tool — see Cross-tool support below for per-host invocation
|
|
76
|
+
claude
|
|
77
|
+
> /forge # discovery interview → spec/BRIEF.md
|
|
75
78
|
> /draft-prd # → spec/PRD.md
|
|
76
79
|
> /draft-spec # → spec/SPEC.md
|
|
77
80
|
> /decompose # → plans/phases.yaml
|
|
@@ -80,31 +83,41 @@ claude # or: codex, cursor, gemini
|
|
|
80
83
|
> /pickup-task # claim first task, worktree created
|
|
81
84
|
```
|
|
82
85
|
|
|
86
|
+
In Codex CLI, the same skills are installed but Codex doesn't expose user-defined slash commands — invoke them by description instead, e.g. `Run forge's discovery interview for my project idea: ...`. Codex's model picks the skill up from `~/.codex/skills/forge/SKILL.md`.
|
|
87
|
+
|
|
83
88
|
[Full quick start →](docs/QUICKSTART.md)
|
|
84
89
|
|
|
85
90
|
## Other commands
|
|
86
91
|
|
|
87
92
|
```bash
|
|
88
93
|
npx @firatcand/forge install # Install/reinstall forge skills + agents only
|
|
94
|
+
npx @firatcand/forge doctor # Audit installed skills + agents per detected tool
|
|
89
95
|
npx @firatcand/forge init [name] # Initialize a project in current directory
|
|
90
96
|
npx @firatcand/forge companions # Install founder-skills companions only
|
|
91
97
|
npx @firatcand/forge --help # Show all commands
|
|
92
98
|
npx @firatcand/forge --version # Show version
|
|
93
99
|
```
|
|
94
100
|
|
|
101
|
+
If a slash command stops triggering in one of your AI tools (e.g. you installed Codex CLI after running forge for the first time), run `npx @firatcand/forge doctor` to see exactly what's installed where, then `npx @firatcand/forge install` to sync.
|
|
102
|
+
|
|
95
103
|
## Cross-tool support
|
|
96
104
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
The installer detects which tools you have and installs forge skills + subagents into each. **The skills land in every host, but how you invoke them differs by host.**
|
|
106
|
+
|
|
107
|
+
| Host | Install path | How to invoke a forge skill | Status |
|
|
108
|
+
|------------|---------------------------------------|--------------------------------------------------------------|-----------------------|
|
|
109
|
+
| Claude Code | `~/.claude/skills/`, `~/.claude/agents/` | Typed slash commands: `/forge`, `/draft-prd`, … | ✅ Verified |
|
|
110
|
+
| Codex CLI | `~/.codex/skills/`, `~/.codex/subagents/` | Natural language — Codex doesn't expose user slash commands. Ask the model: "Run forge's discovery interview for …" | ✅ Skills load; no `/forge` syntax |
|
|
111
|
+
| Cursor | `~/.cursor/skills/`, `~/.cursor/agents/` | Unverified — invocation mechanism not yet tested by maintainer | ⚠️ Unverified |
|
|
112
|
+
| Gemini CLI | `~/.gemini/extensions/` | Unverified — uses Gemini's `extensions` format, may need manual config | ⚠️ Unverified |
|
|
113
|
+
|
|
114
|
+
If you're on Codex/Cursor/Gemini and `/forge` doesn't trigger, that's expected — try the natural-language form. Run `npx @firatcand/forge doctor` to confirm the skills are physically present at the expected paths.
|
|
102
115
|
|
|
103
|
-
|
|
116
|
+
If you discover the right invocation pattern for Cursor or Gemini and it differs from natural language, please open an issue or PR — the maintainer is actively looking for confirmation on those two.
|
|
104
117
|
|
|
105
118
|
## Why "forge"?
|
|
106
119
|
|
|
107
|
-
Forge is what you do when you have raw material (an idea) and want a finished tool (a product). The process is heat, pressure, shape, repeat. The framework's namesake skill `/forge` applies
|
|
120
|
+
Forge is what you do when you have raw material (an idea) and want a finished tool (a product). The process is heat, pressure, shape, repeat. The framework's namesake skill `/forge` is a discovery interview that applies pressure to your raw idea until structure emerges.
|
|
108
121
|
|
|
109
122
|
## Inspiration
|
|
110
123
|
|
|
@@ -123,7 +136,7 @@ What forge adds:
|
|
|
123
136
|
|
|
124
137
|
## Status
|
|
125
138
|
|
|
126
|
-
Forge is **
|
|
139
|
+
Forge is **v0.2.1** — used in production by the maintainer for solo founder workflows. Stable enough to depend on, raw enough that you'll find sharp edges. Issues and PRs welcome.
|
|
127
140
|
|
|
128
141
|
## License
|
|
129
142
|
|
package/bin/forge.js
CHANGED
|
@@ -4,12 +4,28 @@ import { checkbox, input, confirm } from '@inquirer/prompts';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import fs from 'fs-extra';
|
|
6
6
|
import path from 'path';
|
|
7
|
+
import os from 'os';
|
|
7
8
|
import { execSync } from 'child_process';
|
|
8
9
|
|
|
9
|
-
import { detectTools, installToTool } from '../lib/tools.js';
|
|
10
|
+
import { detectTools, installToTool, auditTool } from '../lib/tools.js';
|
|
10
11
|
import { COMPANIONS, installCompanion } from '../lib/companions.js';
|
|
11
12
|
import { FORGE_ROOT, getPackageVersion } from '../lib/paths.js';
|
|
12
13
|
|
|
14
|
+
function tildify(p) {
|
|
15
|
+
if (!p) return p;
|
|
16
|
+
const home = os.homedir();
|
|
17
|
+
return p.startsWith(home) ? '~' + p.slice(home.length) : p;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function formatInstallSummary(tool, result) {
|
|
21
|
+
const parts = [`${result.skillsCount} skills → ${tildify(result.skillsTarget)}`];
|
|
22
|
+
if (result.agentsTarget) {
|
|
23
|
+
const agentLabel = tool.key === 'codex' ? 'subagents' : 'agents';
|
|
24
|
+
parts.push(`${result.agentsCount} ${agentLabel} → ${tildify(result.agentsTarget)}`);
|
|
25
|
+
}
|
|
26
|
+
return `${tool.name} — ${parts.join(', ')}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
13
29
|
function showHelp() {
|
|
14
30
|
console.log(`
|
|
15
31
|
${chalk.bold('🔨 forge')} — A lightweight framework for shipping software products with AI coding agents
|
|
@@ -17,13 +33,15 @@ ${chalk.bold('🔨 forge')} — A lightweight framework for shipping software pr
|
|
|
17
33
|
${chalk.bold('Usage:')}
|
|
18
34
|
npx @firatcand/forge Run interactive setup (default)
|
|
19
35
|
npx @firatcand/forge install Install forge skills + agents only
|
|
36
|
+
npx @firatcand/forge doctor Audit installed skills + agents per tool
|
|
20
37
|
npx @firatcand/forge init [name] Initialize a forge project in current directory
|
|
21
38
|
npx @firatcand/forge companions Install founder-skills companions
|
|
22
39
|
npx @firatcand/forge --version Show version
|
|
23
40
|
npx @firatcand/forge --help Show this help
|
|
24
41
|
|
|
25
42
|
${chalk.bold('Skills (use inside your AI coding tool):')}
|
|
26
|
-
/forge
|
|
43
|
+
${chalk.dim(` Claude Code: type the / name. Codex CLI: ask in natural language ("run forge's discovery interview").`)}
|
|
44
|
+
/forge Discovery interview → BRIEF.md
|
|
27
45
|
/draft-prd Generate PRD.md from BRIEF.md
|
|
28
46
|
/draft-spec Generate SPEC.md from PRD.md
|
|
29
47
|
/draft-design Generate DESIGN.md from PRD.md (optional)
|
|
@@ -84,8 +102,8 @@ async function runInteractiveSetup() {
|
|
|
84
102
|
console.log(chalk.bold('\n📦 Installing forge skills (21) and agents (12)...\n'));
|
|
85
103
|
for (const toolKey of selectedTools) {
|
|
86
104
|
const tool = detected.find(t => t.key === toolKey);
|
|
87
|
-
await installToTool(tool, FORGE_ROOT);
|
|
88
|
-
console.log(chalk.green(' ✓') +
|
|
105
|
+
const result = await installToTool(tool, FORGE_ROOT);
|
|
106
|
+
console.log(chalk.green(' ✓') + ' ' + formatInstallSummary(tool, result));
|
|
89
107
|
}
|
|
90
108
|
|
|
91
109
|
console.log();
|
|
@@ -145,13 +163,82 @@ async function commandInstall() {
|
|
|
145
163
|
|
|
146
164
|
for (const toolKey of selectedTools) {
|
|
147
165
|
const tool = detected.find(t => t.key === toolKey);
|
|
148
|
-
await installToTool(tool, FORGE_ROOT);
|
|
149
|
-
console.log(chalk.green(' ✓') +
|
|
166
|
+
const result = await installToTool(tool, FORGE_ROOT);
|
|
167
|
+
console.log(chalk.green(' ✓') + ' ' + formatInstallSummary(tool, result));
|
|
150
168
|
}
|
|
151
169
|
|
|
152
170
|
console.log(chalk.bold.green('\n✅ Done\n'));
|
|
153
171
|
}
|
|
154
172
|
|
|
173
|
+
async function commandDoctor() {
|
|
174
|
+
console.log(chalk.bold('\n🔨 forge doctor\n'));
|
|
175
|
+
|
|
176
|
+
const detected = detectTools();
|
|
177
|
+
if (detected.length === 0) {
|
|
178
|
+
console.log(chalk.red(' ⚠️ No supported AI coding tools detected.'));
|
|
179
|
+
console.log(chalk.dim(' Install one of: Claude Code, Codex CLI, Cursor, Gemini CLI'));
|
|
180
|
+
console.log(chalk.dim(' Then re-run: npx @firatcand/forge\n'));
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
let anyDrift = false;
|
|
185
|
+
for (const tool of detected) {
|
|
186
|
+
const audit = await auditTool(tool, FORGE_ROOT);
|
|
187
|
+
const agentLabelWord = tool.key === 'codex' ? 'subagents' : 'agents';
|
|
188
|
+
|
|
189
|
+
const skillsStaleSuffix = audit.staleSkills.length > 0
|
|
190
|
+
? chalk.yellow(` (${audit.staleSkills.length} stale)`)
|
|
191
|
+
: '';
|
|
192
|
+
const skillsLabel = `${audit.installedSkills.length}/${audit.expectedSkills.length} skills${skillsStaleSuffix}`;
|
|
193
|
+
|
|
194
|
+
let agentsLabel = null;
|
|
195
|
+
if (audit.agentsTarget) {
|
|
196
|
+
const agentsStaleSuffix = audit.staleAgents.length > 0
|
|
197
|
+
? chalk.yellow(` (${audit.staleAgents.length} stale)`)
|
|
198
|
+
: '';
|
|
199
|
+
agentsLabel = `${audit.installedAgents.length}/${audit.expectedAgents.length} ${agentLabelWord}${agentsStaleSuffix}`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const toolDrift =
|
|
203
|
+
audit.missingSkills.length > 0 ||
|
|
204
|
+
audit.missingAgents.length > 0 ||
|
|
205
|
+
audit.staleSkills.length > 0 ||
|
|
206
|
+
audit.staleAgents.length > 0;
|
|
207
|
+
|
|
208
|
+
const statusIcon = toolDrift ? chalk.yellow(' ⚠') : chalk.green(' ✓');
|
|
209
|
+
const counts = agentsLabel ? `${skillsLabel}, ${agentsLabel}` : skillsLabel;
|
|
210
|
+
console.log(`${statusIcon} ${tool.name} — ${counts}`);
|
|
211
|
+
console.log(chalk.dim(` skills: ${tildify(audit.skillsTarget)}`));
|
|
212
|
+
if (audit.agentsTarget) {
|
|
213
|
+
console.log(chalk.dim(` ${agentLabelWord}: ${tildify(audit.agentsTarget)}`));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (audit.missingSkills.length > 0) {
|
|
217
|
+
console.log(chalk.yellow(` missing skills: ${audit.missingSkills.join(', ')}`));
|
|
218
|
+
}
|
|
219
|
+
if (audit.staleSkills.length > 0) {
|
|
220
|
+
console.log(chalk.yellow(` stale skills: ${audit.staleSkills.join(', ')}`));
|
|
221
|
+
}
|
|
222
|
+
if (audit.missingAgents.length > 0) {
|
|
223
|
+
console.log(chalk.yellow(` missing ${agentLabelWord}: ${audit.missingAgents.join(', ')}`));
|
|
224
|
+
}
|
|
225
|
+
if (audit.staleAgents.length > 0) {
|
|
226
|
+
console.log(chalk.yellow(` stale ${agentLabelWord}: ${audit.staleAgents.join(', ')}`));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (toolDrift) anyDrift = true;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
console.log();
|
|
233
|
+
if (anyDrift) {
|
|
234
|
+
console.log(chalk.yellow('Some tools have missing or stale forge skills/agents.'));
|
|
235
|
+
console.log(chalk.dim('Run: ') + chalk.cyan('npx @firatcand/forge install') + chalk.dim(' to sync.\n'));
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
console.log(chalk.bold.green('✅ All detected tools are in sync\n'));
|
|
240
|
+
}
|
|
241
|
+
|
|
155
242
|
async function commandCompanions() {
|
|
156
243
|
console.log(chalk.bold('\n🔨 forge companions\n'));
|
|
157
244
|
|
|
@@ -319,7 +406,7 @@ async function commandInit(projectNameArg) {
|
|
|
319
406
|
console.log(chalk.bold.green('\n✅ Project initialized\n'));
|
|
320
407
|
console.log(chalk.bold('Next:'));
|
|
321
408
|
console.log(' Open your AI coding tool: ' + chalk.cyan('claude') + ' or ' + chalk.cyan('codex'));
|
|
322
|
-
console.log(' Run: ' + chalk.cyan('/forge') + ' (
|
|
409
|
+
console.log(' Run: ' + chalk.cyan('/forge') + ' (discovery interview → BRIEF.md)\n');
|
|
323
410
|
}
|
|
324
411
|
|
|
325
412
|
async function main() {
|
|
@@ -331,6 +418,9 @@ async function main() {
|
|
|
331
418
|
case 'install':
|
|
332
419
|
await commandInstall();
|
|
333
420
|
break;
|
|
421
|
+
case 'doctor':
|
|
422
|
+
await commandDoctor();
|
|
423
|
+
break;
|
|
334
424
|
case 'companions':
|
|
335
425
|
await commandCompanions();
|
|
336
426
|
break;
|
package/lib/tools.js
CHANGED
|
@@ -1,7 +1,38 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import os from 'os';
|
|
3
|
+
import crypto from 'crypto';
|
|
3
4
|
import fs from 'fs-extra';
|
|
4
5
|
|
|
6
|
+
const HASH_IGNORE = new Set(['.DS_Store', 'Thumbs.db', '.git']);
|
|
7
|
+
|
|
8
|
+
async function hashEntry(entryPath) {
|
|
9
|
+
let stat;
|
|
10
|
+
try {
|
|
11
|
+
stat = await fs.stat(entryPath);
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
if (stat.isFile()) {
|
|
16
|
+
const buf = await fs.readFile(entryPath);
|
|
17
|
+
return crypto.createHash('sha256').update(buf).digest('hex');
|
|
18
|
+
}
|
|
19
|
+
if (stat.isDirectory()) {
|
|
20
|
+
const entries = (await fs.readdir(entryPath))
|
|
21
|
+
.filter(name => !HASH_IGNORE.has(name))
|
|
22
|
+
.sort();
|
|
23
|
+
const hash = crypto.createHash('sha256');
|
|
24
|
+
for (const name of entries) {
|
|
25
|
+
const childHash = await hashEntry(path.join(entryPath, name));
|
|
26
|
+
if (childHash === null) continue;
|
|
27
|
+
hash.update(name);
|
|
28
|
+
hash.update('\0');
|
|
29
|
+
hash.update(childHash);
|
|
30
|
+
}
|
|
31
|
+
return hash.digest('hex');
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
5
36
|
const TOOL_DEFINITIONS = [
|
|
6
37
|
{
|
|
7
38
|
key: 'claude',
|
|
@@ -53,6 +84,7 @@ export async function installToTool(tool, forgeRoot) {
|
|
|
53
84
|
await fs.copy(src, dst, { overwrite: true, errorOnExist: false });
|
|
54
85
|
}
|
|
55
86
|
|
|
87
|
+
let agentsCount = 0;
|
|
56
88
|
if (agentsTarget) {
|
|
57
89
|
const agentsSource = path.join(forgeRoot, 'agents');
|
|
58
90
|
if (await fs.pathExists(agentsSource)) {
|
|
@@ -63,6 +95,76 @@ export async function installToTool(tool, forgeRoot) {
|
|
|
63
95
|
await fs.remove(dst);
|
|
64
96
|
await fs.copy(src, dst, { overwrite: true, errorOnExist: false });
|
|
65
97
|
}
|
|
98
|
+
agentsCount = agents.length;
|
|
66
99
|
}
|
|
67
100
|
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
skillsCount: skills.length,
|
|
104
|
+
agentsCount,
|
|
105
|
+
skillsTarget,
|
|
106
|
+
agentsTarget,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function listExpectedSkills(forgeRoot) {
|
|
111
|
+
return fs.readdir(path.join(forgeRoot, 'skills'));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function listExpectedAgents(forgeRoot) {
|
|
115
|
+
const agentsSource = path.join(forgeRoot, 'agents');
|
|
116
|
+
if (!(await fs.pathExists(agentsSource))) return [];
|
|
117
|
+
return fs.readdir(agentsSource);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function diffByContent(names, sourceDir, targetDir) {
|
|
121
|
+
const stale = [];
|
|
122
|
+
for (const name of names) {
|
|
123
|
+
const sourceHash = await hashEntry(path.join(sourceDir, name));
|
|
124
|
+
const targetHash = await hashEntry(path.join(targetDir, name));
|
|
125
|
+
if (sourceHash !== targetHash) stale.push(name);
|
|
126
|
+
}
|
|
127
|
+
return stale;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export async function auditTool(tool, forgeRoot) {
|
|
131
|
+
const expectedSkills = await listExpectedSkills(forgeRoot);
|
|
132
|
+
const skillsTarget = path.join(tool.dir, tool.skillsDir);
|
|
133
|
+
const skillsSource = path.join(forgeRoot, 'skills');
|
|
134
|
+
const skillsInstalled = (await fs.pathExists(skillsTarget))
|
|
135
|
+
? new Set(await fs.readdir(skillsTarget))
|
|
136
|
+
: new Set();
|
|
137
|
+
const installedSkills = expectedSkills.filter(s => skillsInstalled.has(s));
|
|
138
|
+
const missingSkills = expectedSkills.filter(s => !skillsInstalled.has(s));
|
|
139
|
+
const staleSkills = await diffByContent(installedSkills, skillsSource, skillsTarget);
|
|
140
|
+
|
|
141
|
+
let agentsTarget = null;
|
|
142
|
+
let expectedAgents = [];
|
|
143
|
+
let installedAgents = [];
|
|
144
|
+
let missingAgents = [];
|
|
145
|
+
let staleAgents = [];
|
|
146
|
+
if (tool.agentsDir) {
|
|
147
|
+
agentsTarget = path.join(tool.dir, tool.agentsDir);
|
|
148
|
+
const agentsSource = path.join(forgeRoot, 'agents');
|
|
149
|
+
expectedAgents = await listExpectedAgents(forgeRoot);
|
|
150
|
+
const agentsInstalled = (await fs.pathExists(agentsTarget))
|
|
151
|
+
? new Set(await fs.readdir(agentsTarget))
|
|
152
|
+
: new Set();
|
|
153
|
+
installedAgents = expectedAgents.filter(a => agentsInstalled.has(a));
|
|
154
|
+
missingAgents = expectedAgents.filter(a => !agentsInstalled.has(a));
|
|
155
|
+
staleAgents = await diffByContent(installedAgents, agentsSource, agentsTarget);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
skillsTarget,
|
|
160
|
+
expectedSkills,
|
|
161
|
+
installedSkills,
|
|
162
|
+
missingSkills,
|
|
163
|
+
staleSkills,
|
|
164
|
+
agentsTarget,
|
|
165
|
+
expectedAgents,
|
|
166
|
+
installedAgents,
|
|
167
|
+
missingAgents,
|
|
168
|
+
staleAgents,
|
|
169
|
+
};
|
|
68
170
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firatcand/forge",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "A lightweight framework for shipping software products from idea to production with AI coding agents (Claude Code, Codex CLI, Cursor, Gemini)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/skills/forge/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: forge
|
|
3
|
-
description:
|
|
3
|
+
description: Run forge's discovery interview over a raw idea and produce a validated project BRIEF. Heavy ceremony — 6 forcing questions. The required first command for any new forge project.
|
|
4
4
|
tools: Read, Write, Edit, Bash(git*)
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -71,7 +71,7 @@ BRIEF written to spec/BRIEF.md
|
|
|
71
71
|
Gate 1 — review the brief. To proceed:
|
|
72
72
|
• /draft-prd to generate the PRD
|
|
73
73
|
• Edit spec/BRIEF.md directly for fixes
|
|
74
|
-
• /forge --refine [section] to re-
|
|
74
|
+
• /forge --refine [section] to re-interview a weak section
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
## --refine mode
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
- New API routes must have input validation
|
|
23
23
|
- See `spec/` for full conventions
|
|
24
24
|
|
|
25
|
-
## Forge principles (auto-applied — see
|
|
25
|
+
## Forge principles (auto-applied — see [Forge ETHOS.md](https://github.com/firatcand/forge/blob/main/ETHOS.md))
|
|
26
26
|
1. Boil the Lake — refuse weak inputs
|
|
27
27
|
2. Iron Law of Investigation — no fixes without RCA
|
|
28
28
|
3. Confusion Protocol — clarify, don't guess
|