substrate-ai 0.1.10 → 0.1.12
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 +1 -1
- package/dist/cli/index.js +48 -14
- package/package.json +3 -5
- package/README.npm.md +0 -206
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://
|
|
2
|
+
<img src="https://raw.githubusercontent.com/johnplanow/substrate/main/assets/substrate-header.png" alt="Substrate — Autonomous Software Development Pipeline" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
# Substrate
|
package/dist/cli/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from "url";
|
|
|
8
8
|
import { dirname, extname, isAbsolute, join, relative, resolve } from "path";
|
|
9
9
|
import { access, mkdir, readFile, readdir, stat, writeFile } from "fs/promises";
|
|
10
10
|
import { execFile } from "child_process";
|
|
11
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
11
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
12
12
|
import yaml, { dump, load } from "js-yaml";
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
import { fileURLToPath as fileURLToPath$1 } from "node:url";
|
|
@@ -323,9 +323,9 @@ const DEFAULT_CONFIG = {
|
|
|
323
323
|
|
|
324
324
|
//#endregion
|
|
325
325
|
//#region src/cli/commands/templates.ts
|
|
326
|
-
const __filename = fileURLToPath$1(import.meta.url);
|
|
327
|
-
const __dirname = dirname$1(__filename);
|
|
328
|
-
const TEMPLATES_DIR = join$1(__dirname, "..", "templates");
|
|
326
|
+
const __filename$1 = fileURLToPath$1(import.meta.url);
|
|
327
|
+
const __dirname$1 = dirname$1(__filename$1);
|
|
328
|
+
const TEMPLATES_DIR = join$1(__dirname$1, "..", "templates");
|
|
329
329
|
/**
|
|
330
330
|
* Get the absolute path to a template YAML file.
|
|
331
331
|
*
|
|
@@ -12114,6 +12114,15 @@ Analyze thoroughly and return ONLY the JSON array with no additional text.`;
|
|
|
12114
12114
|
|
|
12115
12115
|
//#endregion
|
|
12116
12116
|
//#region src/cli/commands/auto.ts
|
|
12117
|
+
const __filename = fileURLToPath$1(import.meta.url);
|
|
12118
|
+
const __dirname = dirname(__filename);
|
|
12119
|
+
/**
|
|
12120
|
+
* Absolute path to the Substrate package root.
|
|
12121
|
+
*
|
|
12122
|
+
* In source: src/cli/commands/ → 3 levels up = repo root
|
|
12123
|
+
* Post-build: dist/cli/commands/ → 3 levels up = dist parent = package root
|
|
12124
|
+
*/
|
|
12125
|
+
const PACKAGE_ROOT = join(__dirname, "..", "..", "..");
|
|
12117
12126
|
const logger$3 = createLogger("auto-cmd");
|
|
12118
12127
|
/** BMAD baseline token total for full pipeline comparison (analysis+planning+solutioning+implementation) */
|
|
12119
12128
|
const BMAD_BASELINE_TOKENS_FULL = 56800;
|
|
@@ -12313,18 +12322,41 @@ function formatPipelineSummary(run, tokenSummary, decisionsCount, storiesCount,
|
|
|
12313
12322
|
return lines.join("\n");
|
|
12314
12323
|
}
|
|
12315
12324
|
async function runAutoInit(options) {
|
|
12316
|
-
const { pack: packName, projectRoot, outputFormat } = options;
|
|
12325
|
+
const { pack: packName, projectRoot, outputFormat, force = false } = options;
|
|
12317
12326
|
const packPath = join(projectRoot, "packs", packName);
|
|
12318
12327
|
const dbRoot = await resolveMainRepoRoot(projectRoot);
|
|
12319
12328
|
const dbDir = join(dbRoot, ".substrate");
|
|
12320
12329
|
const dbPath = join(dbDir, "substrate.db");
|
|
12321
12330
|
try {
|
|
12331
|
+
const localManifest = join(packPath, "manifest.yaml");
|
|
12332
|
+
let scaffolded = false;
|
|
12333
|
+
if (!existsSync(localManifest) || force) {
|
|
12334
|
+
const bundledPackPath = join(PACKAGE_ROOT, "packs", packName);
|
|
12335
|
+
if (!existsSync(join(bundledPackPath, "manifest.yaml"))) {
|
|
12336
|
+
const errorMsg = `Pack '${packName}' not found locally or in bundled packs. Try reinstalling Substrate.`;
|
|
12337
|
+
if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, errorMsg) + "\n");
|
|
12338
|
+
else process.stderr.write(`Error: ${errorMsg}\n`);
|
|
12339
|
+
return 1;
|
|
12340
|
+
}
|
|
12341
|
+
if (force && existsSync(localManifest)) {
|
|
12342
|
+
logger$3.info({ pack: packName }, "Replacing existing pack with bundled version");
|
|
12343
|
+
process.stderr.write(`Warning: Replacing existing pack '${packName}' with bundled version\n`);
|
|
12344
|
+
}
|
|
12345
|
+
mkdirSync(dirname(packPath), { recursive: true });
|
|
12346
|
+
cpSync(bundledPackPath, packPath, { recursive: true });
|
|
12347
|
+
logger$3.info({
|
|
12348
|
+
pack: packName,
|
|
12349
|
+
dest: packPath
|
|
12350
|
+
}, "Scaffolded methodology pack");
|
|
12351
|
+
process.stdout.write(`Scaffolding methodology pack '${packName}' into packs/${packName}/\n`);
|
|
12352
|
+
scaffolded = true;
|
|
12353
|
+
}
|
|
12322
12354
|
const packLoader = createPackLoader();
|
|
12323
12355
|
try {
|
|
12324
12356
|
await packLoader.load(packPath);
|
|
12325
12357
|
} catch (err) {
|
|
12326
12358
|
const msg = err instanceof Error ? err.message : String(err);
|
|
12327
|
-
const errorMsg = `Methodology pack '${packName}' not found.
|
|
12359
|
+
const errorMsg = `Methodology pack '${packName}' not found. Check that packs/${packName}/manifest.yaml exists or try reinstalling Substrate.\n${msg}`;
|
|
12328
12360
|
if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, errorMsg) + "\n");
|
|
12329
12361
|
else process.stderr.write(`Error: ${errorMsg}\n`);
|
|
12330
12362
|
return 1;
|
|
@@ -12337,7 +12369,8 @@ async function runAutoInit(options) {
|
|
|
12337
12369
|
const successMsg = `Pack '${packName}' and database initialized successfully at ${dbPath}`;
|
|
12338
12370
|
if (outputFormat === "json") process.stdout.write(formatOutput({
|
|
12339
12371
|
pack: packName,
|
|
12340
|
-
dbPath
|
|
12372
|
+
dbPath,
|
|
12373
|
+
scaffolded
|
|
12341
12374
|
}, "json", true) + "\n");
|
|
12342
12375
|
else process.stdout.write(`${successMsg}\n`);
|
|
12343
12376
|
return 0;
|
|
@@ -13479,12 +13512,13 @@ async function runAmendCommand(options) {
|
|
|
13479
13512
|
*/
|
|
13480
13513
|
function registerAutoCommand(program, _version = "0.0.0", projectRoot = process.cwd()) {
|
|
13481
13514
|
const auto = program.command("auto").description("Autonomous implementation pipeline");
|
|
13482
|
-
auto.command("init").description("Initialize a methodology pack and decision store for autonomous pipeline").option("--pack <name>", "Methodology pack name", "bmad").option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").action(async (opts) => {
|
|
13515
|
+
auto.command("init").description("Initialize a methodology pack and decision store for autonomous pipeline").option("--pack <name>", "Methodology pack name", "bmad").option("--project-root <path>", "Project root directory", projectRoot).option("--force", "Overwrite existing local pack with bundled version").option("--output-format <format>", "Output format: human (default) or json", "human").action(async (opts) => {
|
|
13483
13516
|
const outputFormat = opts.outputFormat === "json" ? "json" : "human";
|
|
13484
13517
|
const exitCode = await runAutoInit({
|
|
13485
13518
|
pack: opts.pack,
|
|
13486
13519
|
projectRoot: opts.projectRoot,
|
|
13487
|
-
outputFormat
|
|
13520
|
+
outputFormat,
|
|
13521
|
+
force: opts.force ?? false
|
|
13488
13522
|
});
|
|
13489
13523
|
process.exitCode = exitCode;
|
|
13490
13524
|
});
|
|
@@ -14566,12 +14600,12 @@ const logger = createLogger("cli");
|
|
|
14566
14600
|
/** Resolve the package.json path relative to this file */
|
|
14567
14601
|
async function getPackageVersion() {
|
|
14568
14602
|
try {
|
|
14569
|
-
const __filename$
|
|
14570
|
-
const __dirname$
|
|
14603
|
+
const __filename$2 = fileURLToPath(import.meta.url);
|
|
14604
|
+
const __dirname$2 = dirname(__filename$2);
|
|
14571
14605
|
const paths = [
|
|
14572
|
-
resolve(__dirname$
|
|
14573
|
-
resolve(__dirname$
|
|
14574
|
-
resolve(__dirname$
|
|
14606
|
+
resolve(__dirname$2, "../../package.json"),
|
|
14607
|
+
resolve(__dirname$2, "../package.json"),
|
|
14608
|
+
resolve(__dirname$2, "../../../package.json")
|
|
14575
14609
|
];
|
|
14576
14610
|
for (const pkgPath of paths) try {
|
|
14577
14611
|
const content = await readFile(pkgPath, "utf-8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "substrate-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Substrate — multi-agent orchestration daemon for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
"bin": {
|
|
24
24
|
"substrate": "./dist/cli/index.js"
|
|
25
25
|
},
|
|
26
|
-
"readme": "README.npm.md",
|
|
27
26
|
"main": "./dist/index.js",
|
|
28
27
|
"exports": {
|
|
29
28
|
".": {
|
|
@@ -41,12 +40,11 @@
|
|
|
41
40
|
"dist/**/*.json",
|
|
42
41
|
"dist/cli/templates",
|
|
43
42
|
"packs",
|
|
44
|
-
"README.md"
|
|
45
|
-
"README.npm.md"
|
|
43
|
+
"README.md"
|
|
46
44
|
],
|
|
47
45
|
"scripts": {
|
|
48
46
|
"build": "tsdown",
|
|
49
|
-
"postbuild": "cp -r src/cli/templates dist/cli/templates
|
|
47
|
+
"postbuild": "cp -r src/cli/templates dist/cli/templates",
|
|
50
48
|
"dev": "tsx watch src/cli/index.ts",
|
|
51
49
|
"test": "vitest run --coverage",
|
|
52
50
|
"test:watch": "vitest",
|
package/README.npm.md
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="https://github.com/user-attachments/assets/622dd577-2814-4657-bb28-112ed272486d" alt="Substrate — Autonomous Software Development Pipeline" />
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
# Substrate
|
|
6
|
-
|
|
7
|
-
Autonomous software development pipeline powered by multi-agent orchestration. Substrate takes a project idea from concept through analysis, planning, architecture, implementation, and code review — coordinating CLI-based AI agents (Claude Code, Codex, Gemini CLI) to do the work.
|
|
8
|
-
|
|
9
|
-
Substrate follows a modular monolith pattern running as a single Node.js process. The orchestrator never calls LLMs directly — all intelligent work is delegated to CLI agents running as child processes in isolated git worktrees. The autonomous pipeline compiles BMAD methodology workflows into token-efficient agent dispatches.
|
|
10
|
-
|
|
11
|
-
## Prerequisites
|
|
12
|
-
|
|
13
|
-
- **Node.js** 22.0.0 or later
|
|
14
|
-
- **git** 2.20 or later
|
|
15
|
-
- At least one supported AI CLI agent installed:
|
|
16
|
-
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (`claude`)
|
|
17
|
-
- [Codex CLI](https://github.com/openai/codex) (`codex`)
|
|
18
|
-
- Gemini CLI (`gemini`)
|
|
19
|
-
|
|
20
|
-
## Installation
|
|
21
|
-
|
|
22
|
-
Install as a project dependency:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
npm install substrate-ai
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Or install globally:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install -g substrate-ai
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Verify the installation:
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
npx substrate --version # project install
|
|
38
|
-
substrate --version # global install
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
> Examples below use `[npx] substrate` — include `npx` for project installs, omit for global.
|
|
42
|
-
|
|
43
|
-
## Quick Start
|
|
44
|
-
|
|
45
|
-
### Autonomous Pipeline (recommended)
|
|
46
|
-
|
|
47
|
-
Got an idea? Substrate can take it from concept to working code.
|
|
48
|
-
|
|
49
|
-
1. **Brainstorm** — explore your idea with a multi-persona AI session:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
[npx] substrate brainstorm
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
2. **Initialize the pipeline** — set up the methodology pack and decision store:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
[npx] substrate auto init
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
3. **Run the full pipeline** — analysis, planning, solutioning, and implementation:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
[npx] substrate auto run
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Substrate walks through the entire software development lifecycle autonomously:
|
|
68
|
-
- **Analysis** — generates a product brief from your brainstorm
|
|
69
|
-
- **Planning** — creates a PRD with requirements
|
|
70
|
-
- **Solutioning** — produces architecture, epics, and stories
|
|
71
|
-
- **Implementation** — dispatches agents to build, test, and code-review each story
|
|
72
|
-
|
|
73
|
-
You can start from any phase or resume an interrupted run:
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
[npx] substrate auto run --from solutioning # Skip to a specific phase
|
|
77
|
-
[npx] substrate auto resume # Pick up where you left off
|
|
78
|
-
[npx] substrate auto status # Check pipeline progress
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Pick Up an Existing BMAD Project
|
|
82
|
-
|
|
83
|
-
Already have a project with BMAD artifacts (vanilla BMAD or the Beads-based ai-toolkit)? Substrate can pick up the remaining implementation work. It reads one directory — `_bmad-output/` — and doesn't care which tool created it.
|
|
84
|
-
|
|
85
|
-
**What Substrate needs from your project:**
|
|
86
|
-
|
|
87
|
-
| File | Required? | Purpose |
|
|
88
|
-
|------|-----------|---------|
|
|
89
|
-
| `_bmad-output/planning-artifacts/epics.md` | Yes | Parsed into per-epic context shards |
|
|
90
|
-
| `_bmad-output/planning-artifacts/architecture.md` | Yes | Tech stack and constraints for agents |
|
|
91
|
-
| `_bmad-output/implementation-artifacts/*.md` | Optional | Existing story files — Substrate skips create-story for any it finds |
|
|
92
|
-
| `package.json` | Optional | Test framework detection |
|
|
93
|
-
|
|
94
|
-
**Three commands:**
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
npm install substrate-ai
|
|
98
|
-
[npx] substrate auto init # Seeds context from _bmad-output/
|
|
99
|
-
[npx] substrate auto run --stories 5-3,5-4,6-1 # Only the unfinished story keys
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
For each story, Substrate runs: **create-story** (skipped if story file exists) → **dev-story** (implement) → **code-review** (adversarial review). Non-conflicting stories run in parallel automatically.
|
|
103
|
-
|
|
104
|
-
Substrate does not read `sprint-status.yaml` or `.beads/` — you decide what's left by choosing which story keys to pass.
|
|
105
|
-
|
|
106
|
-
## Supported Agents
|
|
107
|
-
|
|
108
|
-
| Agent ID | CLI Tool | Billing |
|
|
109
|
-
|----------|----------|---------|
|
|
110
|
-
| `claude-code` | Claude Code | Subscription (Max) or API key |
|
|
111
|
-
| `codex` | Codex CLI | Subscription (ChatGPT Plus/Pro) or API key |
|
|
112
|
-
| `gemini` | Gemini CLI | Subscription or API key |
|
|
113
|
-
|
|
114
|
-
## Commands
|
|
115
|
-
|
|
116
|
-
### Pipeline
|
|
117
|
-
|
|
118
|
-
| Command | Description |
|
|
119
|
-
|---------|-------------|
|
|
120
|
-
| `substrate brainstorm` | Interactive multi-persona ideation session |
|
|
121
|
-
| `substrate auto init` | Initialize methodology pack for autonomous pipeline |
|
|
122
|
-
| `substrate auto run` | Run the full pipeline (analysis → implement) |
|
|
123
|
-
| `substrate auto run --from <phase>` | Start from a specific phase |
|
|
124
|
-
| `substrate auto resume` | Resume an interrupted pipeline run |
|
|
125
|
-
| `substrate auto status` | Show pipeline run status |
|
|
126
|
-
|
|
127
|
-
### Monitoring
|
|
128
|
-
|
|
129
|
-
| Command | Description |
|
|
130
|
-
|---------|-------------|
|
|
131
|
-
| `substrate monitor status` | View task metrics and agent performance |
|
|
132
|
-
| `substrate monitor report` | Generate a detailed performance report |
|
|
133
|
-
| `substrate cost-report` | View cost and token usage summary |
|
|
134
|
-
|
|
135
|
-
### Setup
|
|
136
|
-
|
|
137
|
-
| Command | Description |
|
|
138
|
-
|---------|-------------|
|
|
139
|
-
| `substrate init` | Initialize project configuration |
|
|
140
|
-
| `substrate --help` | Show all available commands |
|
|
141
|
-
|
|
142
|
-
## Configuration
|
|
143
|
-
|
|
144
|
-
Substrate reads configuration from `.substrate/config.yaml` in your project root. Run `[npx] substrate init` to generate a default config.
|
|
145
|
-
|
|
146
|
-
## Development
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
# Clone and install
|
|
150
|
-
git clone https://github.com/johnplanow/substrate.git
|
|
151
|
-
cd substrate
|
|
152
|
-
npm install
|
|
153
|
-
|
|
154
|
-
# Build
|
|
155
|
-
npm run build
|
|
156
|
-
|
|
157
|
-
# Run tests
|
|
158
|
-
npm test
|
|
159
|
-
|
|
160
|
-
# Development mode (watch)
|
|
161
|
-
npm run dev
|
|
162
|
-
|
|
163
|
-
# Type check
|
|
164
|
-
npm run typecheck
|
|
165
|
-
|
|
166
|
-
# Lint
|
|
167
|
-
npm run lint
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
## Manual Task Graphs
|
|
171
|
-
|
|
172
|
-
For fine-grained control, you can define exactly what agents should do in a YAML task graph:
|
|
173
|
-
|
|
174
|
-
```yaml
|
|
175
|
-
version: "1"
|
|
176
|
-
session:
|
|
177
|
-
name: "my-tasks"
|
|
178
|
-
tasks:
|
|
179
|
-
write-tests:
|
|
180
|
-
name: "Write unit tests"
|
|
181
|
-
prompt: |
|
|
182
|
-
Look at the src/utils/ directory.
|
|
183
|
-
Write comprehensive unit tests for all exported functions.
|
|
184
|
-
type: testing
|
|
185
|
-
agent: claude-code
|
|
186
|
-
update-docs:
|
|
187
|
-
name: "Update README"
|
|
188
|
-
prompt: |
|
|
189
|
-
Read the README.md and verify it accurately describes
|
|
190
|
-
the project. Fix any inaccuracies.
|
|
191
|
-
type: docs
|
|
192
|
-
agent: codex
|
|
193
|
-
depends_on:
|
|
194
|
-
- write-tests
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
```bash
|
|
198
|
-
[npx] substrate start --graph tasks.yaml # Execute the graph
|
|
199
|
-
[npx] substrate plan --graph tasks.yaml # Preview without running
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
Tasks without dependencies run in parallel. Each agent gets its own isolated git worktree.
|
|
203
|
-
|
|
204
|
-
## License
|
|
205
|
-
|
|
206
|
-
MIT
|