@cobusgreyling/loop-init 1.1.0 → 1.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 +12 -1
- package/dist/cli.js +76 -0
- package/package.json +13 -3
- package/starters/minimal-loop/LOOP.md +5 -2
- package/templates/SKILL.md.loop-budget +40 -0
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Scaffold loop engineering starters into your project by pattern and tool.
|
|
4
4
|
|
|
5
|
+
**npx @cobusgreyling/loop-init . --pattern daily-triage --tool grok** works immediately.
|
|
6
|
+
|
|
5
7
|
## Install & Run
|
|
6
8
|
|
|
7
9
|
```bash
|
|
@@ -12,6 +14,8 @@ npx @cobusgreyling/loop-init . -p dependency-sweeper --dry-run
|
|
|
12
14
|
|
|
13
15
|
See [docs/RELEASE.md](../../docs/RELEASE.md) for npm publish tags. The published package bundles `starters/` and `templates/` from this monorepo.
|
|
14
16
|
|
|
17
|
+
After scaffolding, always run `npx @cobusgreyling/loop-audit . --suggest` and actually execute the first report-only loop to generate activity signals.
|
|
18
|
+
|
|
15
19
|
## Patterns
|
|
16
20
|
|
|
17
21
|
| Pattern | Default state file |
|
|
@@ -25,6 +29,12 @@ See [docs/RELEASE.md](../../docs/RELEASE.md) for npm publish tags. The published
|
|
|
25
29
|
|
|
26
30
|
L2 patterns (`ci-sweeper`, `dependency-sweeper`) also copy `minimal-fix` and `loop-verifier` templates when missing from the starter.
|
|
27
31
|
|
|
32
|
+
Every scaffold also creates:
|
|
33
|
+
|
|
34
|
+
- `loop-budget.md` — pattern-specific daily caps and kill switch
|
|
35
|
+
- `loop-run-log.md` — append-only run history
|
|
36
|
+
- `loop-budget` skill — runtime budget guard at start/end of each run
|
|
37
|
+
|
|
28
38
|
## Tools
|
|
29
39
|
|
|
30
40
|
- `grok` (default)
|
|
@@ -40,8 +50,9 @@ cd tools/loop-init && npm ci && npm test
|
|
|
40
50
|
node dist/cli.js /path/to/project --pattern daily-triage --tool grok
|
|
41
51
|
```
|
|
42
52
|
|
|
43
|
-
Pair with `loop-audit` after scaffolding:
|
|
53
|
+
Pair with `loop-audit` and `loop-cost` after scaffolding:
|
|
44
54
|
|
|
45
55
|
```bash
|
|
56
|
+
npx @cobusgreyling/loop-cost --pattern daily-triage --level L1
|
|
46
57
|
npx @cobusgreyling/loop-audit . --suggest
|
|
47
58
|
```
|
package/dist/cli.js
CHANGED
|
@@ -13,6 +13,7 @@ const PATTERN_STARTERS = {
|
|
|
13
13
|
'dependency-sweeper': 'dependency-sweeper',
|
|
14
14
|
'post-merge-cleanup': 'post-merge-cleanup',
|
|
15
15
|
'changelog-drafter': 'changelog-drafter',
|
|
16
|
+
'issue-triage': 'minimal-loop', // reuses daily-triage starter + new skill can be added manually or via templates later
|
|
16
17
|
};
|
|
17
18
|
const TOOL_SUFFIX = {
|
|
18
19
|
grok: '',
|
|
@@ -33,6 +34,17 @@ const STATE_FILES = {
|
|
|
33
34
|
'dependency-sweeper': 'dependency-sweeper-state.md',
|
|
34
35
|
'post-merge-cleanup': 'post-merge-state.md',
|
|
35
36
|
'changelog-drafter': 'changelog-drafter-state.md',
|
|
37
|
+
'issue-triage': 'issue-triage-state.md',
|
|
38
|
+
};
|
|
39
|
+
/** Mirrors patterns/registry.yaml cost caps — used when scaffolding observability files. */
|
|
40
|
+
const PATTERN_BUDGET = {
|
|
41
|
+
'daily-triage': { name: 'Daily Triage', maxRunsPerDay: 2, dailyCap: 100_000, maxSpawnsL1: 0, maxSpawnsL2: 2 },
|
|
42
|
+
'pr-babysitter': { name: 'PR Babysitter', maxRunsPerDay: 288, dailyCap: 2_000_000, maxSpawnsL1: 0, maxSpawnsL2: 3 },
|
|
43
|
+
'ci-sweeper': { name: 'CI Sweeper', maxRunsPerDay: 96, dailyCap: 1_000_000, maxSpawnsL1: 0, maxSpawnsL2: 3 },
|
|
44
|
+
'dependency-sweeper': { name: 'Dependency Sweeper', maxRunsPerDay: 4, dailyCap: 500_000, maxSpawnsL1: 0, maxSpawnsL2: 3 },
|
|
45
|
+
'post-merge-cleanup': { name: 'Post-Merge Cleanup', maxRunsPerDay: 1, dailyCap: 200_000, maxSpawnsL1: 0, maxSpawnsL2: 2 },
|
|
46
|
+
'changelog-drafter': { name: 'Changelog Drafter', maxRunsPerDay: 1, dailyCap: 100_000, maxSpawnsL1: 0, maxSpawnsL2: 2 },
|
|
47
|
+
'issue-triage': { name: 'Issue Triage', maxRunsPerDay: 12, dailyCap: 80_000, maxSpawnsL1: 0, maxSpawnsL2: 1 },
|
|
36
48
|
};
|
|
37
49
|
function parseArgs(argv) {
|
|
38
50
|
let pattern = 'daily-triage';
|
|
@@ -126,6 +138,62 @@ async function copyL2Templates(pattern, tool, targetDir, templatesRoot, dryRun)
|
|
|
126
138
|
await copyTemplateVerifier(templatesRoot, targetDir, tool, dryRun);
|
|
127
139
|
}
|
|
128
140
|
}
|
|
141
|
+
function formatTokenCap(n) {
|
|
142
|
+
if (n >= 1_000_000)
|
|
143
|
+
return `${n / 1_000_000}M`;
|
|
144
|
+
if (n >= 1_000)
|
|
145
|
+
return `${n / 1_000}k`;
|
|
146
|
+
return String(n);
|
|
147
|
+
}
|
|
148
|
+
function buildLoopBudgetMd(pattern) {
|
|
149
|
+
const b = PATTERN_BUDGET[pattern];
|
|
150
|
+
return `# Loop Budget — YOUR_PROJECT
|
|
151
|
+
|
|
152
|
+
> Primary loop: **${b.name}** (scaffolded by loop-init)
|
|
153
|
+
|
|
154
|
+
## Daily limits
|
|
155
|
+
|
|
156
|
+
| Loop | Max runs/day | Max tokens/day | Max sub-agent spawns/run |
|
|
157
|
+
|------|--------------|----------------|--------------------------|
|
|
158
|
+
| ${b.name} | ${b.maxRunsPerDay} | ${formatTokenCap(b.dailyCap)} | ${b.maxSpawnsL1} (L1) / ${b.maxSpawnsL2} (L2) |
|
|
159
|
+
|
|
160
|
+
## On budget exceed
|
|
161
|
+
|
|
162
|
+
1. Pause schedulers (\`scheduler_delete\` or disable automations)
|
|
163
|
+
2. Append event to \`loop-run-log.md\`
|
|
164
|
+
3. Notify human (Slack / issue / STATE.md High Priority)
|
|
165
|
+
|
|
166
|
+
## Kill switch
|
|
167
|
+
|
|
168
|
+
- Command or issue label: \`loop-pause-all\`
|
|
169
|
+
- Resume only after human clears the flag in STATE.md
|
|
170
|
+
|
|
171
|
+
## Estimate spend
|
|
172
|
+
|
|
173
|
+
\`\`\`bash
|
|
174
|
+
npx @cobusgreyling/loop-cost --pattern ${pattern}
|
|
175
|
+
\`\`\`
|
|
176
|
+
`;
|
|
177
|
+
}
|
|
178
|
+
async function scaffoldObservability(pattern, tool, targetDir, templatesRoot, dryRun) {
|
|
179
|
+
const budgetPath = path.join(targetDir, 'loop-budget.md');
|
|
180
|
+
const runLogTemplate = path.join(templatesRoot, 'loop-run-log.md.template');
|
|
181
|
+
const runLogPath = path.join(targetDir, 'loop-run-log.md');
|
|
182
|
+
if (!(await exists(budgetPath))) {
|
|
183
|
+
const content = buildLoopBudgetMd(pattern);
|
|
184
|
+
if (dryRun) {
|
|
185
|
+
console.log(` would write: ${budgetPath}`);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
await writeFile(budgetPath, content);
|
|
189
|
+
console.log(` created: loop-budget.md`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!(await exists(runLogPath))) {
|
|
193
|
+
await copyFile(runLogTemplate, runLogPath, dryRun);
|
|
194
|
+
}
|
|
195
|
+
await copyTemplateSkill(templatesRoot, 'SKILL.md.loop-budget', targetDir, tool, 'loop-budget', dryRun);
|
|
196
|
+
}
|
|
129
197
|
async function copyFile(src, dest, dryRun) {
|
|
130
198
|
if (!(await exists(src)))
|
|
131
199
|
return false;
|
|
@@ -170,6 +238,11 @@ function firstLoopCommand(pattern, tool) {
|
|
|
170
238
|
claude: '/loop 1d $changelog-scan + draft-release-notes — write RELEASE_NOTES_DRAFT.md and update state. Human approves before publish.',
|
|
171
239
|
codex: 'Automation daily: changelog-scan + draft-release-notes → RELEASE_NOTES_DRAFT.md. Human review.',
|
|
172
240
|
},
|
|
241
|
+
'issue-triage': {
|
|
242
|
+
grok: '/loop 2h Run issue-triage. Update issue-triage-state.md. Propose labels and priority only. No auto-apply. Human reviews the needs-human slice.',
|
|
243
|
+
claude: '/loop 2h $issue-triage — update issue-triage-state.md. Suggest labels on allowlisted areas only. Report mode week one.',
|
|
244
|
+
codex: 'Automation 2h: issue-triage → issue-triage-state.md. Propose only.',
|
|
245
|
+
},
|
|
173
246
|
};
|
|
174
247
|
return cmds[pattern][tool];
|
|
175
248
|
}
|
|
@@ -188,6 +261,7 @@ Patterns:
|
|
|
188
261
|
dependency-sweeper
|
|
189
262
|
post-merge-cleanup
|
|
190
263
|
changelog-drafter (new low-risk release notes pattern)
|
|
264
|
+
issue-triage (new low-risk issue queue health companion to daily triage)
|
|
191
265
|
|
|
192
266
|
Options:
|
|
193
267
|
-p, --pattern Pattern to scaffold
|
|
@@ -267,6 +341,7 @@ Examples:
|
|
|
267
341
|
await copyFile(loopMd, path.join(targetDir, 'LOOP.md'), dryRun);
|
|
268
342
|
}
|
|
269
343
|
await copyL2Templates(pattern, tool, targetDir, templatesRoot, dryRun);
|
|
344
|
+
await scaffoldObservability(pattern, tool, targetDir, templatesRoot, dryRun);
|
|
270
345
|
if (!dryRun && !(await exists(path.join(targetDir, 'AGENTS.md')))) {
|
|
271
346
|
const agentsTemplate = `# AGENTS.md
|
|
272
347
|
|
|
@@ -283,6 +358,7 @@ npm run lint
|
|
|
283
358
|
}
|
|
284
359
|
console.log('\n=== Next steps ===');
|
|
285
360
|
console.log(` npx @cobusgreyling/loop-audit ${target === '.' ? '.' : target} --suggest`);
|
|
361
|
+
console.log(` npx @cobusgreyling/loop-cost --pattern ${pattern}`);
|
|
286
362
|
console.log(` First loop command (${tool}):\n ${firstLoopCommand(pattern, tool)}\n`);
|
|
287
363
|
}
|
|
288
364
|
async function readDirNames(dir) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cobusgreyling/loop-init",
|
|
3
|
-
"version": "1.1
|
|
4
|
-
"description": "Scaffold loop engineering starters into
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"description": "Scaffold loop engineering patterns and starters into any project. Supports Grok, Claude Code, Codex and more. npx @cobusgreyling/loop-init . --pattern daily-triage --tool grok",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"loop-init": "./dist/cli.js"
|
|
@@ -25,8 +25,14 @@
|
|
|
25
25
|
"keywords": [
|
|
26
26
|
"loop-engineering",
|
|
27
27
|
"ai-agents",
|
|
28
|
+
"coding-agents",
|
|
28
29
|
"scaffold",
|
|
29
|
-
"starter"
|
|
30
|
+
"starter",
|
|
31
|
+
"claude-code",
|
|
32
|
+
"grok",
|
|
33
|
+
"codex",
|
|
34
|
+
"github-actions",
|
|
35
|
+
"patterns"
|
|
30
36
|
],
|
|
31
37
|
"author": "Cobus Greyling",
|
|
32
38
|
"license": "MIT",
|
|
@@ -35,6 +41,10 @@
|
|
|
35
41
|
"url": "git+https://github.com/cobusgreyling/loop-engineering.git",
|
|
36
42
|
"directory": "tools/loop-init"
|
|
37
43
|
},
|
|
44
|
+
"homepage": "https://cobusgreyling.github.io/loop-engineering/",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/cobusgreyling/loop-engineering/issues"
|
|
47
|
+
},
|
|
38
48
|
"publishConfig": {
|
|
39
49
|
"access": "public"
|
|
40
50
|
},
|
|
@@ -13,8 +13,11 @@
|
|
|
13
13
|
|
|
14
14
|
## Budget
|
|
15
15
|
|
|
16
|
-
- Max sub-agent spawns per run: 0 (L1)
|
|
17
|
-
-
|
|
16
|
+
- Max sub-agent spawns per run: 0 (L1) / 2 (L2)
|
|
17
|
+
- Max tokens/day: 100k (see `loop-budget.md`)
|
|
18
|
+
- Append each run to `loop-run-log.md`; use `loop-budget` skill at start/end
|
|
19
|
+
- Kill switch: `loop-pause-all` — pause schedulers and notify human
|
|
20
|
+
- Estimate: `npx @cobusgreyling/loop-cost --pattern daily-triage`
|
|
18
21
|
|
|
19
22
|
## Links
|
|
20
23
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: loop-budget
|
|
3
|
+
description: Check token budget and run-log spend before and after a loop run. Enforces early exit when over budget or when there is no actionable work.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Loop Budget Guard
|
|
7
|
+
|
|
8
|
+
Run at the **start** and **end** of every loop iteration.
|
|
9
|
+
|
|
10
|
+
## Start of run
|
|
11
|
+
|
|
12
|
+
1. Read `loop-budget.md` for daily caps and kill-switch flags.
|
|
13
|
+
2. Read recent entries in `loop-run-log.md` (last 24h).
|
|
14
|
+
3. Sum `tokens_estimate` for the active pattern today.
|
|
15
|
+
4. If spend ≥ 80% of the pattern's daily cap → **report-only mode** (no sub-agents, no auto-fix).
|
|
16
|
+
5. If spend ≥ 100% or `loop-pause-all` is set → **exit immediately** with a one-line note in STATE.md.
|
|
17
|
+
6. If watchlist/state has no actionable items → **exit in <5k tokens** (do not spawn sub-agents).
|
|
18
|
+
|
|
19
|
+
## End of run
|
|
20
|
+
|
|
21
|
+
Append one JSON object to `loop-run-log.md`:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"run_id": "<ISO8601>",
|
|
26
|
+
"pattern": "<pattern-id>",
|
|
27
|
+
"duration_s": <number>,
|
|
28
|
+
"items_found": <number>,
|
|
29
|
+
"actions_taken": <number>,
|
|
30
|
+
"escalations": <number>,
|
|
31
|
+
"tokens_estimate": <number>,
|
|
32
|
+
"outcome": "no-op | report-only | fix-proposed | escalated"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Rules
|
|
37
|
+
|
|
38
|
+
- Never exceed `max sub-agent spawns/run` from `loop-budget.md`.
|
|
39
|
+
- High-cadence patterns (CI Sweeper, PR Babysitter) **must** early-exit when nothing is actionable.
|
|
40
|
+
- On self-throttle, append a line to `loop-budget.md` under **Alerts This Period**.
|