@cobusgreyling/loop-init 1.1.0 → 1.2.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 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,6 +1,6 @@
1
1
  {
2
2
  "name": "@cobusgreyling/loop-init",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Scaffold loop engineering starters into your project by pattern and tool.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,6 +35,10 @@
35
35
  "url": "git+https://github.com/cobusgreyling/loop-engineering.git",
36
36
  "directory": "tools/loop-init"
37
37
  },
38
+ "homepage": "https://cobusgreyling.github.io/loop-engineering/",
39
+ "bugs": {
40
+ "url": "https://github.com/cobusgreyling/loop-engineering/issues"
41
+ },
38
42
  "publishConfig": {
39
43
  "access": "public"
40
44
  },
@@ -13,8 +13,11 @@
13
13
 
14
14
  ## Budget
15
15
 
16
- - Max sub-agent spawns per run: 0 (L1)
17
- - Review STATE.md daily
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**.