compounding-loop 0.5.0 → 0.6.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 +152 -140
- package/dist/cli/eval.js +186 -0
- package/dist/cli/eval.js.map +1 -0
- package/dist/cli/hook.js +92 -0
- package/dist/cli/hook.js.map +1 -0
- package/dist/cli/index.js +218 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.js +41 -4
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/recipe.js +89 -0
- package/dist/cli/recipe.js.map +1 -0
- package/dist/cli/recipeDraft.js +64 -0
- package/dist/cli/recipeDraft.js.map +1 -0
- package/dist/cli/runs.js +3 -0
- package/dist/cli/runs.js.map +1 -1
- package/dist/core/eval.js +123 -0
- package/dist/core/eval.js.map +1 -0
- package/dist/core/hooksInit.js +54 -0
- package/dist/core/hooksInit.js.map +1 -0
- package/dist/core/laneRound.js +28 -7
- package/dist/core/laneRound.js.map +1 -1
- package/dist/core/parse/index.js +3 -0
- package/dist/core/parse/index.js.map +1 -1
- package/dist/core/parse/runs.js +1 -0
- package/dist/core/parse/runs.js.map +1 -1
- package/dist/core/recipeDraft.js +37 -0
- package/dist/core/recipeDraft.js.map +1 -0
- package/dist/core/recipes.js +185 -0
- package/dist/core/recipes.js.map +1 -0
- package/dist/core/triggers.js +137 -0
- package/dist/core/triggers.js.map +1 -0
- package/dist/server/data.js +7 -2
- package/dist/server/data.js.map +1 -1
- package/dist/server/index.js +7 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/loops.js +7 -0
- package/dist/server/loops.js.map +1 -1
- package/dist/server/memory.js +115 -0
- package/dist/server/memory.js.map +1 -0
- package/dist/server/memory.json +398 -0
- package/dist/server/static-export.js +6 -0
- package/dist/server/static-export.js.map +1 -1
- package/dist/web/assets/index-C5q9d5-n.css +2 -0
- package/dist/web/assets/index-DDEAcJFt.js +123 -0
- package/dist/web/index.html +2 -2
- package/method/COMPOUNDING_LOOP.md +28 -6
- package/method/operating-card.md +1 -1
- package/method/retro.md +4 -3
- package/package.json +4 -4
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/commands/loop-init.md +1 -0
- package/plugin/commands/retro.md +3 -2
- package/plugin/hooks/hooks.json +62 -0
- package/templates/recipe.md +39 -0
- package/templates/recipes/cli-command-json.md +47 -0
- package/templates/recipes/static-calculator-site.md +50 -0
- package/templates/static-site/CLAUDE.md +1 -1
- package/dist/web/assets/index-BozIcdeb.js +0 -88
- package/dist/web/assets/index-Te_olhNA.css +0 -2
package/dist/web/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="./favicon.svg" />
|
|
7
7
|
<title>Compounding Loop</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-DDEAcJFt.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-C5q9d5-n.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
> Copy this section into your always-loaded rules file. Keep it under ~60 lines.
|
|
37
37
|
> The § numbers point to Part B of `COMPOUNDING_LOOP.md`.
|
|
38
38
|
|
|
39
|
-
**Objective:** the most verified-correct results per minute of the
|
|
39
|
+
**Objective:** the most verified-correct results per minute of the owner's attention, from the smallest context that still passes. A wrong result that looks right is the most expensive one. Tokens are spent where they buy correctness (checks, review), not on re-learning what a recipe, a trigger or a check already knows.
|
|
40
40
|
|
|
41
41
|
**Start of every session**
|
|
42
42
|
1. Read `.ai/index.md`. Open a knowledge entry only when it's relevant to what you're doing.
|
|
@@ -79,11 +79,11 @@ Ranked by real cost, most expensive first:
|
|
|
79
79
|
1. **Wrong results that look right.** You find out late, and everything built on top has to be redone.
|
|
80
80
|
2. **Human attention.** Explaining, re-explaining, watching, reviewing.
|
|
81
81
|
3. **Waiting time.**
|
|
82
|
-
4. **Tokens
|
|
82
|
+
4. **Tokens.** Once cheap, now a real limit: a smaller context lets a smaller or local model do the job, and a subscription's five-hour limit is shared by every run. One loop spent about two thirds of its scheduled fires on idle runs; that is the same waste as re-reading what is already known.
|
|
83
83
|
|
|
84
|
-
So the goal is **the most verified-correct results per minute of human attention.**
|
|
84
|
+
So the goal is **the most verified-correct results per minute of human attention, from the smallest context that still passes.** Not "zero context": one recipe plus the checks that prove it.
|
|
85
85
|
|
|
86
|
-
Trim context when it hurts quality (noise, stale notes, contradictions)
|
|
86
|
+
Tokens are spent where they buy correctness (checks, review), not on re-learning what a recipe, a trigger or a check already knows. Trim context when it hurts quality (noise, stale notes, contradictions) and when a recipe or trigger can carry the lesson instead. Do not compress a note into keywords: that saves a few hundred tokens and throws away the *why*, which is the part that prevents repeated mistakes. Only a measured result counts as a claim that something got cheaper (§13).
|
|
87
87
|
|
|
88
88
|
### 2. Two ideas everything follows from
|
|
89
89
|
|
|
@@ -95,6 +95,7 @@ Trim context when it hurts quality (noise, stale notes, contradictions), not to
|
|
|
95
95
|
|---|---|---|
|
|
96
96
|
| Memory | Load every rule every session | A short index, plus triggers that fire at the moment of relevance (§7, §8) |
|
|
97
97
|
| Context | One long window that slowly degrades | Fresh windows with handoffs; subagents for reading (§9, §10) |
|
|
98
|
+
| Experience | Start every project from zero, or paste a whole old repo | One recipe for this kind of project: steps, traps and the check that proves each step (§7) |
|
|
98
99
|
| Compute | The strongest model for everything | The cheapest tier that passes the checks (§10) |
|
|
99
100
|
| Rules | Prose rules re-read forever | Automated checks that cost nothing until broken (§12) |
|
|
100
101
|
| Human attention | Watching the agent work | Four touchpoints (§14) |
|
|
@@ -160,13 +161,14 @@ This is the biggest multiplier in the whole method. An agent that can check its
|
|
|
160
161
|
|
|
161
162
|
### 7. Memory
|
|
162
163
|
|
|
163
|
-
|
|
164
|
+
Six layers, each loaded differently:
|
|
164
165
|
|
|
165
166
|
| Layer | Holds | Loaded |
|
|
166
167
|
|---|---|---|
|
|
167
168
|
| Core | Operating Card + project core | Always. Small and unchanging, so it stays cached |
|
|
168
169
|
| Index | One line per knowledge entry | Always |
|
|
169
170
|
| Knowledge | Gotchas, facts, decisions, lessons, open questions | Only when relevant or triggered |
|
|
171
|
+
| Recipes | Procedures that worked: steps, traps, checks (below) | One, when the task matches (`loop recipe match`); the SessionStart hook names the best one |
|
|
170
172
|
| Task state | `.ai/task.md` | Every window of the current task; deleted afterwards |
|
|
171
173
|
| Source of truth | Code, git history, test output, docs | Read when needed; never copied |
|
|
172
174
|
|
|
@@ -178,6 +180,12 @@ Five layers, each loaded differently:
|
|
|
178
180
|
K-0017 gotcha ✔ MV3 service worker loses in-memory state after ~30s idle · files: src/background/**
|
|
179
181
|
```
|
|
180
182
|
|
|
183
|
+
**Recipes are the layer for procedures.** A knowledge entry says "this breaks"; a recipe says "to build this kind of thing, do these steps, and this check proves each one". It is one Markdown file (`templates/recipe.md`) with front matter (`id`, `title`, `kind`, `stack` as `name@major`, `tags`, `status`, `source`, `uses`, `passes`, `updated`) and five sections in order: When to use, Steps (each names its proof), Traps (each pointing at a knowledge id or trigger), Checks, Start from. **Hard cap 6 KB**: a recipe is the small exact context, not a manual.
|
|
184
|
+
- *Stored* in `.ai/recipes/` (project) and `~/.ai/recipes/` (yours, across projects). Nothing personal: no absolute paths, emails or secrets.
|
|
185
|
+
- *Induced only from work whose checks passed*, as small appended or edited items with evidence, never a full rewrite. Rewriting the whole file loses what earlier runs learned (ACE, Zhang et al. 2025, "context collapse"). `loop recipe draft` follows this delta rule.
|
|
186
|
+
- *Used* by `loop recipe match` (stack overlap at the major version, plus tag and keyword overlap) and `loop recipe show <id> --context`, which prints exactly what a model receives.
|
|
187
|
+
- *Judged* by `uses` and `passes`; a recipe that fails more than it passes is fixed or deleted, like a trigger.
|
|
188
|
+
|
|
181
189
|
**Cross-project knowledge is keyed by library and major version, not by project type.** At task start, read the dependency manifest (`package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, …) and load the index lines from `~/.ai/libs/<library>@<major>.md` for each dependency. This has three advantages:
|
|
182
190
|
- No guessing about what "kind" of project this is.
|
|
183
191
|
- It combines on its own: a Next + Supabase + Tailwind project simply gets all three sets of notes.
|
|
@@ -196,7 +204,17 @@ Triggers watch events the tool already sees, run outside the model, and cost not
|
|
|
196
204
|
| **Command** | Before a matching command runs | `npm run build` → "run `npx prisma generate` first" (or just run it automatically) |
|
|
197
205
|
| **Topic** | The task text matches keywords | "persist auth" → a one-line hint pointing to K-0017 |
|
|
198
206
|
|
|
199
|
-
- **With hooks** (for example Claude Code):
|
|
207
|
+
- **With hooks** (for example Claude Code): `loop hook <event>` reads the hook JSON from stdin, matches it against `.ai/triggers.yaml` and prints `{"hookSpecificOutput":{"hookEventName":"<event>","additionalContext":"…"}}`, or nothing. Wire it through the plugin (`plugin/hooks/hooks.json`) or a project `.claude/settings.json` (`loop init --hooks`). Match built-in tools only (`Bash|Read|Edit|Write|Glob|Grep`); context from MCP and Agent calls may be dropped.
|
|
208
|
+
|
|
209
|
+
| Hook event | Kinds it checks |
|
|
210
|
+
|---|---|
|
|
211
|
+
| `SessionStart` | The best matching recipe, as one line |
|
|
212
|
+
| `UserPromptSubmit` | Topic |
|
|
213
|
+
| `PreToolUse` (Bash) | Command |
|
|
214
|
+
| `PostToolUse` | File. It fires only after a tool *succeeds* |
|
|
215
|
+
| `PostToolUseFailure` | Error and file. A failed Bash call fires this, not `PostToolUse` |
|
|
216
|
+
|
|
217
|
+
A hook never calls a model or the network, exits 0 on any error (a broken hook must not break a run), injects at most 2,000 characters, and injects each trigger once per session. Each fire is logged locally to `.ai/.trigger-log.jsonl`.
|
|
200
218
|
- **Without hooks:** manual trigger mode. Card rules 7 and 8 make the agent search the index after errors and before edits. It's less automatic but has the same effect, and works in any tool.
|
|
201
219
|
- **Precision beats coverage.** A trigger that fires often and doesn't help is noise. Track `fired` and `helped`, and fix or delete triggers that help less than about half the time.
|
|
202
220
|
|
|
@@ -312,6 +330,7 @@ The AI writes prompts for its next window, its subagents and its reviewers. It's
|
|
|
312
330
|
**Retro.** About 2 minutes, when the checks pass. The AI drafts it and the human approves.
|
|
313
331
|
1. List what was learned. For each item: does it apply beyond this task, or only to it? Is it confirmed or a guess? At what moment would it have helped (which file, command or error)?
|
|
314
332
|
2. Move general, confirmed items down the promotion ladder as far as they'll go.
|
|
333
|
+
**Recipe step:** is this a *procedure* someone will repeat (a kind of project or feature)? Then draft a recipe (`loop recipe draft`, §7), check it with `loop recipe check`, and keep it only if it is short and every step has a proof. A repeated *procedure* becomes a recipe; a repeated *mistake* still goes note → trigger → check.
|
|
315
334
|
3. Put library-level lessons in `~/.ai/libs/<library>@<major>.md`.
|
|
316
335
|
4. Delete `.ai/task.md`. Knowledge that only mattered for this task goes with it, on purpose.
|
|
317
336
|
5. Add a line to `.ai/log.md` (§13) and update `routing.md`.
|
|
@@ -320,6 +339,7 @@ The AI writes prompts for its next window, its subagents and its reviewers. It's
|
|
|
320
339
|
|
|
321
340
|
```
|
|
322
341
|
guess → confirmed note → note with a trigger → automated check
|
|
342
|
+
↘ repeated procedure → recipe
|
|
323
343
|
```
|
|
324
344
|
|
|
325
345
|
The last step is the goal: **the best memory is one the model never has to read.** "Never use `require()` here" becomes a lint rule. "Run prisma generate before build" becomes part of the build script. Then the prose note is deleted. A check costs nothing until it's broken, and it can't be ignored.
|
|
@@ -346,6 +366,8 @@ What to watch:
|
|
|
346
366
|
- **First-try pass rate per tier.** This feeds the routing table.
|
|
347
367
|
- **Trigger precision:** times helped ÷ times fired.
|
|
348
368
|
- **Windows until the checks pass**, and cost.
|
|
369
|
+
- **Tokens per verified unit:** tokens spent divided by units whose checks passed. A cheaper run that fails its checks is not cheaper.
|
|
370
|
+
- **The eval** (`loop eval`) is the one place a context claim is tested: it rebuilds known tasks cold, with a recipe, and with triggers, then reports pass rate, tokens and time per arm and model. Read the headline only when a results file exists; no results, no claim. The owner runs it; unattended lanes use the fake runner.
|
|
349
371
|
|
|
350
372
|
Prefer numbers from tools (check results, git, billing) over the AI's own account of how things went. Change one thing at a time and watch the numbers. Every threshold in this file (50–60%, 20 tasks, 90%, 5 windows) is a starting guess for your log to correct.
|
|
351
373
|
|
package/method/operating-card.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> The full method is in `.ai/method.md`. The § numbers point to Part B there.
|
|
4
4
|
|
|
5
|
-
**Objective:** the most verified-correct results per minute of the owner's attention
|
|
5
|
+
**Objective:** the most verified-correct results per minute of the owner's attention, from the smallest context that still passes. A wrong result that looks right is the most expensive one. Tokens are spent where they buy correctness (checks, review), not on re-learning what a recipe, a trigger or a check already knows.
|
|
6
6
|
|
|
7
7
|
**Start of every session**
|
|
8
8
|
1. Read `.ai/index.md`. Open a knowledge entry only when it's relevant to what you're doing.
|
package/method/retro.md
CHANGED
|
@@ -5,9 +5,10 @@ Run it when the checks pass, before deleting `.ai/task.md`. About two minutes.
|
|
|
5
5
|
1. List what was learned. For each item: does it apply beyond this task? Is it confirmed or a guess? At what moment would it have helped (file, command or error)?
|
|
6
6
|
2. Move general, confirmed items down the promotion ladder as far as they go: `guess → confirmed note → note with a trigger → automated check`. The best memory is one the model never has to read: turn a rule into a lint, test or script and delete the prose.
|
|
7
7
|
3. Write each kept lesson as a knowledge entry (`.ai/knowledge/K-NNNN.md`, see `method/example/K-0001.md`) with triggers, and add one line to `.ai/index.md`.
|
|
8
|
-
4.
|
|
9
|
-
5.
|
|
10
|
-
6.
|
|
8
|
+
4. Is this a procedure someone will repeat? Then draft a recipe (`loop recipe draft`; see method §7 and `templates/recipe.md`). A repeated *procedure* becomes a recipe; a repeated *mistake* still goes note → trigger → check. For an existing recipe, add or change items; never rewrite the file.
|
|
9
|
+
5. Flag entries this task showed to be wrong or stale. Never delete a CONFIRMED entry without new evidence.
|
|
10
|
+
6. Add one line to `.ai/log.md`: date, task, checks result, runs used, what was learned.
|
|
11
|
+
7. Delete `.ai/task.md`.
|
|
11
12
|
|
|
12
13
|
## In a lane
|
|
13
14
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compounding-loop",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Write the brief, check back tomorrow: unattended, verified Claude Code build loops with a local dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -66,13 +66,13 @@
|
|
|
66
66
|
"tsx": "^4.23.15",
|
|
67
67
|
"typescript": "^7.0.2",
|
|
68
68
|
"vite": "^8.3.3",
|
|
69
|
-
"vitest": "^5.0.3"
|
|
70
|
-
"yaml": "^2.9.1"
|
|
69
|
+
"vitest": "^5.0.3"
|
|
71
70
|
},
|
|
72
71
|
"dependencies": {
|
|
73
72
|
"@clack/prompts": "^1.8.1",
|
|
74
73
|
"@hono/node-server": "^2.1.4",
|
|
75
74
|
"commander": "^15.0.0",
|
|
76
|
-
"hono": "^4.13.13"
|
|
75
|
+
"hono": "^4.13.13",
|
|
76
|
+
"yaml": "^2.9.1"
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compounding-loop",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Run unattended, verified Claude Code build loops: set up a repo, hand off between windows, run retros and escape stuck loops.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": ["loop", "unattended", "verification", "handoff", "retro"]
|
|
@@ -8,6 +8,7 @@ Set this repository up for unattended, verified build loops.
|
|
|
8
8
|
2. Make sure these exist, creating only what is missing and never overwriting the user's files:
|
|
9
9
|
- `CLAUDE.md` containing the Operating Card (the "Operating Card (the Compounding Loop)" section).
|
|
10
10
|
- `.ai/method.md`, `.ai/index.md`, `.ai/knowledge/`, `.ai/log.md`.
|
|
11
|
+
- `.ai/triggers.yaml` (a starter) and, if the user agrees, the hooks in `.claude/settings.json` (`npx compounding-loop init --hooks`) so triggers fire at the moment they matter. The plugin already ships the same hooks; do not add both.
|
|
11
12
|
- `.ai/task.md` with `Run: 0 / 30`, a Contract with a "Done when" that a command can check, and empty Confirmed, Guesses, Tried and Decisions sections.
|
|
12
13
|
3. Ask the user for the one-sentence goal and the command that proves it works (for example `npm test`) if `IDEA.md` or the task contract does not already say.
|
|
13
14
|
4. Finish with the exact command the user should run next, and do not start the build yourself.
|
package/plugin/commands/retro.md
CHANGED
|
@@ -7,5 +7,6 @@ Run the retro (method section 12) now that the checks pass.
|
|
|
7
7
|
1. Run the checks once more and confirm they pass. If they do not, stop and say so; the task is not done.
|
|
8
8
|
2. Read `.ai/task.md`. List the lessons worth keeping beyond this task (Confirmed facts that will bite again, gotchas, decisions). For each, propose a knowledge entry with its triggers (files, error text, commands, topics) and evidence.
|
|
9
9
|
3. Flag existing entries in `.ai/index.md` that this task showed to be wrong or stale. Do not delete or rewrite a CONFIRMED entry without new evidence.
|
|
10
|
-
4.
|
|
11
|
-
5.
|
|
10
|
+
4. Is this a procedure someone will repeat (a kind of project or feature)? Then draft a recipe: run `loop recipe draft --print-prompt`, or `loop recipe draft` if the user agrees to a Claude call. The draft lands in `.ai/recipes/<id>.draft.md` and is scored by `loop recipe check`. For an existing recipe id the draft is a list of added or changed items, never a full rewrite. A repeated *procedure* becomes a recipe; a repeated *mistake* still goes note -> trigger -> check.
|
|
11
|
+
5. Add one line to `.ai/log.md`: date, task, checks result, number of windows, what was learned.
|
|
12
|
+
6. After the user approves the proposed entries and the recipe draft, write them, update `.ai/index.md`, and delete `.ai/task.md`.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "loop hook SessionStart",
|
|
9
|
+
"timeout": 5
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"UserPromptSubmit": [
|
|
15
|
+
{
|
|
16
|
+
"hooks": [
|
|
17
|
+
{
|
|
18
|
+
"type": "command",
|
|
19
|
+
"command": "loop hook UserPromptSubmit",
|
|
20
|
+
"timeout": 5
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"PreToolUse": [
|
|
26
|
+
{
|
|
27
|
+
"matcher": "Bash|Read|Edit|Write|Glob|Grep",
|
|
28
|
+
"hooks": [
|
|
29
|
+
{
|
|
30
|
+
"type": "command",
|
|
31
|
+
"command": "loop hook PreToolUse",
|
|
32
|
+
"timeout": 5
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"PostToolUse": [
|
|
38
|
+
{
|
|
39
|
+
"matcher": "Bash|Read|Edit|Write|Glob|Grep",
|
|
40
|
+
"hooks": [
|
|
41
|
+
{
|
|
42
|
+
"type": "command",
|
|
43
|
+
"command": "loop hook PostToolUse",
|
|
44
|
+
"timeout": 5
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"PostToolUseFailure": [
|
|
50
|
+
{
|
|
51
|
+
"matcher": "Bash|Read|Edit|Write|Glob|Grep",
|
|
52
|
+
"hooks": [
|
|
53
|
+
{
|
|
54
|
+
"type": "command",
|
|
55
|
+
"command": "loop hook PostToolUseFailure",
|
|
56
|
+
"timeout": 5
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: R-your-slug
|
|
3
|
+
title: Short name of the kind of project or feature
|
|
4
|
+
kind: feature
|
|
5
|
+
stack:
|
|
6
|
+
- node@20
|
|
7
|
+
tags:
|
|
8
|
+
- one-word-tag
|
|
9
|
+
status: GUESS
|
|
10
|
+
source: owner/repo at commit abc1234
|
|
11
|
+
uses: 0
|
|
12
|
+
passes: 0
|
|
13
|
+
updated: 2026-01-01
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<!-- Copy to .ai/recipes/R-<slug>.md. Keep it under 6 KB: a recipe is the small exact context, not a manual.
|
|
17
|
+
Check it with `loop recipe check`. Change an existing recipe by adding or editing items, never by regenerating the file.
|
|
18
|
+
Induce it only from work whose checks passed. No absolute paths, emails or secrets. -->
|
|
19
|
+
|
|
20
|
+
## When to use
|
|
21
|
+
|
|
22
|
+
One paragraph: the kind of task this fits, and when it does not.
|
|
23
|
+
|
|
24
|
+
## Steps
|
|
25
|
+
|
|
26
|
+
1. Do the first thing. Proof: `npm test`.
|
|
27
|
+
2. Do the next thing. Proof: `node --test`.
|
|
28
|
+
|
|
29
|
+
## Traps
|
|
30
|
+
|
|
31
|
+
- One line per trap, with what covers it (K-0001 or a trigger id).
|
|
32
|
+
|
|
33
|
+
## Checks
|
|
34
|
+
|
|
35
|
+
- `npm test`
|
|
36
|
+
|
|
37
|
+
## Start from
|
|
38
|
+
|
|
39
|
+
- The template or files to copy first.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: R-cli-command-json
|
|
3
|
+
title: Add a CLI subcommand with --json output and tests
|
|
4
|
+
kind: feature
|
|
5
|
+
stack:
|
|
6
|
+
- node@20
|
|
7
|
+
tags:
|
|
8
|
+
- cli
|
|
9
|
+
- json
|
|
10
|
+
- subcommand
|
|
11
|
+
- command
|
|
12
|
+
status: CONFIRMED
|
|
13
|
+
source: Minntooos/Compounding-Loop src/cli and tests/unit/cli, rounds 4 to 6
|
|
14
|
+
uses: 0
|
|
15
|
+
passes: 0
|
|
16
|
+
updated: 2026-10-14
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
A Node command-line tool needs one more subcommand that reports something, for people (a table) and for scripts (`--json`). Not for commands that only wrap another tool.
|
|
22
|
+
|
|
23
|
+
## Steps
|
|
24
|
+
|
|
25
|
+
1. Write the logic as a pure function that takes its inputs and returns a plain object (no printing, no `process.exit`). Proof: `npm test` runs its unit test.
|
|
26
|
+
2. Test it first: the normal result, an empty or missing input, and a bad argument that throws a message saying how to fix it. Use a temp folder, never the real repo. Proof: `npm test`.
|
|
27
|
+
3. Register the subcommand with a one-line description and a `--json` option. With `--json` print only `JSON.stringify(result, null, 2)` to stdout; without it print the human text. Proof: a test runs the command and parses stdout.
|
|
28
|
+
4. Make errors short and actionable: print them to stderr and set `process.exitCode = 1` instead of exiting mid-stream. Proof: a test asserts the exit code and the message.
|
|
29
|
+
5. Add the command to `--help` and the README usage list. Proof: `node bin/<tool>.js --help`.
|
|
30
|
+
6. Run the whole suite. Proof: `npm test`.
|
|
31
|
+
|
|
32
|
+
## Traps
|
|
33
|
+
|
|
34
|
+
- Any extra `console.log` breaks `--json` for scripts; log progress to stderr.
|
|
35
|
+
- Build paths with `node:path`, never a hard-coded `/` (Windows).
|
|
36
|
+
- Start child processes with `execFile` and an argument array, never a shell string.
|
|
37
|
+
- Tests that use real temp folders can hit `EBUSY` on Windows at cleanup; pass `maxRetries` to `rm` (K-0002).
|
|
38
|
+
- A JSON shape is a contract: add fields, never rename them.
|
|
39
|
+
|
|
40
|
+
## Checks
|
|
41
|
+
|
|
42
|
+
- `npm test`
|
|
43
|
+
- `node bin/<tool>.js <command> --json`
|
|
44
|
+
|
|
45
|
+
## Start from
|
|
46
|
+
|
|
47
|
+
- An existing subcommand in the same file (copy its option handling) and its test file.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: R-static-calculator-site
|
|
3
|
+
title: Add a calculator page to a static niche site
|
|
4
|
+
kind: feature
|
|
5
|
+
stack:
|
|
6
|
+
- node@20
|
|
7
|
+
tags:
|
|
8
|
+
- calculator
|
|
9
|
+
- static
|
|
10
|
+
- seo
|
|
11
|
+
- html
|
|
12
|
+
status: CONFIRMED
|
|
13
|
+
source: Minntooos/Compounding-Loop templates/static-site, five live sites built unattended in round 1
|
|
14
|
+
uses: 0
|
|
15
|
+
passes: 0
|
|
16
|
+
updated: 2026-10-14
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
A static site (plain HTML, CSS and ES modules, no build step) needs one more tool page: a calculator or converter that must be correct and rank for one search intent. Not for sites with a build step or a backend.
|
|
22
|
+
|
|
23
|
+
## Steps
|
|
24
|
+
|
|
25
|
+
1. Put the formula in a pure function in `site/js/lib/<topic>.js`, no DOM access. Proof: `npm run unit` imports it.
|
|
26
|
+
2. Write `tests/unit/<topic>.test.mjs` (`node:test`) with at least two reference cases from an authoritative source (URL in a comment above each) and the edges: zero, empty, impossible input, both unit directions. Proof: `npm run unit`.
|
|
27
|
+
3. Make the page `site/<slug>/index.html`, slug lowercase and keyword-first, with `<title>`, a meta description of at most 160 characters, one `<h1>`, a canonical on the site's own host, and JSON-LD. Proof: `npm run check`.
|
|
28
|
+
4. Add the page script as an external module (no inline script or handler); show a clear message for bad input, never `NaN`, `Infinity` or `undefined`. Write results with `textContent`. Proof: `npm run check`.
|
|
29
|
+
5. Write 300+ original visible words: how to use it, how it is calculated, a worked example, a short FAQ. Proof: `npm run check`.
|
|
30
|
+
6. Link the page from the home page and from related pages, and add its URL to `site/sitemap.xml`. Proof: `npm run check`.
|
|
31
|
+
7. Run everything and fix what the messages say. Proof: `npm test`.
|
|
32
|
+
|
|
33
|
+
## Traps
|
|
34
|
+
|
|
35
|
+
- A test that re-derives your own formula proves nothing; take the cases from a source (K-0003 in the starter kit).
|
|
36
|
+
- Never change a published URL; add a 301 redirect to both `netlify.toml` and `vercel.json` if you must.
|
|
37
|
+
- A sitemap entry is easy to forget; the check fails without it.
|
|
38
|
+
- Inline scripts, `innerHTML` with user input and CDN scripts break the CSP; use modules and `textContent`.
|
|
39
|
+
- Pages that differ by one swapped word are doorway pages; the check fails above 60% shared phrasing.
|
|
40
|
+
- Meta descriptions over 160 characters are cut in results.
|
|
41
|
+
|
|
42
|
+
## Checks
|
|
43
|
+
|
|
44
|
+
- `npm run check`
|
|
45
|
+
- `npm run unit`
|
|
46
|
+
- `npm test`
|
|
47
|
+
|
|
48
|
+
## Start from
|
|
49
|
+
|
|
50
|
+
- `templates/static-site` in the Compounding Loop package (`loop new` copies it): `site/`, `scripts/check.mjs`, `tests/`.
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
|
|
60
60
|
> The full method is in `.ai/method.md`. The § numbers point to Part B there.
|
|
61
61
|
|
|
62
|
-
**Objective:** the most verified-correct results per minute of the owner's attention
|
|
62
|
+
**Objective:** the most verified-correct results per minute of the owner's attention, from the smallest context that still passes. A wrong result that looks right is the most expensive one. Tokens are spent where they buy correctness (checks, review), not on re-learning what a recipe, a trigger or a check already knows.
|
|
63
63
|
|
|
64
64
|
**Start of every session**
|
|
65
65
|
1. Read `.ai/index.md`. Open a knowledge entry only when it's relevant to what you're doing.
|