@boopkit/cli 0.6.11 → 0.6.13
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 +26 -5
- package/dist/capability-catalog.json +11 -0
- package/dist/capability-versions.json +2 -1
- package/dist/cli.js +2 -1
- package/dist/commands/add.js +49 -2
- package/dist/commands/init.d.ts +17 -1
- package/dist/commands/init.js +149 -25
- package/dist/commands/loop-merge.d.ts +1 -0
- package/dist/commands/loop-merge.js +4 -2
- package/dist/commands/loop.d.ts +21 -2
- package/dist/commands/loop.js +105 -16
- package/dist/commands/loop.js.orig-pre-maxbuffer +1455 -0
- package/dist/lib/execute.js +1 -1
- package/dist/lib/scaffold.d.ts +26 -9
- package/dist/lib/scaffold.js +60 -18
- package/docs/init.md +132 -86
- package/docs/loop.md +16 -0
- package/package.json +3 -2
- package/profiles/base/profile.md +105 -0
- package/profiles/base/templates/.github/copilot-instructions.md +3 -0
- package/profiles/base/templates/.gitignore.hbs +6 -0
- package/profiles/base/templates/AGENTS.md.hbs +50 -0
- package/profiles/base/templates/CLAUDE.md.hbs +3 -0
- package/profiles/base/templates/README.md.hbs +15 -0
- package/profiles/base/templates/docs/README.md +12 -0
- package/profiles/base/templates/package.json.hbs +7 -0
- package/profiles/base/templates/reference/README.md +16 -0
- package/profiles/base/templates/specs/README.md +12 -0
- package/profiles/development/profile.md +8 -1
package/dist/lib/execute.js
CHANGED
|
@@ -127,7 +127,7 @@ function executeTask(task, manifest) {
|
|
|
127
127
|
case 'link-package': {
|
|
128
128
|
const data = task.data;
|
|
129
129
|
(0, scaffold_1.mergePackageJson)(targetDir, undefined, undefined, {
|
|
130
|
-
[data.packageName]: (0, scaffold_1.getBoopkitVersion)(data.packageName),
|
|
130
|
+
[data.packageName]: (0, scaffold_1.getBoopkitVersion)(data.packageName, [targetDir]),
|
|
131
131
|
}, { skipBackup: true });
|
|
132
132
|
break;
|
|
133
133
|
}
|
package/dist/lib/scaffold.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { CapabilityHook } from './config';
|
|
2
2
|
export interface TemplateVariables {
|
|
3
3
|
projectName: string;
|
|
4
|
-
port
|
|
5
|
-
scripts
|
|
6
|
-
nodeVersion
|
|
4
|
+
port?: number;
|
|
5
|
+
scripts?: Record<string, string>;
|
|
6
|
+
nodeVersion?: string;
|
|
7
7
|
hookImports?: string;
|
|
8
8
|
hookInit?: string;
|
|
9
9
|
hookPreRoutes?: string;
|
|
@@ -21,11 +21,22 @@ export interface TemplateVariables {
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function renderTemplate(templateContent: string, variables: TemplateVariables): string;
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* Resolve the template directory `boop init` renders for a profile.
|
|
25
|
+
*
|
|
26
|
+
* A profile that ships its own `profiles/<name>/templates/` folder gets that
|
|
27
|
+
* folder, which must be complete on its own — nothing is merged from the kernel.
|
|
28
|
+
* Every other profile falls back to `src/templates/kernel/`. The fallback is
|
|
29
|
+
* what keeps `web-app`, which ships no templates/ folder, scaffolding exactly
|
|
30
|
+
* what it always has.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getTemplatesDir(profileName: string): string;
|
|
33
|
+
export declare function profileHasTemplates(profileName: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Copy and render every file in a templates directory (the kernel templates
|
|
36
|
+
* by default) into a target directory. Creates directories as needed. Does
|
|
37
|
+
* not overwrite existing files unless overwrite is true.
|
|
27
38
|
*/
|
|
28
|
-
export declare function scaffoldKernel(targetDir: string, variables: TemplateVariables, overwrite?: boolean): string[];
|
|
39
|
+
export declare function scaffoldKernel(targetDir: string, variables: TemplateVariables, overwrite?: boolean, templatesDir?: string): string[];
|
|
29
40
|
/**
|
|
30
41
|
* Compute SHA-256 hash of a file's content.
|
|
31
42
|
*/
|
|
@@ -64,11 +75,17 @@ export declare function linkSkillsToClaude(targetDir: string, only?: Iterable<st
|
|
|
64
75
|
* Read the version from a @boopkit/ package's package.json and return ^version.
|
|
65
76
|
* Fallback chain:
|
|
66
77
|
* 1. Monorepo packages/ dir (development)
|
|
67
|
-
* 2. require.resolve from CLI's node_modules
|
|
78
|
+
* 2. require.resolve from `searchPaths`, then the CLI's node_modules
|
|
68
79
|
* 3. dist/capability-versions.json (baked at build time for npm installs)
|
|
69
80
|
* 4. '*' (last resort)
|
|
81
|
+
*
|
|
82
|
+
* `searchPaths` is where the *project* is, and it comes before the CLI root for
|
|
83
|
+
* the same reason `planAdd` passes it: the package a project is being given may
|
|
84
|
+
* only exist under that project — npm-linked from a worktree, or installed by
|
|
85
|
+
* `boop add`'s own phase 0 — and reading only the CLI root then falls all the
|
|
86
|
+
* way through to `'*'`, which is not a version any install can resolve.
|
|
70
87
|
*/
|
|
71
|
-
export declare function getBoopkitVersion(packageName: string): string;
|
|
88
|
+
export declare function getBoopkitVersion(packageName: string, searchPaths?: string[]): string;
|
|
72
89
|
/**
|
|
73
90
|
* The warning shown when a dependency lands in a project's package.json with no
|
|
74
91
|
* version range. Written to be actionable by an agent reading it in a
|
package/dist/lib/scaffold.js
CHANGED
|
@@ -37,6 +37,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.renderTemplate = renderTemplate;
|
|
40
|
+
exports.getTemplatesDir = getTemplatesDir;
|
|
41
|
+
exports.profileHasTemplates = profileHasTemplates;
|
|
40
42
|
exports.scaffoldKernel = scaffoldKernel;
|
|
41
43
|
exports.hashFile = hashFile;
|
|
42
44
|
exports.copyCapabilityFiles = copyCapabilityFiles;
|
|
@@ -68,19 +70,33 @@ function renderTemplate(templateContent, variables) {
|
|
|
68
70
|
const compiled = handlebars_1.default.compile(templateContent, { noEscape: true });
|
|
69
71
|
return compiled(variables);
|
|
70
72
|
}
|
|
73
|
+
function getKernelTemplatesDir() {
|
|
74
|
+
return path.join((0, config_1.getBoopRoot)(), 'src', 'templates', 'kernel');
|
|
75
|
+
}
|
|
71
76
|
/**
|
|
72
|
-
*
|
|
77
|
+
* Resolve the template directory `boop init` renders for a profile.
|
|
78
|
+
*
|
|
79
|
+
* A profile that ships its own `profiles/<name>/templates/` folder gets that
|
|
80
|
+
* folder, which must be complete on its own — nothing is merged from the kernel.
|
|
81
|
+
* Every other profile falls back to `src/templates/kernel/`. The fallback is
|
|
82
|
+
* what keeps `web-app`, which ships no templates/ folder, scaffolding exactly
|
|
83
|
+
* what it always has.
|
|
73
84
|
*/
|
|
74
|
-
function getTemplatesDir() {
|
|
75
|
-
return
|
|
85
|
+
function getTemplatesDir(profileName) {
|
|
86
|
+
return profileHasTemplates(profileName) ? getProfileTemplatesDir(profileName) : getKernelTemplatesDir();
|
|
87
|
+
}
|
|
88
|
+
function profileHasTemplates(profileName) {
|
|
89
|
+
return fs.existsSync(getProfileTemplatesDir(profileName));
|
|
90
|
+
}
|
|
91
|
+
function getProfileTemplatesDir(profileName) {
|
|
92
|
+
return path.join((0, config_1.getBoopRoot)(), 'profiles', profileName, 'templates');
|
|
76
93
|
}
|
|
77
94
|
/**
|
|
78
|
-
* Copy and render
|
|
79
|
-
* Creates directories as needed. Does
|
|
80
|
-
* unless overwrite is true.
|
|
95
|
+
* Copy and render every file in a templates directory (the kernel templates
|
|
96
|
+
* by default) into a target directory. Creates directories as needed. Does
|
|
97
|
+
* not overwrite existing files unless overwrite is true.
|
|
81
98
|
*/
|
|
82
|
-
function scaffoldKernel(targetDir, variables, overwrite = false) {
|
|
83
|
-
const templatesDir = getTemplatesDir();
|
|
99
|
+
function scaffoldKernel(targetDir, variables, overwrite = false, templatesDir = getKernelTemplatesDir()) {
|
|
84
100
|
const written = [];
|
|
85
101
|
function processDir(srcDir, destDir) {
|
|
86
102
|
if (!fs.existsSync(destDir)) {
|
|
@@ -101,12 +117,13 @@ function scaffoldKernel(targetDir, variables, overwrite = false) {
|
|
|
101
117
|
if (!overwrite && fs.existsSync(destPath)) {
|
|
102
118
|
continue;
|
|
103
119
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
// Only .hbs files are text by contract; anything else may be binary, so copy its bytes untouched
|
|
121
|
+
if (entry.name.endsWith('.hbs')) {
|
|
122
|
+
fs.writeFileSync(destPath, renderTemplate(fs.readFileSync(srcPath, 'utf-8'), variables), 'utf-8');
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
fs.copyFileSync(srcPath, destPath);
|
|
126
|
+
}
|
|
110
127
|
written.push(path.relative(targetDir, destPath));
|
|
111
128
|
}
|
|
112
129
|
}
|
|
@@ -128,7 +145,11 @@ function hashFile(filePath) {
|
|
|
128
145
|
* Returns list of copied file paths relative to targetDir, and file hashes.
|
|
129
146
|
*/
|
|
130
147
|
function copyCapabilityFiles(targetDir, capabilityName, searchPaths) {
|
|
131
|
-
|
|
148
|
+
// Default to the project itself, so this resolves the capability to the same
|
|
149
|
+
// package `planAdd` did. Without it a capability that lives only under the
|
|
150
|
+
// project resolved here to nothing, and `boop add` reported every file copied
|
|
151
|
+
// while copying none (boop-2vdy.8.5).
|
|
152
|
+
const pkgDir = (0, capability_1.getPackageDir)(capabilityName, searchPaths ?? [targetDir]);
|
|
132
153
|
if (pkgDir) {
|
|
133
154
|
// Read package.json for boopkit config
|
|
134
155
|
const pkgJsonPath = path.join(pkgDir, 'package.json');
|
|
@@ -266,11 +287,17 @@ function updateCapabilityHashes(targetDir, capabilityName, fileHashes, version)
|
|
|
266
287
|
* Read the version from a @boopkit/ package's package.json and return ^version.
|
|
267
288
|
* Fallback chain:
|
|
268
289
|
* 1. Monorepo packages/ dir (development)
|
|
269
|
-
* 2. require.resolve from CLI's node_modules
|
|
290
|
+
* 2. require.resolve from `searchPaths`, then the CLI's node_modules
|
|
270
291
|
* 3. dist/capability-versions.json (baked at build time for npm installs)
|
|
271
292
|
* 4. '*' (last resort)
|
|
293
|
+
*
|
|
294
|
+
* `searchPaths` is where the *project* is, and it comes before the CLI root for
|
|
295
|
+
* the same reason `planAdd` passes it: the package a project is being given may
|
|
296
|
+
* only exist under that project — npm-linked from a worktree, or installed by
|
|
297
|
+
* `boop add`'s own phase 0 — and reading only the CLI root then falls all the
|
|
298
|
+
* way through to `'*'`, which is not a version any install can resolve.
|
|
272
299
|
*/
|
|
273
|
-
function getBoopkitVersion(packageName) {
|
|
300
|
+
function getBoopkitVersion(packageName, searchPaths) {
|
|
274
301
|
const pkgName = packageName.replace(/^@boopkit\//, '');
|
|
275
302
|
// Try monorepo packages/ directory first (development)
|
|
276
303
|
const monorepoPkgJsonPath = path.join((0, config_1.getBoopRoot)(), 'packages', pkgName, 'package.json');
|
|
@@ -281,10 +308,25 @@ function getBoopkitVersion(packageName) {
|
|
|
281
308
|
catch {
|
|
282
309
|
// Not in monorepo — try require.resolve (published CLI install)
|
|
283
310
|
}
|
|
311
|
+
// Then the node_modules of each search path, read straight off disk rather
|
|
312
|
+
// than through require.resolve — the package being read may have no build
|
|
313
|
+
// output yet, and a resolver is entitled to refuse a package whose `main`
|
|
314
|
+
// does not exist.
|
|
315
|
+
for (const searchPath of [...(searchPaths ?? []), (0, config_1.getBoopRoot)()]) {
|
|
316
|
+
try {
|
|
317
|
+
const installedPath = path.join(searchPath, 'node_modules', packageName, 'package.json');
|
|
318
|
+
const pkg = JSON.parse(fs.readFileSync(installedPath, 'utf-8'));
|
|
319
|
+
if (pkg.version)
|
|
320
|
+
return `^${pkg.version}`;
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
// Not installed under this path — try the next
|
|
324
|
+
}
|
|
325
|
+
}
|
|
284
326
|
// Try resolving the installed package
|
|
285
327
|
try {
|
|
286
328
|
const resolvedPath = require.resolve(`${packageName}/package.json`, {
|
|
287
|
-
paths: [(0, config_1.getBoopRoot)()],
|
|
329
|
+
paths: [...(searchPaths ?? []), (0, config_1.getBoopRoot)()],
|
|
288
330
|
});
|
|
289
331
|
const pkg = JSON.parse(fs.readFileSync(resolvedPath, 'utf-8'));
|
|
290
332
|
return `^${pkg.version}`;
|
package/docs/init.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# boop init
|
|
2
2
|
|
|
3
|
-
`boop init` is the command you run when you want a real starting point quickly.
|
|
3
|
+
`boop init` is the command you run when you want a real starting point quickly.
|
|
4
|
+
It creates a new project directory, applies a boop profile, writes a `.boop/config.json` manifest, and, unless you opt out, installs npm dependencies and sets up the project's beads issue tracker.
|
|
5
|
+
The goal is simple: get you to a local project you can work in, extend, and keep clean as both humans and agents start contributing.
|
|
4
6
|
|
|
5
7
|
## Synopsis
|
|
6
8
|
|
|
@@ -10,9 +12,15 @@ boop init <name> --profile <profile>
|
|
|
10
12
|
|
|
11
13
|
If you omit `--profile`, Boop uses `web-app`.
|
|
12
14
|
|
|
15
|
+
`<name>` can be a plain name or a path such as `~/work/aws-setup`.
|
|
16
|
+
Either way, the project is named after its folder, `aws-setup` in that example:
|
|
17
|
+
that is the name in `package.json`, `.boop/config.json` and the README heading, and the beads issue prefix.
|
|
18
|
+
|
|
13
19
|
## Before You Run It
|
|
14
20
|
|
|
15
|
-
The
|
|
21
|
+
The `web-app` profile requires Node 24 or newer.
|
|
22
|
+
If your Node version is too old, `boop init` exits before creating the directory and prints an upgrade hint.
|
|
23
|
+
The `base` profile names no runtime, so it has no version to check.
|
|
16
24
|
|
|
17
25
|
## Available Profiles
|
|
18
26
|
|
|
@@ -27,110 +35,154 @@ Current output:
|
|
|
27
35
|
```text
|
|
28
36
|
Available profiles:
|
|
29
37
|
|
|
38
|
+
base
|
|
39
|
+
Planning, writing and issue tracking for a project that isn't an application
|
|
40
|
+
capabilities:
|
|
41
|
+
Development: project-mgmt, product-design, skills
|
|
42
|
+
|
|
43
|
+
development
|
|
44
|
+
Development skills only — for a project with no application domain (a CLI, a library, a data pipeline)
|
|
45
|
+
capabilities:
|
|
46
|
+
Development: coding, testing, project-mgmt, product-design, skills, workflows
|
|
47
|
+
|
|
30
48
|
web-app
|
|
31
|
-
Full-stack web application (Express + Handlebars + Tailwind
|
|
32
|
-
capabilities: web, api, database
|
|
49
|
+
Full-stack web application (Express + Handlebars + Tailwind)
|
|
33
50
|
runtime: node | deploy: heroku | port: 3000
|
|
51
|
+
capabilities:
|
|
52
|
+
Application: web, api, services, database
|
|
53
|
+
Development: coding, testing, project-mgmt, product-design, skills, workflows
|
|
54
|
+
Demo: hello
|
|
34
55
|
```
|
|
35
56
|
|
|
36
|
-
`
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
`boop init` can scaffold from two of these.
|
|
58
|
+
`web-app` carries a kernel, the configuration for a running application, and renders an Express server from it.
|
|
59
|
+
`base` has no kernel, but it ships templates of its own,
|
|
60
|
+
so it renders a project for planning, writing and tracking work instead:
|
|
61
|
+
agent instructions, a README in each of `specs/`, `reference/` and `docs/`,
|
|
62
|
+
and the planning and writing skills, with no application code at all.
|
|
63
|
+
|
|
64
|
+
The third profile, `development`, carries development capabilities and no application domain.
|
|
65
|
+
It has neither a kernel nor templates, so there is nothing for `boop init` to write,
|
|
66
|
+
and `boop init --profile development` is refused with a pointer to the two ways it is meant to be used:
|
|
40
67
|
naming it as the `profile` in an existing project's `.boop/config.json`,
|
|
41
68
|
or `boop add` for the capabilities you want.
|
|
42
69
|
|
|
43
70
|
## What It Creates
|
|
44
71
|
|
|
45
|
-
Running `boop init my-saas --profile web-app --no-install` creates a project like this:
|
|
72
|
+
Running `boop init my-saas --profile web-app --no-install --no-beads` creates a project like this, shown to two levels:
|
|
46
73
|
|
|
47
74
|
```text
|
|
48
75
|
my-saas/
|
|
49
|
-
.boop
|
|
76
|
+
.boop/
|
|
77
|
+
config.json
|
|
78
|
+
.env
|
|
79
|
+
.env.example
|
|
80
|
+
.github/
|
|
81
|
+
copilot-instructions.md
|
|
50
82
|
.gitignore
|
|
83
|
+
AGENTS.md
|
|
84
|
+
CLAUDE.md
|
|
51
85
|
Procfile
|
|
52
86
|
README.md
|
|
87
|
+
jest.config.js
|
|
53
88
|
package.json
|
|
89
|
+
prisma/
|
|
90
|
+
schema/
|
|
91
|
+
public/
|
|
92
|
+
css/
|
|
93
|
+
favicon.svg
|
|
54
94
|
reference/
|
|
55
|
-
architecture
|
|
56
|
-
message-queue-patterns.ref.md
|
|
95
|
+
(architecture, database, REST API, service layer and web UI pages, among others)
|
|
57
96
|
skills/
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
SKILL.md
|
|
62
|
-
boop-coding-commit-changes/
|
|
63
|
-
SKILL.md
|
|
64
|
-
boop-coding-development/
|
|
65
|
-
SKILL.md
|
|
66
|
-
boop-coding-review-changes/
|
|
67
|
-
SKILL.md
|
|
68
|
-
boop-database-data-model/
|
|
69
|
-
SKILL.md
|
|
70
|
-
boop-database-prisma/
|
|
71
|
-
SKILL.md
|
|
72
|
-
boop-product-design-engineering-design/
|
|
73
|
-
SKILL.md
|
|
74
|
-
boop-product-design-feature-documentation/
|
|
75
|
-
SKILL.md
|
|
76
|
-
boop-product-design-feature-requirements/
|
|
77
|
-
SKILL.md
|
|
78
|
-
boop-product-design-reference-integration/
|
|
79
|
-
SKILL.md
|
|
80
|
-
boop-project-mgmt-beads-planning/
|
|
81
|
-
SKILL.md
|
|
82
|
-
boop-project-mgmt-engineering-planning/
|
|
83
|
-
SKILL.md
|
|
84
|
-
boop-services-controllers/
|
|
85
|
-
SKILL.md
|
|
86
|
-
boop-services-services/
|
|
87
|
-
SKILL.md
|
|
88
|
-
boop-skill-authoring/
|
|
89
|
-
SKILL.md
|
|
90
|
-
boop-testing-tdd-light/
|
|
91
|
-
SKILL.md
|
|
92
|
-
boop-testing-testing/
|
|
93
|
-
SKILL.md
|
|
94
|
-
boop-testing-testing-express-web/
|
|
95
|
-
SKILL.md
|
|
96
|
-
boop-web-web-ui-design/
|
|
97
|
-
SKILL.md
|
|
97
|
+
(40 skill folders from the installed capabilities)
|
|
98
|
+
specs/
|
|
99
|
+
README.md
|
|
98
100
|
src/
|
|
101
|
+
app.ts
|
|
102
|
+
controllers/
|
|
103
|
+
db.ts
|
|
99
104
|
lib/
|
|
100
|
-
|
|
105
|
+
middleware/
|
|
106
|
+
routes/
|
|
107
|
+
scripts/
|
|
101
108
|
server.ts
|
|
109
|
+
services/
|
|
110
|
+
styles/
|
|
111
|
+
tailwind.config.ts
|
|
112
|
+
tests/
|
|
102
113
|
tsconfig.json
|
|
114
|
+
tsconfig.test.json
|
|
115
|
+
views/
|
|
103
116
|
```
|
|
104
117
|
|
|
105
118
|
That scaffold breaks down into a few parts:
|
|
106
119
|
|
|
107
|
-
- Kernel files: `.gitignore`, `Procfile`, `README.md`, `package.json`, `tsconfig.json`, `src/server.ts`,
|
|
120
|
+
- Kernel files, rendered from boop's kernel templates: `.github/copilot-instructions.md`, `.gitignore`, `AGENTS.md`, `CLAUDE.md`, `Procfile`, `README.md`, `package.json`, `tsconfig.json`, `src/app.ts`, `src/server.ts`, `src/lib/.gitkeep`, `specs/README.md` and `reference/boop-guide.ref.md`
|
|
108
121
|
- Profile reference docs: copied into `reference/`
|
|
109
|
-
-
|
|
110
|
-
- Project manifest: `.boop.json` records the project name, profile, boop version, installed capabilities, and creation timestamp
|
|
111
|
-
- Capability install effects: default capability dependencies and scripts are merged into `package.json`, and
|
|
122
|
+
- Capability files: each capability's skills are copied into `skills/`, and its scaffold files (`src/`, `views/`, `styles/`, `prisma/`, `tests/` and so on) into the project
|
|
123
|
+
- Project manifest: `.boop/config.json` records the project name, profile, boop version, installed capabilities, the hashes of the files each capability wrote, and the creation timestamp
|
|
124
|
+
- Capability install effects: default capability dependencies and scripts are merged into `package.json`, and any environment variables a capability needs are written to `.env` and `.env.example`
|
|
112
125
|
|
|
113
126
|
For the `web-app` profile, the default capabilities are:
|
|
114
127
|
|
|
115
|
-
- `web`
|
|
116
|
-
- `
|
|
117
|
-
- `
|
|
118
|
-
|
|
119
|
-
At the moment, those capabilities show up most clearly in `package.json`, `skills/`, and `.boop.json`. The initial source tree is still small: the kernel server entry point plus the copied reference and skill material.
|
|
128
|
+
- Application: `web`, `api`, `services`, `database`
|
|
129
|
+
- Development: `coding`, `testing`, `project-mgmt`, `product-design`, `skills`, `workflows`
|
|
130
|
+
- Demo: `hello`
|
|
120
131
|
|
|
121
132
|
Beyond the defaults, optional capabilities are available to add later with `boop add <capability>`. For example, `users-and-accounts` adds user management and authentication, and `noticeboard` provides a fuller service-layer reference demo. See the profile documentation for the complete list.
|
|
122
133
|
|
|
134
|
+
The `base` profile makes a much smaller project.
|
|
135
|
+
Running `boop init notes --profile base --no-install --no-beads` creates this:
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
notes/
|
|
139
|
+
.boop/
|
|
140
|
+
config.json
|
|
141
|
+
.github/
|
|
142
|
+
copilot-instructions.md
|
|
143
|
+
.gitignore
|
|
144
|
+
AGENTS.md
|
|
145
|
+
CLAUDE.md
|
|
146
|
+
README.md
|
|
147
|
+
docs/
|
|
148
|
+
README.md
|
|
149
|
+
package.json
|
|
150
|
+
reference/
|
|
151
|
+
README.md
|
|
152
|
+
skills/
|
|
153
|
+
(16 skill folders from project-mgmt, product-design and skills)
|
|
154
|
+
specs/
|
|
155
|
+
README.md
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
There is no `src/`, no test setup and no server to start.
|
|
159
|
+
The `package.json` holds only the capability packages, the `bd` dependency and two `bd:` scripts;
|
|
160
|
+
it is there because it is how boop records the capabilities and refreshes their skills with `boop update`.
|
|
161
|
+
Without `--no-beads`, the project also has a `.beads/` folder and a git repository with two commits, as described under `--no-beads` below.
|
|
162
|
+
|
|
123
163
|
## Options
|
|
124
164
|
|
|
125
165
|
- `--profile <profile>`: choose which profile to initialize. Defaults to `web-app`.
|
|
126
166
|
- `--no-install`: skip `npm install`. This is useful if you want to inspect or adjust the scaffold before installing dependencies.
|
|
167
|
+
- `--no-beads`: skip the beads setup.
|
|
168
|
+
By default, when the profile installs `project-mgmt` (as `web-app` and `base` both do), Boop's last step is `bd init --non-interactive --server -p <name>`,
|
|
169
|
+
where the issue prefix is the project folder's name even when you pass a path such as `~/work/aws-setup`.
|
|
170
|
+
That creates the project's beads issue database in Dolt server mode and starts its Dolt server,
|
|
171
|
+
so `bd create` works straight away and `boop loop` can run in the project without first migrating it to server mode.
|
|
172
|
+
Pass `--no-beads` for a throwaway scaffold or a CI run; the command is printed under "Next steps" so you can run it later.
|
|
173
|
+
If `bd` is not installed, or `bd init` fails, init still succeeds and prints the same command.
|
|
174
|
+
|
|
175
|
+
Just before `bd init`, Boop creates a git repository in the new project and commits the scaffold, so the project starts with two commits (the scaffold, then beads) and a clean `git status`.
|
|
176
|
+
With `--no-beads`, Boop leaves git alone.
|
|
177
|
+
If git has no `user.name` and `user.email` configured, Boop skips its commit and tells you; it never sets an identity for you.
|
|
178
|
+
If the new project is inside another git repository, Boop skips both the commit and `bd init` and tells you why, because `bd init` would commit into that repository and redirect its git hooks.
|
|
127
179
|
|
|
128
180
|
If you do not pass `--no-install`, Boop runs `npm install` after scaffolding and then prints the same next-step summary.
|
|
129
181
|
|
|
130
|
-
## Example: Initialize Without Installing
|
|
182
|
+
## Example: Initialize Without Installing or Setting Up Beads
|
|
131
183
|
|
|
132
184
|
```bash
|
|
133
|
-
boop init my-saas --profile web-app --no-install
|
|
185
|
+
boop init my-saas --profile web-app --no-install --no-beads
|
|
134
186
|
```
|
|
135
187
|
|
|
136
188
|
Expected output:
|
|
@@ -138,43 +190,37 @@ Expected output:
|
|
|
138
190
|
```text
|
|
139
191
|
Created project "my-saas" with profile "web-app"
|
|
140
192
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
package.json
|
|
146
|
-
src/lib/.gitkeep
|
|
147
|
-
src/server.ts
|
|
148
|
-
tsconfig.json
|
|
149
|
-
|
|
150
|
-
Capabilities: web, api, database
|
|
151
|
-
|
|
152
|
-
Scripts added:
|
|
153
|
-
tailwind:build: npx @tailwindcss/cli -i src/public/css/input.css -o src/public/css/style.css --minify
|
|
154
|
-
tailwind:watch: npx @tailwindcss/cli -i src/public/css/input.css -o src/public/css/style.css --watch
|
|
155
|
-
db:migrate: prisma migrate dev --schema=prisma/schema/
|
|
156
|
-
db:deploy: prisma migrate deploy --schema=prisma/schema/
|
|
157
|
-
db:seed: prisma db seed --schema=prisma/schema/
|
|
158
|
-
db:generate: prisma generate --schema=prisma/schema/
|
|
159
|
-
db:studio: prisma studio --schema=prisma/schema/
|
|
193
|
+
13 kernel files · 11 capabilities · 68 capability files · 13 scripts
|
|
194
|
+
Application: web, api, services, database
|
|
195
|
+
Development: coding, testing, project-mgmt, product-design, skills, workflows
|
|
196
|
+
Demo: hello
|
|
160
197
|
|
|
161
198
|
Next steps:
|
|
162
199
|
cd my-saas
|
|
163
200
|
npm install
|
|
164
|
-
|
|
201
|
+
bd init --non-interactive --server -p my-saas
|
|
202
|
+
boop status ← check what needs configuration
|
|
203
|
+
npm run dev ← start development server
|
|
165
204
|
```
|
|
166
205
|
|
|
206
|
+
The counts change as capabilities grow.
|
|
207
|
+
A `base` project's summary counts template files rather than kernel files,
|
|
208
|
+
and its next steps stop at `boop status`, because there is no development server to start.
|
|
209
|
+
|
|
167
210
|
## What To Do After Init
|
|
168
211
|
|
|
169
|
-
|
|
212
|
+
Run the commands under "Next steps".
|
|
213
|
+
If you used `--no-install` and `--no-beads`, that is:
|
|
170
214
|
|
|
171
215
|
```bash
|
|
172
216
|
cd my-saas
|
|
173
217
|
npm install
|
|
218
|
+
bd init --non-interactive --server -p my-saas
|
|
219
|
+
boop status
|
|
174
220
|
npm run dev
|
|
175
221
|
```
|
|
176
222
|
|
|
177
|
-
If you let Boop install dependencies for you, the shorter version is:
|
|
223
|
+
If you let Boop install dependencies and set up beads for you, the shorter version is:
|
|
178
224
|
|
|
179
225
|
```bash
|
|
180
226
|
cd my-saas
|
package/docs/loop.md
CHANGED
|
@@ -122,6 +122,21 @@ Session logs are written to `labs/claude-runs/` in the project directory. Each i
|
|
|
122
122
|
- **Budget caps** — each issue is capped at `--budget` USD
|
|
123
123
|
- **Resume limits** — prevents infinite retry loops (default: 3 attempts)
|
|
124
124
|
- **Permission skipping** — enabled by default for unattended operation; use `--no-skip-perms` to require approval for each tool call
|
|
125
|
+
- **A failed queue read is never a clean finish** — if the loop cannot read the ready queue it says so and stops with exit code 1, rather than reporting "No more ready issues" and exiting 0. See [Reading the ready queue](#reading-the-ready-queue).
|
|
126
|
+
|
|
127
|
+
## Reading the ready queue
|
|
128
|
+
|
|
129
|
+
The loop reads claimable work with `bd ready --json -n 0`, projected through `jq` to the only three fields its filters use: `id`, `issue_type` and `parent`.
|
|
130
|
+
|
|
131
|
+
The projection matters because `bd ready --json` returns every ready issue *with its full description*. In a repo with 112 ready issues that is 274,529 bytes, roughly 70% of it description the loop never looks at; projected, the same read is 5,941 bytes. Node captures at most 1 MiB from a subprocess by default and fails past it, so an unprojected read on a mature backlog dies — and a dead read used to be indistinguishable from an empty queue, which is how a loop could stop early with work still ready.
|
|
132
|
+
|
|
133
|
+
**`jq` is recommended but not required.** It ships with neither stock macOS nor stock Debian, so when it is missing the loop warns once and falls back to the unprojected read. That stays safe because every `bd` read is capped at 256 MiB rather than the 1 MiB default. Install `jq` to keep the read small:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
brew install jq
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
If the ready queue cannot be read at all, the loop says which command failed and stops with exit code 1 rather than reporting a clean finish. Under `--poll` it logs the failure and retries on the next interval.
|
|
125
140
|
|
|
126
141
|
## Planning Mode
|
|
127
142
|
|
|
@@ -167,6 +182,7 @@ The prefix is included in the planning prompt as a suggestion for naming the fea
|
|
|
167
182
|
- **Flags used separately** — `--work` without `--flow` (or vice versa) prints an error. They must be used together.
|
|
168
183
|
- **Feature ID not found** — If the planning session doesn't output `FEATURE_ID=<id>` and the fallback query finds no matching recent feature, the command exits with an error and points to the session log for debugging.
|
|
169
184
|
- **Planning session limit hit** — If the Claude session hits a usage limit, the command exits without proceeding to the loop phase.
|
|
185
|
+
- **Ready-queue read failure** — If `bd ready` cannot be read, the loop reports the failing command and stops with exit code 1; it never reports a clean finish on a read it could not make.
|
|
170
186
|
|
|
171
187
|
Planning session logs are written to `labs/claude-runs/` with the prefix `_planning_`.
|
|
172
188
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boopkit/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.13",
|
|
4
4
|
"description": "boop: the opinionated bootstrap for founder friendly, AI-first web apps - code plus agent skills, composable from day one.",
|
|
5
5
|
"main": "dist/cli.js",
|
|
6
6
|
"workspaces": [
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
|
-
"build": "tsc && node tools/generate-version-manifest.js",
|
|
24
|
+
"build": "npm run build:caps && tsc && node tools/generate-version-manifest.js",
|
|
25
|
+
"build:cli": "tsc && node tools/generate-version-manifest.js",
|
|
25
26
|
"typecheck": "tsc -p tsconfig.test.json",
|
|
26
27
|
"skills:index": "node tools/generate-skills-index.js",
|
|
27
28
|
"skills:layout": "tsx tools/generate-installed-layout.ts",
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: base
|
|
3
|
+
description: Planning, writing and issue tracking for a project that isn't an application
|
|
4
|
+
defaultCapabilities:
|
|
5
|
+
- project-mgmt
|
|
6
|
+
- product-design
|
|
7
|
+
- skills
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Base Profile
|
|
11
|
+
|
|
12
|
+
The part of boop that was never about web apps:
|
|
13
|
+
the folder conventions, the agent instructions, the issue tracker,
|
|
14
|
+
and the planning and writing skills.
|
|
15
|
+
|
|
16
|
+
Some projects produce decisions, documents and tracked work rather than code.
|
|
17
|
+
Setting up an AWS environment is one; a research project or a migration plan is another.
|
|
18
|
+
They still need somewhere to write down what is intended,
|
|
19
|
+
somewhere to record what now exists,
|
|
20
|
+
and a list of what comes next.
|
|
21
|
+
This profile gives them that and nothing else.
|
|
22
|
+
|
|
23
|
+
It is not a web app with the app removed.
|
|
24
|
+
A project made from it should read as a place to think and to track work,
|
|
25
|
+
with `specs/` for what we intend, `reference/` for what exists, and issues for what comes next.
|
|
26
|
+
Nothing in it assumes there is code to build, test or deploy,
|
|
27
|
+
and if a file only makes sense for an application, it does not belong here.
|
|
28
|
+
|
|
29
|
+
## What You Get
|
|
30
|
+
|
|
31
|
+
Three capabilities, all of them `type: development`,
|
|
32
|
+
whose skills apply to work that isn't code without any edits:
|
|
33
|
+
|
|
34
|
+
- **project-mgmt** — beads issue tracking and planning skills
|
|
35
|
+
- **product-design** — requirements, design, documentation and writing skills
|
|
36
|
+
- **skills** — skill authoring, discovery and maintenance
|
|
37
|
+
|
|
38
|
+
The profile also ships its own `templates/` folder,
|
|
39
|
+
which `boop init` renders in place of the web-app kernel templates:
|
|
40
|
+
an `AGENTS.md` that describes a project whose output is documents and tracked work,
|
|
41
|
+
a `README.md`, a `CLAUDE.md` pointer, a `.github/copilot-instructions.md` pointer, a `.gitignore`,
|
|
42
|
+
a README in each of `specs/`, `reference/` and `docs/` saying what belongs there,
|
|
43
|
+
and a minimal `package.json`.
|
|
44
|
+
Because `project-mgmt` is installed, `boop init` then commits the scaffold
|
|
45
|
+
and sets up the project's beads issue tracker in Dolt server mode,
|
|
46
|
+
so work can be filed as issues from the first minute.
|
|
47
|
+
|
|
48
|
+
The `package.json` has no scripts or dependencies of its own.
|
|
49
|
+
It exists because it is how boop delivers capability skills and refreshes them:
|
|
50
|
+
without one, the capability packages would never be recorded
|
|
51
|
+
and `boop update` would have nothing to update.
|
|
52
|
+
|
|
53
|
+
## Three Deliberate Omissions
|
|
54
|
+
|
|
55
|
+
The development capabilities that every other profile carries —
|
|
56
|
+
`coding`, `testing` and `workflows` —
|
|
57
|
+
are left out on purpose.
|
|
58
|
+
An agent takes the skills and files in a project as a hint about what kind of work happens there,
|
|
59
|
+
so every code-shaped thing in the scaffold is an invitation to do code-shaped work.
|
|
60
|
+
|
|
61
|
+
### No testing
|
|
62
|
+
|
|
63
|
+
`testing` installs Jest, `ts-jest`, a `tsconfig.test.json` and a `tests/` folder.
|
|
64
|
+
A project with nothing to test would carry a test runner nobody runs,
|
|
65
|
+
and an agent that finds one will reasonably suggest writing tests for it.
|
|
66
|
+
|
|
67
|
+
### No workflows
|
|
68
|
+
|
|
69
|
+
Seven of the ten `workflows` skills are for code:
|
|
70
|
+
feature development, refactoring, test audits, website work and so on.
|
|
71
|
+
An agent asked to "set up the network" could reasonably pick one of them up
|
|
72
|
+
and start a feature branch for something that has no code in it.
|
|
73
|
+
The three that suit any project — issue sweeps, knowledge backfill and stray disposition —
|
|
74
|
+
can join this profile once `workflows` is split (tracked in `boop-4n87`).
|
|
75
|
+
|
|
76
|
+
### No coding
|
|
77
|
+
|
|
78
|
+
`coding` is mostly about application code:
|
|
79
|
+
development conventions, code style, debugging.
|
|
80
|
+
When a project grows code of its own, such as Terraform for an infrastructure project,
|
|
81
|
+
`boop add coding` brings those skills in.
|
|
82
|
+
Leaving the capability out costs nothing until then.
|
|
83
|
+
|
|
84
|
+
## No Kernel, and Templates Instead
|
|
85
|
+
|
|
86
|
+
### No kernel
|
|
87
|
+
|
|
88
|
+
`web-app` carries a `kernel` block:
|
|
89
|
+
a node runtime, a deploy target, a port, an Express dependency set and the scripts that start a server.
|
|
90
|
+
This profile scaffolds no application, so it has none of those to name.
|
|
91
|
+
|
|
92
|
+
Unlike `development`, which has no kernel either and is refused by `boop init`,
|
|
93
|
+
this profile ships `templates/`,
|
|
94
|
+
and a profile with templates is one `boop init` can scaffold.
|
|
95
|
+
The steps that only mean something for an application —
|
|
96
|
+
the Node version check, merging kernel dependencies
|
|
97
|
+
and the `npm run dev` next step —
|
|
98
|
+
are skipped.
|
|
99
|
+
|
|
100
|
+
### No reference/
|
|
101
|
+
|
|
102
|
+
The folder READMEs live under `templates/`, not in a `profiles/base/reference/` folder.
|
|
103
|
+
Boop mirrors every profile's `reference/` pages into its own `reference/` folder as symlinks,
|
|
104
|
+
so a README placed there would land in boop's own tree
|
|
105
|
+
rather than in the projects made from this profile.
|