@cobusgreyling/loop-init 1.1.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.
Files changed (69) hide show
  1. package/README.md +47 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +296 -0
  4. package/package.json +45 -0
  5. package/starters/README.md +33 -0
  6. package/starters/changelog-drafter/.claude/agents/verifier.md +5 -0
  7. package/starters/changelog-drafter/.claude/skills/changelog-scan/SKILL.md +11 -0
  8. package/starters/changelog-drafter/.claude/skills/draft-release-notes/SKILL.md +11 -0
  9. package/starters/changelog-drafter/.codex/agents/verifier.toml +12 -0
  10. package/starters/changelog-drafter/.codex/skills/changelog-scan/SKILL.md +9 -0
  11. package/starters/changelog-drafter/.codex/skills/draft-release-notes/SKILL.md +9 -0
  12. package/starters/changelog-drafter/.grok/skills/changelog-scan/SKILL.md +53 -0
  13. package/starters/changelog-drafter/.grok/skills/draft-release-notes/SKILL.md +65 -0
  14. package/starters/changelog-drafter/.grok/skills/loop-verifier/SKILL.md +40 -0
  15. package/starters/changelog-drafter/LOOP.md +32 -0
  16. package/starters/changelog-drafter/README.md +48 -0
  17. package/starters/changelog-drafter/changelog-drafter-state.md.example +18 -0
  18. package/starters/ci-sweeper/.claude/agents/loop-verifier.md +35 -0
  19. package/starters/ci-sweeper/.claude/skills/ci-triage/SKILL.md +29 -0
  20. package/starters/ci-sweeper/.codex/agents/verifier.toml +15 -0
  21. package/starters/ci-sweeper/.codex/skills/ci-triage/SKILL.md +29 -0
  22. package/starters/ci-sweeper/.grok/skills/ci-triage/SKILL.md +29 -0
  23. package/starters/ci-sweeper/README.md +27 -0
  24. package/starters/ci-sweeper/ci-sweeper-state.md.example +12 -0
  25. package/starters/dependency-sweeper/.claude/agents/loop-verifier.md +35 -0
  26. package/starters/dependency-sweeper/.claude/skills/dependency-triage/SKILL.md +36 -0
  27. package/starters/dependency-sweeper/.codex/agents/verifier.toml +15 -0
  28. package/starters/dependency-sweeper/.codex/skills/dependency-triage/SKILL.md +36 -0
  29. package/starters/dependency-sweeper/.grok/skills/dependency-triage/SKILL.md +36 -0
  30. package/starters/dependency-sweeper/LOOP.md +30 -0
  31. package/starters/dependency-sweeper/README.md +46 -0
  32. package/starters/dependency-sweeper/dependency-sweeper-state.md.example +23 -0
  33. package/starters/minimal-loop/.grok/skills/loop-triage/SKILL.md +46 -0
  34. package/starters/minimal-loop/LOOP.md +22 -0
  35. package/starters/minimal-loop/README.md +41 -0
  36. package/starters/minimal-loop/STATE.md.example +12 -0
  37. package/starters/minimal-loop-claude/.claude/agents/loop-verifier.md +35 -0
  38. package/starters/minimal-loop-claude/.claude/skills/loop-triage/SKILL.md +46 -0
  39. package/starters/minimal-loop-claude/LOOP.md +32 -0
  40. package/starters/minimal-loop-claude/README.md +42 -0
  41. package/starters/minimal-loop-claude/STATE.md.example +12 -0
  42. package/starters/minimal-loop-codex/.codex/agents/verifier.toml +15 -0
  43. package/starters/minimal-loop-codex/.codex/skills/loop-triage/SKILL.md +46 -0
  44. package/starters/minimal-loop-codex/LOOP.md +32 -0
  45. package/starters/minimal-loop-codex/README.md +49 -0
  46. package/starters/minimal-loop-codex/STATE.md.example +12 -0
  47. package/starters/post-merge-cleanup/.claude/agents/loop-verifier.md +35 -0
  48. package/starters/post-merge-cleanup/.claude/skills/post-merge-scan/SKILL.md +34 -0
  49. package/starters/post-merge-cleanup/.codex/agents/verifier.toml +15 -0
  50. package/starters/post-merge-cleanup/.codex/skills/post-merge-scan/SKILL.md +34 -0
  51. package/starters/post-merge-cleanup/.grok/skills/post-merge-scan/SKILL.md +34 -0
  52. package/starters/post-merge-cleanup/LOOP.md +22 -0
  53. package/starters/post-merge-cleanup/README.md +34 -0
  54. package/starters/post-merge-cleanup/post-merge-state.md.example +22 -0
  55. package/starters/pr-babysitter/.claude/agents/loop-verifier.md +35 -0
  56. package/starters/pr-babysitter/.claude/skills/pr-review-triage/SKILL.md +29 -0
  57. package/starters/pr-babysitter/.codex/agents/verifier.toml +15 -0
  58. package/starters/pr-babysitter/.codex/skills/pr-review-triage/SKILL.md +29 -0
  59. package/starters/pr-babysitter/.grok/skills/pr-review-triage/SKILL.md +29 -0
  60. package/starters/pr-babysitter/LOOP.md +20 -0
  61. package/starters/pr-babysitter/README.md +36 -0
  62. package/starters/pr-babysitter/pr-babysitter-state.md.example +19 -0
  63. package/templates/SKILL.md.loop-triage +54 -0
  64. package/templates/SKILL.md.minimal-fix +45 -0
  65. package/templates/SKILL.md.verifier +48 -0
  66. package/templates/STATE.md.template +22 -0
  67. package/templates/loop-budget.md.template +22 -0
  68. package/templates/loop-run-log.md.template +22 -0
  69. package/templates/pattern-template.md +58 -0
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # loop-init
2
+
3
+ Scaffold loop engineering starters into your project by pattern and tool.
4
+
5
+ ## Install & Run
6
+
7
+ ```bash
8
+ npx @cobusgreyling/loop-init . --pattern daily-triage --tool grok
9
+ npx @cobusgreyling/loop-init . -p pr-babysitter -t claude
10
+ npx @cobusgreyling/loop-init . -p dependency-sweeper --dry-run
11
+ ```
12
+
13
+ See [docs/RELEASE.md](../../docs/RELEASE.md) for npm publish tags. The published package bundles `starters/` and `templates/` from this monorepo.
14
+
15
+ ## Patterns
16
+
17
+ | Pattern | Default state file |
18
+ |---------|-------------------|
19
+ | `daily-triage` | `STATE.md` |
20
+ | `pr-babysitter` | `pr-babysitter-state.md` |
21
+ | `ci-sweeper` | `ci-sweeper-state.md` |
22
+ | `dependency-sweeper` | `dependency-sweeper-state.md` |
23
+ | `post-merge-cleanup` | `post-merge-state.md` |
24
+ | `changelog-drafter` | `changelog-drafter-state.md` |
25
+
26
+ L2 patterns (`ci-sweeper`, `dependency-sweeper`) also copy `minimal-fix` and `loop-verifier` templates when missing from the starter.
27
+
28
+ ## Tools
29
+
30
+ - `grok` (default)
31
+ - `claude`
32
+ - `codex`
33
+
34
+ Falls back to Grok starter paths when a per-tool variant is not yet available.
35
+
36
+ ## From this repo
37
+
38
+ ```bash
39
+ cd tools/loop-init && npm ci && npm test
40
+ node dist/cli.js /path/to/project --pattern daily-triage --tool grok
41
+ ```
42
+
43
+ Pair with `loop-audit` after scaffolding:
44
+
45
+ ```bash
46
+ npx @cobusgreyling/loop-audit . --suggest
47
+ ```
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,296 @@
1
+ #!/usr/bin/env node
2
+ import { cp, mkdir, readFile, writeFile, access } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
7
+ const MONOREPO_STARTERS = path.resolve(PACKAGE_ROOT, '../../starters');
8
+ const MONOREPO_TEMPLATES = path.resolve(PACKAGE_ROOT, '../../templates');
9
+ const PATTERN_STARTERS = {
10
+ 'daily-triage': 'minimal-loop',
11
+ 'pr-babysitter': 'pr-babysitter',
12
+ 'ci-sweeper': 'ci-sweeper',
13
+ 'dependency-sweeper': 'dependency-sweeper',
14
+ 'post-merge-cleanup': 'post-merge-cleanup',
15
+ 'changelog-drafter': 'changelog-drafter',
16
+ };
17
+ const TOOL_SUFFIX = {
18
+ grok: '',
19
+ claude: '-claude',
20
+ codex: '-codex',
21
+ };
22
+ const L2_PATTERNS = new Set(['ci-sweeper', 'dependency-sweeper']);
23
+ const PATTERNS_NEEDING_FIX = new Set([
24
+ 'pr-babysitter',
25
+ 'ci-sweeper',
26
+ 'dependency-sweeper',
27
+ 'post-merge-cleanup',
28
+ ]);
29
+ const STATE_FILES = {
30
+ 'daily-triage': 'STATE.md',
31
+ 'pr-babysitter': 'pr-babysitter-state.md',
32
+ 'ci-sweeper': 'ci-sweeper-state.md',
33
+ 'dependency-sweeper': 'dependency-sweeper-state.md',
34
+ 'post-merge-cleanup': 'post-merge-state.md',
35
+ 'changelog-drafter': 'changelog-drafter-state.md',
36
+ };
37
+ function parseArgs(argv) {
38
+ let pattern = 'daily-triage';
39
+ let tool = 'grok';
40
+ let target = '.';
41
+ let dryRun = false;
42
+ for (let i = 0; i < argv.length; i++) {
43
+ const a = argv[i];
44
+ if (a === '--pattern' || a === '-p')
45
+ pattern = argv[++i];
46
+ else if (a === '--tool' || a === '-t')
47
+ tool = argv[++i];
48
+ else if (a === '--dry-run')
49
+ dryRun = true;
50
+ else if (a === '--help' || a === '-h')
51
+ return { help: true, pattern, tool, target, dryRun };
52
+ else if (!a.startsWith('-'))
53
+ target = a;
54
+ }
55
+ return { help: false, pattern, tool, target, dryRun };
56
+ }
57
+ async function exists(p) {
58
+ try {
59
+ await access(p);
60
+ return true;
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ async function copyDir(src, dest, dryRun) {
67
+ if (!(await exists(src)))
68
+ return false;
69
+ if (dryRun) {
70
+ console.log(` would copy: ${src} → ${dest}`);
71
+ return true;
72
+ }
73
+ await mkdir(path.dirname(dest), { recursive: true });
74
+ await cp(src, dest, { recursive: true });
75
+ console.log(` copied: ${src} → ${dest}`);
76
+ return true;
77
+ }
78
+ async function resolveBundledOrMonorepo(name) {
79
+ const bundled = path.join(PACKAGE_ROOT, name);
80
+ if (await exists(bundled))
81
+ return bundled;
82
+ return name === 'starters' ? MONOREPO_STARTERS : MONOREPO_TEMPLATES;
83
+ }
84
+ async function copyTemplateSkill(templatesRoot, templateFile, targetDir, tool, skillName, dryRun) {
85
+ const src = path.join(templatesRoot, templateFile);
86
+ const destByTool = {
87
+ grok: path.join(targetDir, '.grok', 'skills', skillName, 'SKILL.md'),
88
+ claude: path.join(targetDir, '.claude', 'skills', skillName, 'SKILL.md'),
89
+ codex: path.join(targetDir, '.codex', 'skills', skillName, 'SKILL.md'),
90
+ };
91
+ const dest = destByTool[tool];
92
+ if (await exists(dest))
93
+ return;
94
+ await copyFile(src, dest, dryRun);
95
+ }
96
+ async function copyTemplateVerifier(templatesRoot, targetDir, tool, dryRun) {
97
+ const verifierPaths = {
98
+ grok: path.join(targetDir, '.grok', 'skills', 'loop-verifier', 'SKILL.md'),
99
+ claude: path.join(targetDir, '.claude', 'agents', 'loop-verifier.md'),
100
+ codex: path.join(targetDir, '.codex', 'agents', 'verifier.toml'),
101
+ };
102
+ const dest = verifierPaths[tool];
103
+ if (await exists(dest))
104
+ return;
105
+ if (tool === 'codex') {
106
+ const src = path.join(templatesRoot, 'SKILL.md.verifier');
107
+ const body = await readFile(src, 'utf8');
108
+ const toml = `name = "loop-verifier"\ndescription = "Independent verification agent for loop-produced changes."\n\n[system_prompt]\ncontent = """\n${body}\n"""\n`;
109
+ if (dryRun) {
110
+ console.log(` would write verifier: ${dest}`);
111
+ return;
112
+ }
113
+ await mkdir(path.dirname(dest), { recursive: true });
114
+ await writeFile(dest, toml);
115
+ console.log(` created: ${dest} (from verifier template)`);
116
+ return;
117
+ }
118
+ const src = path.join(templatesRoot, 'SKILL.md.verifier');
119
+ await copyFile(src, dest, dryRun);
120
+ }
121
+ async function copyL2Templates(pattern, tool, targetDir, templatesRoot, dryRun) {
122
+ if (!PATTERNS_NEEDING_FIX.has(pattern) && !L2_PATTERNS.has(pattern))
123
+ return;
124
+ await copyTemplateSkill(templatesRoot, 'SKILL.md.minimal-fix', targetDir, tool, 'minimal-fix', dryRun);
125
+ if (L2_PATTERNS.has(pattern) || pattern === 'dependency-sweeper') {
126
+ await copyTemplateVerifier(templatesRoot, targetDir, tool, dryRun);
127
+ }
128
+ }
129
+ async function copyFile(src, dest, dryRun) {
130
+ if (!(await exists(src)))
131
+ return false;
132
+ if (dryRun) {
133
+ console.log(` would copy: ${src} → ${dest}`);
134
+ return true;
135
+ }
136
+ await mkdir(path.dirname(dest), { recursive: true });
137
+ await cp(src, dest);
138
+ console.log(` copied: ${src} → ${dest}`);
139
+ return true;
140
+ }
141
+ function firstLoopCommand(pattern, tool) {
142
+ const cmds = {
143
+ 'daily-triage': {
144
+ grok: '/loop 1d Run loop-triage. Update STATE.md. No auto-fix in week one.',
145
+ claude: '/loop 1d $loop-triage — update STATE.md. Report-only week one.',
146
+ codex: 'Automation daily: $loop-triage → update STATE.md. Report-only.',
147
+ },
148
+ 'pr-babysitter': {
149
+ grok: '/loop 10m Run pr-review-triage. Update pr-babysitter-state.md. Worktree + minimal-fix + verifier for allowlisted PRs only. Escalate after 3 attempts.',
150
+ claude: '/loop 10m $pr-review-triage — update pr-babysitter-state.md. No auto-merge.',
151
+ codex: 'Automation 10m: pr-review-triage → pr-babysitter-state.md. No auto-merge.',
152
+ },
153
+ 'ci-sweeper': {
154
+ grok: '/loop 15m Run ci-triage on failing CI. Update ci-sweeper-state.md. Fix only regressions in worktree. Max 3 attempts.',
155
+ claude: '/loop 15m $ci-triage — update ci-sweeper-state.md. Max 3 fix attempts.',
156
+ codex: 'Automation 15m: ci-triage on CI failures. Max 3 attempts.',
157
+ },
158
+ 'dependency-sweeper': {
159
+ grok: '/loop 6h Run dependency-triage. Patch-only auto-fix in worktree + verifier. Escalate majors and denylist.',
160
+ claude: '/loop 6h $dependency-triage — patch-only with verifier. Escalate risky bumps.',
161
+ codex: 'Automation 6h: dependency-triage. Patch-only with verifier.',
162
+ },
163
+ 'post-merge-cleanup': {
164
+ grok: '/loop 1d Run post-merge-scan on recent merges. Update post-merge-state.md. Small fixes only in worktree.',
165
+ claude: '/loop 1d $post-merge-scan — update post-merge-state.md. Small fixes only.',
166
+ codex: 'Automation daily: post-merge-scan → post-merge-state.md.',
167
+ },
168
+ 'changelog-drafter': {
169
+ 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.',
170
+ claude: '/loop 1d $changelog-scan + draft-release-notes — write RELEASE_NOTES_DRAFT.md and update state. Human approves before publish.',
171
+ codex: 'Automation daily: changelog-scan + draft-release-notes → RELEASE_NOTES_DRAFT.md. Human review.',
172
+ },
173
+ };
174
+ return cmds[pattern][tool];
175
+ }
176
+ async function main() {
177
+ const args = parseArgs(process.argv.slice(2));
178
+ if (args.help) {
179
+ console.log(`loop-init — scaffold loop engineering starters
180
+
181
+ Usage:
182
+ loop-init [target-dir] --pattern <name> --tool <grok|claude|codex>
183
+
184
+ Patterns:
185
+ daily-triage (default)
186
+ pr-babysitter
187
+ ci-sweeper
188
+ dependency-sweeper
189
+ post-merge-cleanup
190
+ changelog-drafter (new low-risk release notes pattern)
191
+
192
+ Options:
193
+ -p, --pattern Pattern to scaffold
194
+ -t, --tool Tool target (default: grok)
195
+ --dry-run Print actions without copying
196
+ -h, --help This help
197
+
198
+ Examples:
199
+ npx @cobusgreyling/loop-init . --pattern daily-triage --tool grok
200
+ npx @cobusgreyling/loop-init . -p pr-babysitter -t claude
201
+ `);
202
+ process.exit(0);
203
+ }
204
+ const { pattern, tool, target, dryRun } = args;
205
+ const targetDir = path.resolve(target);
206
+ const baseStarter = PATTERN_STARTERS[pattern];
207
+ const suffix = TOOL_SUFFIX[tool];
208
+ const starterName = pattern === 'daily-triage' ? `minimal-loop${suffix}` : baseStarter;
209
+ const startersRoot = await resolveBundledOrMonorepo('starters');
210
+ const templatesRoot = await resolveBundledOrMonorepo('templates');
211
+ const starterRoot = path.join(startersRoot, starterName);
212
+ if (!(await exists(starterRoot))) {
213
+ const fallback = path.join(startersRoot, baseStarter);
214
+ if (!(await exists(fallback))) {
215
+ console.error(`Starter not found: ${starterRoot}`);
216
+ process.exit(1);
217
+ }
218
+ console.log(`Note: no ${tool} variant for ${pattern} — using ${baseStarter} (Grok paths)`);
219
+ }
220
+ const effectiveStarter = (await exists(starterRoot))
221
+ ? starterRoot
222
+ : path.join(startersRoot, baseStarter);
223
+ console.log(`\nloop-init: ${pattern} → ${targetDir} (${tool})${dryRun ? ' [dry-run]' : ''}\n`);
224
+ const skillRoots = [
225
+ path.join(effectiveStarter, '.grok', 'skills'),
226
+ path.join(effectiveStarter, '.claude', 'skills'),
227
+ path.join(effectiveStarter, '.codex', 'skills'),
228
+ ];
229
+ for (const skillsDir of skillRoots) {
230
+ if (!(await exists(skillsDir)))
231
+ continue;
232
+ const toolPrefix = skillsDir.includes('.grok')
233
+ ? '.grok/skills'
234
+ : skillsDir.includes('.claude')
235
+ ? '.claude/skills'
236
+ : '.codex/skills';
237
+ const entries = await readDirNames(skillsDir);
238
+ for (const entry of entries) {
239
+ await copyDir(path.join(skillsDir, entry), path.join(targetDir, toolPrefix, entry), dryRun);
240
+ }
241
+ }
242
+ const agentFiles = [
243
+ { src: path.join(effectiveStarter, '.claude', 'agents'), dest: path.join(targetDir, '.claude', 'agents') },
244
+ { src: path.join(effectiveStarter, '.codex', 'agents'), dest: path.join(targetDir, '.codex', 'agents') },
245
+ ];
246
+ for (const { src, dest } of agentFiles) {
247
+ if (await exists(src)) {
248
+ const entries = await readDirNames(src);
249
+ for (const entry of entries) {
250
+ await copyFile(path.join(src, entry), path.join(dest, entry), dryRun);
251
+ }
252
+ }
253
+ }
254
+ const stateFile = STATE_FILES[pattern];
255
+ const stateExample = path.join(effectiveStarter, `${stateFile}.example`);
256
+ if (await exists(stateExample)) {
257
+ await copyFile(stateExample, path.join(targetDir, stateFile), dryRun);
258
+ }
259
+ else {
260
+ const alt = path.join(effectiveStarter, 'STATE.md.example');
261
+ if (await exists(alt)) {
262
+ await copyFile(alt, path.join(targetDir, stateFile), dryRun);
263
+ }
264
+ }
265
+ const loopMd = path.join(effectiveStarter, 'LOOP.md');
266
+ if (await exists(loopMd)) {
267
+ await copyFile(loopMd, path.join(targetDir, 'LOOP.md'), dryRun);
268
+ }
269
+ await copyL2Templates(pattern, tool, targetDir, templatesRoot, dryRun);
270
+ if (!dryRun && !(await exists(path.join(targetDir, 'AGENTS.md')))) {
271
+ const agentsTemplate = `# AGENTS.md
272
+
273
+ ## Test commands
274
+ npm test
275
+ npm run lint
276
+
277
+ ## Loop conventions
278
+ - Report-only week one (L1) before enabling auto-fix (L2)
279
+ - See LOOP.md for cadence and human gates
280
+ `;
281
+ await writeFile(path.join(targetDir, 'AGENTS.md'), agentsTemplate);
282
+ console.log(' created: AGENTS.md (template)');
283
+ }
284
+ console.log('\n=== Next steps ===');
285
+ console.log(` npx @cobusgreyling/loop-audit ${target === '.' ? '.' : target} --suggest`);
286
+ console.log(` First loop command (${tool}):\n ${firstLoopCommand(pattern, tool)}\n`);
287
+ }
288
+ async function readDirNames(dir) {
289
+ const { readdir } = await import('node:fs/promises');
290
+ const entries = await readdir(dir, { withFileTypes: true });
291
+ return entries.filter((e) => e.isDirectory() || e.isFile()).map((e) => e.name);
292
+ }
293
+ main().catch((err) => {
294
+ console.error('loop-init failed:', err instanceof Error ? err.message : err);
295
+ process.exit(1);
296
+ });
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@cobusgreyling/loop-init",
3
+ "version": "1.1.0",
4
+ "description": "Scaffold loop engineering starters into your project by pattern and tool.",
5
+ "type": "module",
6
+ "bin": {
7
+ "loop-init": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "starters",
12
+ "templates",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "bundle": "node scripts/bundle-assets.mjs",
17
+ "build": "npm run bundle && tsc",
18
+ "test": "npm run build && node --test test/cli.test.mjs",
19
+ "prepublishOnly": "npm test",
20
+ "start": "node dist/cli.js"
21
+ },
22
+ "engines": {
23
+ "node": ">=18"
24
+ },
25
+ "keywords": [
26
+ "loop-engineering",
27
+ "ai-agents",
28
+ "scaffold",
29
+ "starter"
30
+ ],
31
+ "author": "Cobus Greyling",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/cobusgreyling/loop-engineering.git",
36
+ "directory": "tools/loop-init"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^20.0.0",
43
+ "typescript": "^5.0.0"
44
+ }
45
+ }
@@ -0,0 +1,33 @@
1
+ # Starters
2
+
3
+ Clone-and-run scaffolds. Copy into your project — or use `loop-init`:
4
+
5
+ ```bash
6
+ npx @cobusgreyling/loop-init . --pattern daily-triage --tool grok
7
+ npx @cobusgreyling/loop-init . -p pr-babysitter -t claude
8
+ ```
9
+
10
+ ## Daily Triage (L1 report-only)
11
+
12
+ | Starter | Tool | Path |
13
+ |---------|------|------|
14
+ | [minimal-loop](./minimal-loop/) | Grok | `.grok/skills/` |
15
+ | [minimal-loop-claude](./minimal-loop-claude/) | Claude Code | `.claude/skills/` + `.claude/agents/` |
16
+ | [minimal-loop-codex](./minimal-loop-codex/) | Codex | `.codex/skills/` + `.codex/agents/` |
17
+
18
+ ## L2 assisted patterns
19
+
20
+ | Starter | Pattern | Tools | Readiness |
21
+ |---------|---------|-------|-----------|
22
+ | [pr-babysitter](./pr-babysitter/) | PR Babysitter | Grok, Claude, Codex | L2 assisted |
23
+ | [ci-sweeper](./ci-sweeper/) | CI Sweeper | Grok, Claude, Codex | L2 assisted |
24
+ | [dependency-sweeper](./dependency-sweeper/) | Dependency Sweeper | Grok, Claude, Codex | L2 patch-only |
25
+ | [post-merge-cleanup](./post-merge-cleanup/) | Post-Merge Cleanup | Grok, Claude, Codex | L1 → L2 |
26
+ | [changelog-drafter](./changelog-drafter/) | Changelog Drafter | Grok, Claude, Codex | L1 draft → L2 |
27
+
28
+ After copying:
29
+
30
+ ```bash
31
+ npx @cobusgreyling/loop-audit .
32
+ npx @cobusgreyling/loop-audit . --suggest
33
+ ```
@@ -0,0 +1,5 @@
1
+ You are the independent verifier for the Changelog Drafter loop.
2
+
3
+ Review the draft against the raw scan data. Flag any hallucinated items, missing breaking/security notes, or tone problems.
4
+
5
+ Output a clear verdict + specific suggested fixes. Default to requiring changes.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: changelog-scan
3
+ description: Scan recent merges/PRs/commits for release note content. Structured output for drafter.
4
+ user_invocable: true
5
+ ---
6
+
7
+ # Changelog Scan (Claude)
8
+
9
+ Same contract as the Grok version. Produce the per-item blocks + Scan Summary.
10
+
11
+ Key rules: cite PR numbers, surface breaking/security explicitly, ignore pure dep and bot noise unless security.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: draft-release-notes
3
+ description: Turn changelog-scan output into polished, categorized release notes draft. Propose only.
4
+ user_invocable: true
5
+ ---
6
+
7
+ # Draft Release Notes (Claude)
8
+
9
+ Follow the exact structure and rules from the Grok `draft-release-notes` skill.
10
+
11
+ Output a clean `RELEASE_NOTES_DRAFT.md` (or clear section the loop can persist). Always flag breaking + security at top. End with review note for human.
@@ -0,0 +1,12 @@
1
+ name = "changelog-verifier"
2
+ description = "Independent checker for release note drafts produced by the changelog drafter. Accuracy and completeness focused."
3
+ reasoning_effort = "high"
4
+
5
+ [system_prompt]
6
+ content = """
7
+ You verify release note drafts against the source scan list.
8
+ - No invented changes.
9
+ - Breaking and security items must be prominent and accurate.
10
+ - Output: Verdict (APPROVE / REVISE / ESCALATE) + bullet list of issues or "looks good".
11
+ Default stance: require evidence.
12
+ """
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: changelog-scan
3
+ description: Scan recent merges and commits since last release for changelog content.
4
+ user_invocable: true
5
+ ---
6
+
7
+ Produce the same structured per-item + summary format as the reference implementation.
8
+
9
+ Focus on user-facing changes. Explicitly list breaking and security signals.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: draft-release-notes
3
+ description: Generate categorized release notes draft from scan data. Human must approve before publish.
4
+ user_invocable: true
5
+ ---
6
+
7
+ Use the standard release notes template (Features / Fixes / Breaking / Security / etc.).
8
+
9
+ Output clean markdown suitable for CHANGELOG or GitHub release. Include review disclaimer.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: changelog-scan
3
+ description: >
4
+ Scan recent merges to main (and noteworthy direct commits) since a given window
5
+ (last tag or date in state). Extract titles, labels, types, linked issues, and
6
+ signals for breaking changes or security. Produces structured input for a
7
+ release notes drafter. Use in changelog-drafter loops.
8
+ user_invocable: true
9
+ ---
10
+
11
+ # Changelog Scan Skill
12
+
13
+ ## Inputs the loop will provide
14
+ - Last release tag or previous run timestamp (from state or git)
15
+ - Current date / "now"
16
+ - Any explicit "since" override
17
+
18
+ ## Output Format (one block per significant item)
19
+
20
+ ```markdown
21
+ ### PR #1234 — feat(auth): add magic link login (merged 2026-06-08)
22
+ - Type: feature
23
+ - Labels: enhancement
24
+ - Breaking: no
25
+ - Security: no
26
+ - Linked: #1220
27
+ - Summary (one sentence from PR or commit): Users can now log in via emailed magic links.
28
+ - Files touched (high level): auth/, emails/
29
+ ```
30
+
31
+ Rules for what to include:
32
+ - All merged PRs to main in the window.
33
+ - Direct commits on main that look user-facing (conventional commit feat/fix/perf/security or have linked issues).
34
+ - Ignore pure dependency bumps, internal chores, and bot PRs unless they are security-related (those are handled by dependency-sweeper).
35
+
36
+ ## Additional Signals to Surface
37
+ - Any PR or commit message containing "BREAKING", "breaking change", or `!` conventional commit.
38
+ - Security-related keywords or labels (CVE, vuln, security).
39
+ - Items with "deprecate" or "remove" language.
40
+
41
+ ## Output Summary Section (always at end)
42
+
43
+ ```markdown
44
+ ## Scan Summary
45
+ - Total items: N
46
+ - Features: N
47
+ - Fixes: N
48
+ - Breaking: N (list them)
49
+ - Security: N (list them)
50
+ - Recommended next action for loop: draft-release-notes | human review needed first | too many items — split window
51
+ ```
52
+
53
+ Be precise and cite sources (PR numbers / shas). Do not invent details.
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: draft-release-notes
3
+ description: >
4
+ Takes a structured list of changes from changelog-scan and produces a clean,
5
+ categorized, user-facing release notes draft. Follows project voice and
6
+ conventions. Never publishes — only proposes a draft file or section.
7
+ user_invocable: true
8
+ ---
9
+
10
+ # Draft Release Notes Skill
11
+
12
+ ## Inputs
13
+ - Structured output from `changelog-scan` (the list of items + summary)
14
+ - Previous release version (from state)
15
+ - Target next version (or "unreleased" / "next")
16
+ - Optional: short "Release voice" guidance from AGENTS.md or a project skill (tone, what to highlight, what to omit)
17
+
18
+ ## Output
19
+ Write a ready-to-review draft to `RELEASE_NOTES_DRAFT.md` (or print it clearly so the loop can save it).
20
+
21
+ Use this structure (adapt section names to what actually exists; omit empty sections):
22
+
23
+ ```markdown
24
+ # Release Notes — vX.Y.Z (unreleased)
25
+
26
+ ## Breaking Changes
27
+ - ...
28
+
29
+ ## Features
30
+ - ...
31
+
32
+ ## Bug Fixes
33
+ - ...
34
+
35
+ ## Performance
36
+ - ...
37
+
38
+ ## Security
39
+ - ...
40
+
41
+ ## Documentation & Examples
42
+ - ...
43
+
44
+ ## Internal / Maintenance (usually omitted from public notes)
45
+ - ...
46
+
47
+ **Thanks** to @contributor1, @contributor2 for contributions to this release.
48
+
49
+ **Full changelog**: https://github.com/ORG/REPO/compare/vPREV...HEAD
50
+ ```
51
+
52
+ ## Rules
53
+ - Be concise and scannable. One line per item when possible, with link to PR.
54
+ - Use the actual title / one-sentence summary from the scan. Do not embellish or add marketing fluff unless the project voice explicitly wants it.
55
+ - Always call out breaking changes and security items at the top.
56
+ - If a change has a user upgrade step that is obvious from the PR, include a one-sentence "Upgrade note".
57
+ - Never claim a change was made if it was not in the scanned input.
58
+ - At the very end of the draft, include a short "Draft generated by loop — please review for accuracy and tone before publishing."
59
+
60
+ ## When to Escalate Instead of Drafting
61
+ - More than ~40 items in one window → suggest splitting the release or human curation.
62
+ - Any breaking or security item → include prominent callout and recommend human wordsmithing.
63
+ - The scan summary says "human review needed first".
64
+
65
+ After writing the draft, the loop should update state with the draft location and "pending human review".
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: loop-verifier
3
+ description: >
4
+ Independent checker for release note drafts. Reviews accuracy against the
5
+ changelog-scan data, tone, completeness, and flags breaking/security items.
6
+ Use after draft-release-notes. Never let the drafter verify itself.
7
+ user_invocable: true
8
+ ---
9
+
10
+ # Loop Verifier — Changelog Drafter
11
+
12
+ You are the checker. Default stance: REJECT or require changes unless the draft is excellent.
13
+
14
+ ## Inputs
15
+ - The raw structured scan output
16
+ - The draft produced by draft-release-notes
17
+ - Target version and previous version
18
+
19
+ ## Checklist
20
+ 1. Every item in the draft exists in the scan input (no hallucinations).
21
+ 2. Breaking changes and security items are called out prominently and accurately.
22
+ 3. No invented features or incorrect attribution.
23
+ 4. Tone matches the project (use any "Release voice" guidance provided).
24
+ 5. Draft is scannable and not overly long.
25
+ 6. Includes proper links and thanks where appropriate.
26
+
27
+ ## Output
28
+ ```markdown
29
+ ## Draft Verdict: APPROVE | REVISE | ESCALATE_HUMAN
30
+
31
+ ### Evidence
32
+ - Scan coverage: good | missing items (list)
33
+ - Accuracy: pass | issues (list)
34
+ - Tone & structure: good | needs work
35
+
36
+ ### Recommended changes (if any)
37
+ - ...
38
+ ```
39
+
40
+ If everything is solid: APPROVE and note "ready for human final review before publish".