@cobusgreyling/loop-init 1.2.3 → 1.3.2

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.
Files changed (46) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.js +133 -31
  3. package/package.json +6 -2
  4. package/starters/README.md +8 -1
  5. package/starters/changelog-drafter-opencode/AGENTS.md +15 -0
  6. package/starters/changelog-drafter-opencode/LOOP.md +26 -0
  7. package/starters/changelog-drafter-opencode/README.md +44 -0
  8. package/starters/changelog-drafter-opencode/changelog-drafter-state.md.example +10 -0
  9. package/starters/changelog-drafter-opencode/opencode.json.example +35 -0
  10. package/starters/changelog-drafter-opencode/skills/changelog-scan/SKILL.md +38 -0
  11. package/starters/ci-sweeper-opencode/AGENTS.md +17 -0
  12. package/starters/ci-sweeper-opencode/LOOP.md +26 -0
  13. package/starters/ci-sweeper-opencode/README.md +43 -0
  14. package/starters/ci-sweeper-opencode/ci-sweeper-state.md.example +10 -0
  15. package/starters/ci-sweeper-opencode/opencode.json.example +35 -0
  16. package/starters/ci-sweeper-opencode/skills/ci-triage/SKILL.md +32 -0
  17. package/starters/dependency-sweeper-opencode/AGENTS.md +15 -0
  18. package/starters/dependency-sweeper-opencode/LOOP.md +27 -0
  19. package/starters/dependency-sweeper-opencode/README.md +44 -0
  20. package/starters/dependency-sweeper-opencode/dependency-sweeper-state.md.example +11 -0
  21. package/starters/dependency-sweeper-opencode/opencode.json.example +35 -0
  22. package/starters/dependency-sweeper-opencode/skills/dependency-triage/SKILL.md +35 -0
  23. package/starters/issue-triage-opencode/AGENTS.md +16 -0
  24. package/starters/issue-triage-opencode/LOOP.md +21 -0
  25. package/starters/issue-triage-opencode/README.md +43 -0
  26. package/starters/issue-triage-opencode/issue-triage-state.md.example +11 -0
  27. package/starters/issue-triage-opencode/opencode.json.example +35 -0
  28. package/starters/issue-triage-opencode/skills/issue-triage/SKILL.md +33 -0
  29. package/starters/minimal-loop-opencode/AGENTS.md +23 -0
  30. package/starters/minimal-loop-opencode/LOOP.md +33 -0
  31. package/starters/minimal-loop-opencode/README.md +50 -0
  32. package/starters/minimal-loop-opencode/STATE.md.example +12 -0
  33. package/starters/minimal-loop-opencode/opencode.json.example +35 -0
  34. package/starters/minimal-loop-opencode/skills/loop-triage/SKILL.md +59 -0
  35. package/starters/post-merge-cleanup-opencode/AGENTS.md +15 -0
  36. package/starters/post-merge-cleanup-opencode/LOOP.md +26 -0
  37. package/starters/post-merge-cleanup-opencode/README.md +44 -0
  38. package/starters/post-merge-cleanup-opencode/opencode.json.example +35 -0
  39. package/starters/post-merge-cleanup-opencode/post-merge-state.md.example +10 -0
  40. package/starters/post-merge-cleanup-opencode/skills/post-merge-scan/SKILL.md +34 -0
  41. package/starters/pr-babysitter-opencode/AGENTS.md +18 -0
  42. package/starters/pr-babysitter-opencode/LOOP.md +27 -0
  43. package/starters/pr-babysitter-opencode/README.md +44 -0
  44. package/starters/pr-babysitter-opencode/opencode.json.example +35 -0
  45. package/starters/pr-babysitter-opencode/pr-babysitter-state.md.example +10 -0
  46. package/starters/pr-babysitter-opencode/skills/pr-review-triage/SKILL.md +33 -0
package/README.md CHANGED
@@ -8,6 +8,7 @@ Scaffold loop engineering starters into your project by pattern and tool.
8
8
 
9
9
  ```bash
10
10
  npx @cobusgreyling/loop-init . --pattern daily-triage --tool grok
11
+ npx @cobusgreyling/loop-init . --pattern daily-triage --tool opencode
11
12
  npx @cobusgreyling/loop-init . -p pr-babysitter -t claude
12
13
  npx @cobusgreyling/loop-init . -p dependency-sweeper --dry-run
13
14
  ```
@@ -41,6 +42,7 @@ Every scaffold also creates:
41
42
  - `grok` (default)
42
43
  - `claude`
43
44
  - `codex`
45
+ - `opencode` — daily-triage ships `minimal-loop-opencode` (`skills/`, `AGENTS.md`, `opencode.json`)
44
46
 
45
47
  Falls back to Grok starter paths when a per-tool variant is not yet available.
46
48
 
package/dist/cli.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { spawn } from 'node:child_process';
2
3
  import { cp, mkdir, readFile, writeFile, access } from 'node:fs/promises';
3
4
  import path from 'node:path';
4
5
  import { fileURLToPath } from 'node:url';
@@ -19,6 +20,7 @@ const TOOL_SUFFIX = {
19
20
  grok: '',
20
21
  claude: '-claude',
21
22
  codex: '-codex',
23
+ opencode: '-opencode',
22
24
  };
23
25
  const L2_PATTERNS = new Set(['ci-sweeper', 'dependency-sweeper']);
24
26
  const PATTERNS_NEEDING_FIX = new Set([
@@ -99,6 +101,7 @@ async function copyTemplateSkill(templatesRoot, templateFile, targetDir, tool, s
99
101
  grok: path.join(targetDir, '.grok', 'skills', skillName, 'SKILL.md'),
100
102
  claude: path.join(targetDir, '.claude', 'skills', skillName, 'SKILL.md'),
101
103
  codex: path.join(targetDir, '.codex', 'skills', skillName, 'SKILL.md'),
104
+ opencode: path.join(targetDir, 'skills', skillName, 'SKILL.md'),
102
105
  };
103
106
  const dest = destByTool[tool];
104
107
  if (await exists(dest))
@@ -110,6 +113,7 @@ async function copyTemplateVerifier(templatesRoot, targetDir, tool, dryRun) {
110
113
  grok: path.join(targetDir, '.grok', 'skills', 'loop-verifier', 'SKILL.md'),
111
114
  claude: path.join(targetDir, '.claude', 'agents', 'loop-verifier.md'),
112
115
  codex: path.join(targetDir, '.codex', 'agents', 'verifier.toml'),
116
+ opencode: path.join(targetDir, 'skills', 'loop-verifier', 'SKILL.md'),
113
117
  };
114
118
  const dest = verifierPaths[tool];
115
119
  if (await exists(dest))
@@ -214,53 +218,112 @@ async function copyFile(src, dest, dryRun) {
214
218
  console.log(` copied: ${src} → ${dest}`);
215
219
  return true;
216
220
  }
221
+ const OPENCODE_RUN = 'opencode run';
217
222
  function firstLoopCommand(pattern, tool) {
218
223
  const cmds = {
219
224
  'daily-triage': {
220
225
  grok: '/loop 1d Run loop-triage. Update STATE.md. No auto-fix in week one.',
221
226
  claude: '/loop 1d $loop-triage — update STATE.md. Report-only week one.',
222
227
  codex: 'Automation daily: $loop-triage → update STATE.md. Report-only.',
228
+ opencode: `${OPENCODE_RUN} "Run loop-triage. Read STATE.md first. Update High Priority and Watch List. No auto-fix in week one." --agent loop-triage`,
223
229
  },
224
230
  'pr-babysitter': {
225
231
  grok: '/loop 10m Run pr-review-triage. Update pr-babysitter-state.md. Worktree + minimal-fix + verifier for allowlisted PRs only. Escalate after 3 attempts.',
226
232
  claude: '/loop 10m $pr-review-triage — update pr-babysitter-state.md. No auto-merge.',
227
233
  codex: 'Automation 10m: pr-review-triage → pr-babysitter-state.md. No auto-merge.',
234
+ opencode: `${OPENCODE_RUN} "Run PR babysitter triage. Read pr-babysitter-state.md first. Report only — no code edits." --title "PR babysitter"`,
228
235
  },
229
236
  'ci-sweeper': {
230
237
  grok: '/loop 15m Run ci-triage on failing CI. Update ci-sweeper-state.md. Fix only regressions in worktree. Max 3 attempts.',
231
238
  claude: '/loop 15m $ci-triage — update ci-sweeper-state.md. Max 3 fix attempts.',
232
239
  codex: 'Automation 15m: ci-triage on CI failures. Max 3 attempts.',
240
+ opencode: `${OPENCODE_RUN} "Run ci-triage on failing CI. Update ci-sweeper-state.md. Report only in week one."`,
233
241
  },
234
242
  'dependency-sweeper': {
235
243
  grok: '/loop 6h Run dependency-triage. Patch-only auto-fix in worktree + verifier. Escalate majors and denylist.',
236
244
  claude: '/loop 6h $dependency-triage — patch-only with verifier. Escalate risky bumps.',
237
245
  codex: 'Automation 6h: dependency-triage. Patch-only with verifier.',
246
+ opencode: `${OPENCODE_RUN} "Run dependency-triage. Update dependency-sweeper-state.md. Report only — escalate majors."`,
238
247
  },
239
248
  'post-merge-cleanup': {
240
249
  grok: '/loop 1d Run post-merge-scan on recent merges. Update post-merge-state.md. Small fixes only in worktree.',
241
250
  claude: '/loop 1d $post-merge-scan — update post-merge-state.md. Small fixes only.',
242
251
  codex: 'Automation daily: post-merge-scan → post-merge-state.md.',
252
+ opencode: `${OPENCODE_RUN} "Run post-merge-scan. Update post-merge-state.md. Report only in week one."`,
243
253
  },
244
254
  'changelog-drafter': {
245
255
  grok: '/loop 1d Run changelog-scan on merges since last tag. Produce categorized draft in RELEASE_NOTES_DRAFT.md using draft-release-notes. Update changelog-drafter-state.md. Human review only.',
246
256
  claude: '/loop 1d $changelog-scan + draft-release-notes — write RELEASE_NOTES_DRAFT.md and update state. Human approves before publish.',
247
257
  codex: 'Automation daily: changelog-scan + draft-release-notes → RELEASE_NOTES_DRAFT.md. Human review.',
258
+ opencode: `${OPENCODE_RUN} "Run changelog-scan. Draft RELEASE_NOTES_DRAFT.md. Human review only — no publish."`,
248
259
  },
249
260
  'issue-triage': {
250
261
  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.',
251
262
  claude: '/loop 2h $issue-triage — update issue-triage-state.md. Suggest labels on allowlisted areas only. Report mode week one.',
252
263
  codex: 'Automation 2h: issue-triage → issue-triage-state.md. Propose only.',
264
+ opencode: `${OPENCODE_RUN} "Run issue-triage. Update issue-triage-state.md. Propose labels only — no auto-apply."`,
253
265
  },
254
266
  };
255
267
  return cmds[pattern][tool];
256
268
  }
269
+ async function resolveAuditCli() {
270
+ const monorepo = path.resolve(PACKAGE_ROOT, '../loop-audit/dist/cli.js');
271
+ if (await exists(monorepo))
272
+ return monorepo;
273
+ try {
274
+ const { createRequire } = await import('node:module');
275
+ const require = createRequire(import.meta.url);
276
+ const pkg = require.resolve('@cobusgreyling/loop-audit/package.json');
277
+ return path.join(path.dirname(pkg), 'dist/cli.js');
278
+ }
279
+ catch {
280
+ return null;
281
+ }
282
+ }
283
+ async function runAuditJson(cli, targetDir) {
284
+ return new Promise((resolve, reject) => {
285
+ const child = spawn('node', [cli, targetDir, '--json'], {
286
+ stdio: ['ignore', 'pipe', 'pipe'],
287
+ });
288
+ let stdout = '';
289
+ child.stdout.on('data', (chunk) => {
290
+ stdout += chunk.toString();
291
+ });
292
+ child.on('error', reject);
293
+ child.on('close', () => {
294
+ if (stdout.trim())
295
+ resolve(stdout);
296
+ else
297
+ reject(new Error('loop-audit produced no output'));
298
+ });
299
+ });
300
+ }
301
+ async function runAuditSummary(targetDir) {
302
+ const cli = await resolveAuditCli();
303
+ if (!cli)
304
+ return null;
305
+ try {
306
+ const stdout = await runAuditJson(cli, targetDir);
307
+ return JSON.parse(stdout);
308
+ }
309
+ catch {
310
+ return null;
311
+ }
312
+ }
313
+ function formatScoreBar(score, width = 20) {
314
+ const filled = Math.max(0, Math.min(width, Math.round((score / 100) * width)));
315
+ return `${'█'.repeat(filled)}${'░'.repeat(width - filled)} ${score}/100`;
316
+ }
317
+ function auditTargetArg(target, targetDir) {
318
+ return target === '.' ? '.' : targetDir;
319
+ }
257
320
  async function main() {
258
321
  const args = parseArgs(process.argv.slice(2));
259
322
  if (args.help) {
260
323
  console.log(`loop-init — scaffold loop engineering starters
261
324
 
262
325
  Usage:
263
- loop-init [target-dir] --pattern <name> --tool <grok|claude|codex>
326
+ loop-init [target-dir] --pattern <name> --tool <grok|claude|codex|opencode>
264
327
 
265
328
  Patterns:
266
329
  daily-triage (default)
@@ -280,6 +343,7 @@ Options:
280
343
  Examples:
281
344
  npx @cobusgreyling/loop-init . --pattern daily-triage --tool grok
282
345
  npx @cobusgreyling/loop-init . -p pr-babysitter -t claude
346
+ npx @cobusgreyling/loop-init . -p daily-triage -t opencode
283
347
  `);
284
348
  process.exit(0);
285
349
  }
@@ -297,7 +361,7 @@ Examples:
297
361
  const targetDir = path.resolve(target);
298
362
  const baseStarter = PATTERN_STARTERS[pattern];
299
363
  const suffix = TOOL_SUFFIX[tool];
300
- const starterName = pattern === 'daily-triage' ? `minimal-loop${suffix}` : baseStarter;
364
+ const starterName = `${baseStarter}${suffix}`;
301
365
  const startersRoot = await resolveBundledOrMonorepo('starters');
302
366
  const templatesRoot = await resolveBundledOrMonorepo('templates');
303
367
  const starterRoot = path.join(startersRoot, starterName);
@@ -313,33 +377,52 @@ Examples:
313
377
  ? starterRoot
314
378
  : path.join(startersRoot, baseStarter);
315
379
  console.log(`\nloop-init: ${pattern} → ${targetDir} (${tool})${dryRun ? ' [dry-run]' : ''}\n`);
316
- const skillRoots = [
317
- path.join(effectiveStarter, '.grok', 'skills'),
318
- path.join(effectiveStarter, '.claude', 'skills'),
319
- path.join(effectiveStarter, '.codex', 'skills'),
320
- ];
321
- for (const skillsDir of skillRoots) {
322
- if (!(await exists(skillsDir)))
323
- continue;
324
- const toolPrefix = skillsDir.includes('.grok')
325
- ? '.grok/skills'
326
- : skillsDir.includes('.claude')
327
- ? '.claude/skills'
328
- : '.codex/skills';
329
- const entries = await readDirNames(skillsDir);
330
- for (const entry of entries) {
331
- await copyDir(path.join(skillsDir, entry), path.join(targetDir, toolPrefix, entry), dryRun);
380
+ if (tool === 'opencode') {
381
+ const skillsDir = path.join(effectiveStarter, 'skills');
382
+ if (await exists(skillsDir)) {
383
+ const entries = await readDirNames(skillsDir);
384
+ for (const entry of entries) {
385
+ await copyDir(path.join(skillsDir, entry), path.join(targetDir, 'skills', entry), dryRun);
386
+ }
387
+ }
388
+ const agentsMd = path.join(effectiveStarter, 'AGENTS.md');
389
+ if (await exists(agentsMd)) {
390
+ await copyFile(agentsMd, path.join(targetDir, 'AGENTS.md'), dryRun);
391
+ }
392
+ const opencodeJson = path.join(effectiveStarter, 'opencode.json.example');
393
+ if (await exists(opencodeJson)) {
394
+ await copyFile(opencodeJson, path.join(targetDir, 'opencode.json'), dryRun);
332
395
  }
333
396
  }
334
- const agentFiles = [
335
- { src: path.join(effectiveStarter, '.claude', 'agents'), dest: path.join(targetDir, '.claude', 'agents') },
336
- { src: path.join(effectiveStarter, '.codex', 'agents'), dest: path.join(targetDir, '.codex', 'agents') },
337
- ];
338
- for (const { src, dest } of agentFiles) {
339
- if (await exists(src)) {
340
- const entries = await readDirNames(src);
397
+ else {
398
+ const skillRoots = [
399
+ path.join(effectiveStarter, '.grok', 'skills'),
400
+ path.join(effectiveStarter, '.claude', 'skills'),
401
+ path.join(effectiveStarter, '.codex', 'skills'),
402
+ ];
403
+ for (const skillsDir of skillRoots) {
404
+ if (!(await exists(skillsDir)))
405
+ continue;
406
+ const toolPrefix = skillsDir.includes('.grok')
407
+ ? '.grok/skills'
408
+ : skillsDir.includes('.claude')
409
+ ? '.claude/skills'
410
+ : '.codex/skills';
411
+ const entries = await readDirNames(skillsDir);
341
412
  for (const entry of entries) {
342
- await copyFile(path.join(src, entry), path.join(dest, entry), dryRun);
413
+ await copyDir(path.join(skillsDir, entry), path.join(targetDir, toolPrefix, entry), dryRun);
414
+ }
415
+ }
416
+ const agentFiles = [
417
+ { src: path.join(effectiveStarter, '.claude', 'agents'), dest: path.join(targetDir, '.claude', 'agents') },
418
+ { src: path.join(effectiveStarter, '.codex', 'agents'), dest: path.join(targetDir, '.codex', 'agents') },
419
+ ];
420
+ for (const { src, dest } of agentFiles) {
421
+ if (await exists(src)) {
422
+ const entries = await readDirNames(src);
423
+ for (const entry of entries) {
424
+ await copyFile(path.join(src, entry), path.join(dest, entry), dryRun);
425
+ }
343
426
  }
344
427
  }
345
428
  }
@@ -361,7 +444,7 @@ Examples:
361
444
  await copyL2Templates(pattern, tool, targetDir, templatesRoot, dryRun);
362
445
  await scaffoldObservability(pattern, tool, targetDir, templatesRoot, dryRun);
363
446
  await scaffoldConstraints(targetDir, templatesRoot, tool, dryRun);
364
- if (!dryRun && !(await exists(path.join(targetDir, 'AGENTS.md')))) {
447
+ if (tool !== 'opencode' && !dryRun && !(await exists(path.join(targetDir, 'AGENTS.md')))) {
365
448
  const agentsTemplate = `# AGENTS.md
366
449
 
367
450
  ## Test commands
@@ -375,10 +458,29 @@ npm run lint
375
458
  await writeFile(path.join(targetDir, 'AGENTS.md'), agentsTemplate);
376
459
  console.log(' created: AGENTS.md (template)');
377
460
  }
378
- console.log('\n=== Next steps ===');
379
- console.log(` npx @cobusgreyling/loop-audit ${target === '.' ? '.' : target} --suggest`);
380
- console.log(` npx @cobusgreyling/loop-cost --pattern ${pattern}`);
381
- console.log(` First loop command (${tool}):\n ${firstLoopCommand(pattern, tool)}\n`);
461
+ const auditArg = auditTargetArg(target, targetDir);
462
+ if (!dryRun) {
463
+ const audit = await runAuditSummary(targetDir);
464
+ if (audit) {
465
+ console.log('');
466
+ console.log(`✓ Loop Ready: ${audit.score}/100 (${audit.level})`);
467
+ console.log(` ${formatScoreBar(audit.score)}`);
468
+ console.log(` ${audit.assessment}`);
469
+ console.log('');
470
+ console.log('Paste badge in README:');
471
+ console.log(` npx @cobusgreyling/loop-audit ${auditArg} --badge`);
472
+ }
473
+ else {
474
+ console.log('\n=== Loop Ready score ===');
475
+ console.log(` npx @cobusgreyling/loop-audit ${auditArg} --suggest`);
476
+ }
477
+ }
478
+ console.log('');
479
+ console.log(`First loop (${tool}):`);
480
+ console.log(` ${firstLoopCommand(pattern, tool)}`);
481
+ console.log('');
482
+ console.log(`Estimate cost: npx @cobusgreyling/loop-cost --pattern ${pattern} --level L1`);
483
+ console.log('');
382
484
  }
383
485
  async function readDirNames(dir) {
384
486
  const { readdir } = await import('node:fs/promises');
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cobusgreyling/loop-init",
3
- "version": "1.2.3",
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",
3
+ "version": "1.3.2",
4
+ "description": "Scaffold loop engineering patterns and starters into any project. Supports Grok, Claude Code, Codex, Opencode and more. npx @cobusgreyling/loop-init . --pattern daily-triage --tool opencode",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "loop-init": "./dist/cli.js"
@@ -31,6 +31,7 @@
31
31
  "claude-code",
32
32
  "grok",
33
33
  "codex",
34
+ "opencode",
34
35
  "github-actions",
35
36
  "patterns"
36
37
  ],
@@ -48,6 +49,9 @@
48
49
  "publishConfig": {
49
50
  "access": "public"
50
51
  },
52
+ "dependencies": {
53
+ "@cobusgreyling/loop-audit": "^1.5.0"
54
+ },
51
55
  "devDependencies": {
52
56
  "@types/node": "^26.0.0",
53
57
  "typescript": "^6.0.3"
@@ -14,21 +14,28 @@ npx @cobusgreyling/loop-init . -p pr-babysitter -t claude
14
14
  | [minimal-loop](./minimal-loop/) | Grok | `.grok/skills/` |
15
15
  | [minimal-loop-claude](./minimal-loop-claude/) | Claude Code | `.claude/skills/` + `.claude/agents/` |
16
16
  | [minimal-loop-codex](./minimal-loop-codex/) | Codex | `.codex/skills/` + `.codex/agents/` |
17
+ | [minimal-loop-opencode](./minimal-loop-opencode/) | Opencode | `skills/` + `AGENTS.md` |
17
18
 
18
19
  ## L2 assisted patterns
19
20
 
20
21
  | Starter | Pattern | Tools | Readiness |
21
22
  |---------|---------|-------|-----------|
22
23
  | [pr-babysitter](./pr-babysitter/) | PR Babysitter | Grok, Claude, Codex | L2 assisted |
24
+ | [pr-babysitter-opencode](./pr-babysitter-opencode/) | PR Babysitter | Opencode | L1 → L2 |
23
25
  | [ci-sweeper](./ci-sweeper/) | CI Sweeper | Grok, Claude, Codex | L2 assisted |
26
+ | [ci-sweeper-opencode](./ci-sweeper-opencode/) | CI Sweeper | Opencode | L2 cautious |
24
27
  | [dependency-sweeper](./dependency-sweeper/) | Dependency Sweeper | Grok, Claude, Codex | L2 patch-only |
28
+ | [dependency-sweeper-opencode](./dependency-sweeper-opencode/) | Dependency Sweeper | Opencode | L2 patch-only |
25
29
  | [post-merge-cleanup](./post-merge-cleanup/) | Post-Merge Cleanup | Grok, Claude, Codex | L1 → L2 |
30
+ | [post-merge-cleanup-opencode](./post-merge-cleanup-opencode/) | Post-Merge Cleanup | Opencode | L1 → L2 |
26
31
  | [changelog-drafter](./changelog-drafter/) | Changelog Drafter | Grok, Claude, Codex | L1 draft → L2 |
32
+ | [changelog-drafter-opencode](./changelog-drafter-opencode/) | Changelog Drafter | Opencode | L1 draft → L2 |
27
33
  | [issue-triage](./issue-triage/) | Issue Triage | Grok, Claude, Codex | L1 propose-only |
34
+ | [issue-triage-opencode](./issue-triage-opencode/) | Issue Triage | Opencode | L1 propose-only |
28
35
 
29
36
  After copying:
30
37
 
31
38
  ```bash
32
39
  npx @cobusgreyling/loop-audit .
33
40
  npx @cobusgreyling/loop-audit . --suggest
34
- ```
41
+ ```
@@ -0,0 +1,15 @@
1
+ # AGENTS.md — Changelog Drafter (Opencode)
2
+
3
+ ## Loop Mode
4
+ - L1 report + draft for the first 1-2 weeks.
5
+ - Read `changelog-drafter-state.md` before every run.
6
+ - Human approves every draft before any publish or PR.
7
+
8
+ ## Safety
9
+ - Never create tags, GitHub releases, or update CHANGELOG.md without explicit human approval.
10
+ - Breaking changes and security items must be surfaced explicitly.
11
+ - Draft PRs only when L2 is enabled — never auto-merge.
12
+
13
+ ## Verification
14
+ - Verifier checks draft completeness: categories, date range, links.
15
+ - Record draft status and human feedback in state.
@@ -0,0 +1,26 @@
1
+ # Loop Configuration — Changelog Drafter (Opencode)
2
+
3
+ ## Active Loops
4
+
5
+ | Pattern | Cadence | Status | Command |
6
+ |---------|---------|--------|---------|
7
+ | Changelog Drafter | 1d or on release prep | L1 draft-only | `opencode run "Run changelog-scan"` via cron (after merges settle) |
8
+
9
+ ## Human Gates
10
+ - Breaking changes always human review.
11
+ - Security notes / CVEs human must approve wording.
12
+ - No tags, no PRs, no publishes without explicit approval.
13
+ - First 3 releases: human approves full draft.
14
+
15
+ ## Budget
16
+ - Max sub-agent spawns per run: 2 (scanner + drafter).
17
+ - Prefer running after merges settle (evening).
18
+
19
+ ## Output Convention
20
+ - Draft: `RELEASE_NOTES_DRAFT.md` at repo root.
21
+ - State: `changelog-drafter-state.md`.
22
+
23
+ ## Links
24
+ - Pattern: [changelog-drafter](../../patterns/changelog-drafter.md)
25
+ - Example: [examples/opencode/changelog-drafter.md](../../examples/opencode/changelog-drafter.md)
26
+ - Safety: [docs/safety.md](../../docs/safety.md)
@@ -0,0 +1,44 @@
1
+ # Changelog Drafter — Opencode Starter
2
+
3
+ Clone-and-run scaffold for the **Changelog Drafter** pattern with opencode. Scan merged PRs and commits, produce categorized release notes.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npx @cobusgreyling/loop-init . --pattern changelog-drafter --tool opencode
9
+ ```
10
+
11
+ Or copy manually:
12
+
13
+ ```bash
14
+ cp -r starters/changelog-drafter-opencode/skills .
15
+ cp starters/changelog-drafter-opencode/AGENTS.md .
16
+ cp starters/changelog-drafter-opencode/LOOP.md .
17
+ cp starters/changelog-drafter-opencode/changelog-drafter-state.md.example changelog-drafter-state.md
18
+ cp starters/changelog-drafter-opencode/opencode.json.example opencode.json
19
+ ```
20
+
21
+ Start (L1 report + draft, week 1):
22
+
23
+ ```bash
24
+ opencode run \
25
+ "Run skills/changelog-scan/SKILL.md. Scan merges since last tag (or last 7 days). Produce categorized draft in RELEASE_NOTES_DRAFT.md. Update state. Do not publish or create PRs." \
26
+ --title "Changelog drafter"
27
+ ```
28
+
29
+ ## What's Included
30
+
31
+ | File | Purpose |
32
+ |------|---------|
33
+ | `changelog-drafter-state.md.example` | State spine (last release, draft status) |
34
+ | `skills/changelog-scan/SKILL.md` | Merge scan and categorization skill |
35
+ | `AGENTS.md` | Always-on safety rules |
36
+ | `LOOP.md` | Cadence, gates, budget |
37
+ | `opencode.json.example` | Named agent definitions |
38
+
39
+ ## Next Steps
40
+
41
+ - [patterns/changelog-drafter.md](../../patterns/changelog-drafter.md)
42
+ - [examples/opencode/changelog-drafter.md](../../examples/opencode/changelog-drafter.md)
43
+ - [docs/loop-design-checklist.md](../../docs/loop-design-checklist.md)
44
+ - [stories/changelog-drafter-week-one.md](../../stories/changelog-drafter-week-one.md)
@@ -0,0 +1,10 @@
1
+ # Changelog Drafter State
2
+ Last run: 2026-06-20 09:00 UTC
3
+ Last tag scanned: v0.0.0
4
+ Draft status: none
5
+ Human feedback: pending
6
+
7
+ ## Scan Window
8
+ - From: <!-- last tag or date -->
9
+ - To: <!-- current -->
10
+ - Merges found: 0
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "agent": {
4
+ "changelog-scan": {
5
+ "name": "changelog-scan",
6
+ "description": "Changelog drafting loop. Reads changelog-drafter-state.md, scans merges, and produces categorized release notes.",
7
+ "mode": "primary",
8
+ "prompt": "Read AGENTS.md, LOOP.md, changelog-drafter-state.md, and skills/changelog-scan/SKILL.md. Scan merges since last tag. Produce categorized draft in RELEASE_NOTES_DRAFT.md. Never publish or tag without human approval.",
9
+ "permission": {
10
+ "bash": "ask",
11
+ "edit": "ask"
12
+ }
13
+ },
14
+ "implementer": {
15
+ "name": "implementer",
16
+ "description": "L2 implementer for creating changelog PRs.",
17
+ "mode": "subagent",
18
+ "prompt": "Commit the approved release notes to a new branch and open a draft PR. Flag breaking changes and security items explicitly in the PR body. Do not merge.",
19
+ "permission": {
20
+ "bash": "ask",
21
+ "edit": "ask"
22
+ }
23
+ },
24
+ "verifier": {
25
+ "name": "verifier",
26
+ "description": "Checker agent for draft release notes. APPROVE or REJECT only.",
27
+ "mode": "subagent",
28
+ "prompt": "Review the draft notes for completeness, categorization, and correct date range. Flag missing sections. Do not edit. APPROVE or REJECT.",
29
+ "permission": {
30
+ "bash": "ask",
31
+ "edit": "deny"
32
+ }
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: changelog-scan
3
+ description: >
4
+ Scan merged PRs and commits since a given reference, extract
5
+ titles, labels, types, and signals. Produces structured input
6
+ for release notes drafting.
7
+ user_invocable: true
8
+ ---
9
+
10
+ # Changelog Scan Skill
11
+
12
+ You are a changelog drafting agent. Scan merges and produce release notes.
13
+
14
+ ## Scan Sources
15
+
16
+ - `git log --merges --oneline <last-tag>..HEAD`
17
+ - PR labels and milestones
18
+ - Commit messages since last tag
19
+
20
+ ## Categories
21
+
22
+ - Features
23
+ - Bug fixes
24
+ - Documentation
25
+ - Dependencies
26
+ - Breaking changes
27
+ - Security
28
+
29
+ ## Output
30
+
31
+ - Categorized draft in `RELEASE_NOTES_DRAFT.md`
32
+ - Update `changelog-drafter-state.md` with scan window
33
+
34
+ ## Rules
35
+
36
+ - Never publish or tag without explicit human approval.
37
+ - Surface breaking changes and security items explicitly.
38
+ - L1: draft only — no PRs, no tags.
@@ -0,0 +1,17 @@
1
+ # AGENTS.md — CI Sweeper (Opencode)
2
+
3
+ ## Loop Mode
4
+ - CI sweeper is L2 from week one (action-oriented — CIs are urgent).
5
+ - Read `ci-sweeper-state.md` before every run.
6
+ - Classify failures before attempting any fix.
7
+
8
+ ## Safety
9
+ - Always dispatch into a git worktree per attempt.
10
+ - Infra / security / payments test failures: do not auto-fix; flag and stop.
11
+ - Max 3 fix attempts per item; escalate after.
12
+ - Enforce budget cap from `LOOP.md`.
13
+
14
+ ## Verification
15
+ - Verifier must run tests after implementer.
16
+ - Record attempt count in `ci-sweeper-state.md`.
17
+ - No auto-merge without verifier approval.
@@ -0,0 +1,26 @@
1
+ # Loop Configuration — CI Sweeper (Opencode)
2
+
3
+ ## Active Loops
4
+
5
+ | Pattern | Cadence | Status | Command |
6
+ |---------|---------|--------|---------|
7
+ | CI Sweeper | 5-15m | L2 cautious | `opencode run "Run ci-triage" --agent loop-triage` via cron/systemd |
8
+
9
+ ## Human Gates
10
+ - Infra / security / payments test failures: do not auto-fix.
11
+ - Max 3 fix attempts per item; escalate after.
12
+ - No auto-merge without verifier pass.
13
+
14
+ ## Worktrees
15
+ - Always dispatch into a git worktree per attempt.
16
+ - One worktree per fix; discard after REJECT.
17
+
18
+ ## Budget
19
+ - Max sub-agent spawns per run: 3.
20
+ - Max auto-PRs per day: 5.
21
+ - Early exit if no failures found.
22
+
23
+ ## Links
24
+ - Pattern: [ci-sweeper](../../patterns/ci-sweeper.md)
25
+ - Example: [examples/opencode/ci-sweeper.md](../../examples/opencode/ci-sweeper.md)
26
+ - Safety: [docs/safety.md](../../docs/safety.md)
@@ -0,0 +1,43 @@
1
+ # CI Sweeper — Opencode Starter
2
+
3
+ Clone-and-run scaffold for the **CI Sweeper** pattern with opencode. React to failing CI with minimal fixes at short cadences.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npx @cobusgreyling/loop-init . --pattern ci-sweeper --tool opencode
9
+ ```
10
+
11
+ Or copy manually:
12
+
13
+ ```bash
14
+ cp -r starters/ci-sweeper-opencode/skills .
15
+ cp starters/ci-sweeper-opencode/AGENTS.md .
16
+ cp starters/ci-sweeper-opencode/LOOP.md .
17
+ cp starters/ci-sweeper-opencode/ci-sweeper-state.md.example ci-sweeper-state.md
18
+ cp starters/ci-sweeper-opencode/opencode.json.example opencode.json
19
+ ```
20
+
21
+ Start (L2 cautious — CI sweeper is action-oriented from week one):
22
+
23
+ ```bash
24
+ opencode run \
25
+ "Run skills/ci-triage/SKILL.md. Classify each failing check. For clear single-file regressions, create a worktree and apply a minimal fix with verifier. Update ci-sweeper-state.md. Infra and security failures: escalate." \
26
+ --title "CI sweeper"
27
+ ```
28
+
29
+ ## What's Included
30
+
31
+ | File | Purpose |
32
+ |------|---------|
33
+ | `ci-sweeper-state.md.example` | State spine (in-flight CI failures) |
34
+ | `skills/ci-triage/SKILL.md` | CI-focused triage skill |
35
+ | `AGENTS.md` | Always-on safety rules |
36
+ | `LOOP.md` | Cadence, gates, budget |
37
+ | `opencode.json.example` | Named agent definitions |
38
+
39
+ ## Next Steps
40
+
41
+ - [patterns/ci-sweeper.md](../../patterns/ci-sweeper.md)
42
+ - [examples/opencode/ci-sweeper.md](../../examples/opencode/ci-sweeper.md)
43
+ - [docs/loop-design-checklist.md](../../docs/loop-design-checklist.md)
@@ -0,0 +1,10 @@
1
+ # CI Sweeper State
2
+ Last run: 2026-06-20 09:00 UTC
3
+ Active failures: 0
4
+ Attempt counts: {}
5
+
6
+ ## Failures
7
+ - <!-- Add failing checks here -->
8
+
9
+ ## Escalated
10
+ - <!-- Infra/security failures escalated to human -->