continuous-improvement 3.9.2 → 3.11.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 (150) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +61 -0
  3. package/QUICKSTART.md +13 -8
  4. package/README.md +84 -153
  5. package/bin/backfill.mjs +0 -0
  6. package/bin/check-doc-runtime-claims.mjs +0 -0
  7. package/bin/check-docs-substrings.mjs +73 -0
  8. package/bin/check-everything-mirror.mjs +0 -0
  9. package/bin/check-routing-targets.mjs +0 -0
  10. package/bin/check-scripts-citation-drift.mjs +210 -0
  11. package/bin/check-skill-count.mjs +110 -0
  12. package/bin/check-skill-law-tag.mjs +0 -0
  13. package/bin/check-skill-mirror.mjs +0 -0
  14. package/bin/check-skill-tiers.mjs +0 -0
  15. package/bin/check-test-imports-only.mjs +126 -0
  16. package/bin/check-third-party-shape.mjs +0 -0
  17. package/bin/companion-preference-status.mjs +231 -0
  18. package/bin/gateguard-clear.mjs +53 -0
  19. package/bin/generate-plugin-manifests.mjs +7 -1
  20. package/bin/harvest-friction.mjs +0 -0
  21. package/bin/hook-stats.mjs +0 -0
  22. package/bin/install.mjs +182 -26
  23. package/bin/lint-transcript.mjs +0 -0
  24. package/bin/mcp-server.mjs +215 -2
  25. package/bin/observe.mjs +0 -0
  26. package/bin/pre-commit-block-strays.sh +0 -0
  27. package/bin/refresh-third-party.mjs +315 -313
  28. package/bin/unified-cli.mjs +0 -0
  29. package/commands/audit.md +34 -0
  30. package/commands/companion-preference.md +58 -0
  31. package/commands/discipline.md +14 -0
  32. package/commands/distill.md +39 -0
  33. package/commands/goal-check.md +53 -0
  34. package/commands/grill-me.md +40 -0
  35. package/commands/grill-with-docs.md +38 -0
  36. package/commands/handoff.md +42 -0
  37. package/commands/proceed-with-the-recommendation.md +20 -0
  38. package/commands/recall.md +49 -0
  39. package/commands/reconcile.md +47 -0
  40. package/commands/superpowers.md +2 -2
  41. package/commands/verify-install.md +55 -0
  42. package/hooks/companion-preference.mjs +190 -0
  43. package/hooks/gateguard.mjs +60 -25
  44. package/hooks/goal-drift-stop.mjs +183 -0
  45. package/hooks/observe.sh +15 -1
  46. package/hooks/route-prompt.mjs +180 -0
  47. package/hooks/route-table.json +35 -0
  48. package/hooks/three-section-close.mjs +134 -132
  49. package/lib/cli-anything.mjs +0 -0
  50. package/lib/compound-engineering.mjs +0 -0
  51. package/lib/gateguard-state.mjs +54 -2
  52. package/lib/goal-drift-gate.mjs +50 -0
  53. package/lib/goal-state.mjs +285 -0
  54. package/lib/observe-event.mjs +0 -0
  55. package/lib/plugin-metadata.mjs +126 -12
  56. package/lib/pm-marketplace.mjs +0 -0
  57. package/lib/pm-skills.mjs +0 -0
  58. package/lib/recall-index.mjs +175 -0
  59. package/lib/resolve-home-dir.mjs +0 -0
  60. package/lib/skill-distill.mjs +222 -0
  61. package/lib/skill-tiers.mjs +0 -0
  62. package/lib/unified-plugin.mjs +0 -0
  63. package/llms.txt +1 -1
  64. package/package.json +11 -7
  65. package/plugins/beginner.json +8 -3
  66. package/plugins/continuous-improvement/.claude-plugin/marketplace.json +2 -2
  67. package/plugins/continuous-improvement/.claude-plugin/plugin.json +2 -2
  68. package/plugins/continuous-improvement/agents/README.md +2 -2
  69. package/plugins/continuous-improvement/bin/backfill.mjs +0 -0
  70. package/plugins/continuous-improvement/bin/gateguard-clear.mjs +53 -0
  71. package/plugins/continuous-improvement/bin/mcp-server.mjs +215 -2
  72. package/plugins/continuous-improvement/bin/observe.mjs +0 -0
  73. package/plugins/continuous-improvement/commands/audit.md +34 -0
  74. package/plugins/continuous-improvement/commands/companion-preference.md +58 -0
  75. package/plugins/continuous-improvement/commands/discipline.md +14 -0
  76. package/plugins/continuous-improvement/commands/distill.md +39 -0
  77. package/plugins/continuous-improvement/commands/goal-check.md +53 -0
  78. package/plugins/continuous-improvement/commands/grill-me.md +40 -0
  79. package/plugins/continuous-improvement/commands/grill-with-docs.md +38 -0
  80. package/plugins/continuous-improvement/commands/handoff.md +42 -0
  81. package/plugins/continuous-improvement/commands/proceed-with-the-recommendation.md +20 -0
  82. package/plugins/continuous-improvement/commands/recall.md +49 -0
  83. package/plugins/continuous-improvement/commands/reconcile.md +47 -0
  84. package/plugins/continuous-improvement/commands/superpowers.md +2 -2
  85. package/plugins/continuous-improvement/commands/verify-install.md +55 -0
  86. package/plugins/continuous-improvement/hooks/companion-preference.mjs +190 -0
  87. package/plugins/continuous-improvement/hooks/gateguard.mjs +60 -25
  88. package/plugins/continuous-improvement/hooks/goal-drift-stop.mjs +183 -0
  89. package/plugins/continuous-improvement/hooks/hooks.json +18 -2
  90. package/plugins/continuous-improvement/hooks/observe.sh +15 -1
  91. package/plugins/continuous-improvement/hooks/route-prompt.mjs +180 -0
  92. package/plugins/continuous-improvement/hooks/route-table.json +35 -0
  93. package/plugins/continuous-improvement/hooks/three-section-close.mjs +134 -132
  94. package/plugins/continuous-improvement/lib/gateguard-state.mjs +137 -0
  95. package/plugins/continuous-improvement/lib/goal-drift-gate.mjs +50 -0
  96. package/plugins/continuous-improvement/lib/goal-state.mjs +285 -0
  97. package/plugins/continuous-improvement/lib/observe-event.mjs +0 -0
  98. package/plugins/continuous-improvement/lib/plugin-metadata.mjs +126 -12
  99. package/plugins/continuous-improvement/lib/recall-index.mjs +175 -0
  100. package/plugins/continuous-improvement/lib/resolve-home-dir.mjs +0 -0
  101. package/plugins/continuous-improvement/lib/skill-distill.mjs +222 -0
  102. package/plugins/continuous-improvement/skills/README.md +8 -0
  103. package/plugins/continuous-improvement/skills/audit/SKILL.md +73 -0
  104. package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +13 -17
  105. package/plugins/continuous-improvement/skills/gateguard/SKILL.md +36 -17
  106. package/plugins/continuous-improvement/skills/goal-monitor/SKILL.md +81 -0
  107. package/plugins/continuous-improvement/skills/grill-me/SKILL.md +66 -0
  108. package/plugins/continuous-improvement/skills/grill-with-docs/SKILL.md +252 -0
  109. package/plugins/continuous-improvement/skills/handoff/SKILL.md +59 -0
  110. package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +1 -1
  111. package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +82 -6
  112. package/plugins/continuous-improvement/skills/ralph/SKILL.md +1 -0
  113. package/plugins/continuous-improvement/skills/recall/SKILL.md +50 -0
  114. package/plugins/continuous-improvement/skills/reconcile/SKILL.md +80 -0
  115. package/plugins/continuous-improvement/skills/recovery-classification/SKILL.md +1 -0
  116. package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +1 -0
  117. package/plugins/continuous-improvement/skills/skill-distillation/SKILL.md +57 -0
  118. package/plugins/continuous-improvement/skills/state-reconciliation/SKILL.md +1 -0
  119. package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +1 -0
  120. package/plugins/continuous-improvement/skills/superpowers/SKILL.md +76 -2
  121. package/plugins/continuous-improvement/skills/token-budget-advisor/SKILL.md +1 -1
  122. package/plugins/continuous-improvement/skills/verification-loop/SKILL.md +28 -20
  123. package/plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md +1 -0
  124. package/plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md +1 -1
  125. package/plugins/continuous-improvement/skills/worktree-safety/SKILL.md +3 -2
  126. package/plugins/expert.json +27 -2
  127. package/skills/README.md +3 -0
  128. package/skills/audit.md +73 -0
  129. package/skills/deploy-receipt.md +13 -17
  130. package/skills/gateguard.md +36 -17
  131. package/skills/goal-monitor.md +81 -0
  132. package/skills/grill-me.md +66 -0
  133. package/skills/grill-with-docs.md +252 -0
  134. package/skills/handoff.md +59 -0
  135. package/skills/para-memory-files.md +1 -1
  136. package/skills/proceed-with-the-recommendation.md +82 -6
  137. package/skills/ralph.md +1 -0
  138. package/skills/recall.md +50 -0
  139. package/skills/reconcile.md +80 -0
  140. package/skills/recovery-classification.md +1 -0
  141. package/skills/safety-guard.md +1 -0
  142. package/skills/skill-distillation.md +57 -0
  143. package/skills/state-reconciliation.md +1 -0
  144. package/skills/strategic-compact.md +1 -0
  145. package/skills/superpowers.md +76 -2
  146. package/skills/token-budget-advisor.md +1 -1
  147. package/skills/verification-loop.md +28 -20
  148. package/skills/wild-risa-balance.md +1 -0
  149. package/skills/workspace-surface-audit.md +1 -1
  150. package/skills/worktree-safety.md +3 -2
@@ -0,0 +1,222 @@
1
+ // skill-distill.mts — Pure trajectory → draft-skill distillation.
2
+ //
3
+ // No I/O. Scans observation rows for repeated tool sequences that ended in a
4
+ // successful verification, and proposes DRAFT instincts capturing the pattern.
5
+ // The MCP tools ci_distill_candidates / ci_distill_propose / ci_distill_promote
6
+ // (src/bin/mcp-server.mts) wire the file reads and writes around these
7
+ // functions.
8
+ //
9
+ // Closed-loop "Learn From Every Session" (Law 7) on the SUCCESS side: the
10
+ // friction harvester (src/bin/harvest-friction.mts) already turns failures into
11
+ // instincts; this turns repeated wins into reusable drafts. Drafts never enter
12
+ // the suggestion pool — they require explicit promotion — so a coincidental
13
+ // tool sequence cannot cargo-cult itself into enforced behavior.
14
+ const MIN_TRAJECTORY_LENGTH = 4;
15
+ const GAP_MS = 10 * 60 * 1000;
16
+ const NGRAM_SIZES = [3, 4, 5];
17
+ const DEFAULT_MIN_OCCURRENCES = 3;
18
+ const DEFAULT_MIN_SESSIONS = 2;
19
+ const DRAFT_CONFIDENCE = 0.4;
20
+ const VERIFY_CMD = /\b(npm\s+(run\s+)?(test|verify(:[\w-]+)?|build)|pnpm\s+(test|build)|yarn\s+(test|build)|pytest|cargo\s+test|go\s+test|jest|vitest|make\s+test)\b/i;
21
+ const FAILURE_MARKER = /\b(error|errors|fail|failed|failing|not found|denied|cannot|exception|traceback)\b|exit code [1-9]/i;
22
+ const SUCCESS_MARKER = /\b(pass|passed|passing|success|succeeded|green|0 failures|all tests)\b|\bok\b/i;
23
+ const REFLECTION_MARKER = /\b(verified|phase[- ]?4|verify:all green|all tests pass)\b/i;
24
+ const NOISE_TOOL = /^(ci_|mcp__|TodoWrite$)/;
25
+ function session(obs) {
26
+ return (obs.session ?? obs.session_id ?? "").toString();
27
+ }
28
+ function text(obs) {
29
+ return `${obs.input_summary ?? ""}\n${obs.output_summary ?? ""}`;
30
+ }
31
+ function classifyTrajectorySuccess(observations) {
32
+ for (const obs of observations) {
33
+ if ((obs.tool ?? "") === "Bash") {
34
+ const input = (obs.input_summary ?? "").toString();
35
+ const output = (obs.output_summary ?? "").toString();
36
+ if (VERIFY_CMD.test(input) && !FAILURE_MARKER.test(output) && (output === "" || SUCCESS_MARKER.test(output))) {
37
+ return "verify-exit-0";
38
+ }
39
+ }
40
+ }
41
+ for (const obs of observations) {
42
+ if (REFLECTION_MARKER.test(text(obs))) {
43
+ return "reflection-pass";
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ /**
49
+ * Split a chronological observation list into contiguous trajectories. A
50
+ * boundary occurs on session change or a time gap longer than GAP_MS. Only
51
+ * trajectories of at least MIN_TRAJECTORY_LENGTH observations are returned;
52
+ * each is classified as succeeded or not.
53
+ */
54
+ export function extractTrajectories(observations) {
55
+ const out = [];
56
+ let group = [];
57
+ const flush = () => {
58
+ if (group.length < MIN_TRAJECTORY_LENGTH) {
59
+ group = [];
60
+ return;
61
+ }
62
+ const successReason = classifyTrajectorySuccess(group);
63
+ out.push({
64
+ observations: group,
65
+ session: session(group[0]),
66
+ startTs: (group[0].ts ?? "").toString(),
67
+ endTs: (group[group.length - 1].ts ?? "").toString(),
68
+ succeeded: successReason !== null,
69
+ successReason,
70
+ });
71
+ group = [];
72
+ };
73
+ for (const obs of observations) {
74
+ if (group.length === 0) {
75
+ group.push(obs);
76
+ continue;
77
+ }
78
+ const prev = group[group.length - 1];
79
+ const sessionChanged = session(obs) !== session(prev);
80
+ const prevMs = Date.parse((prev.ts ?? "").toString());
81
+ const curMs = Date.parse((obs.ts ?? "").toString());
82
+ const prevValid = !Number.isNaN(prevMs);
83
+ const curValid = !Number.isNaN(curMs);
84
+ const gapTooBig = (prevValid && curValid && curMs - prevMs > GAP_MS) || (prevValid !== curValid);
85
+ if (sessionChanged || gapTooBig) {
86
+ flush();
87
+ }
88
+ group.push(obs);
89
+ }
90
+ flush();
91
+ return out;
92
+ }
93
+ function toolSequence(trajectory) {
94
+ return trajectory.observations
95
+ .map((obs) => (obs.tool ?? "").toString())
96
+ .filter((tool) => tool.length > 0 && !NOISE_TOOL.test(tool));
97
+ }
98
+ // Tool names are external data (observations.jsonl). The candidate id is later
99
+ // joined into a draft file path, so it must be slugified to [a-z0-9-] to keep a
100
+ // hostile tool name (`../`, `/`, `\`) from escaping the drafts directory.
101
+ function slugifyNgram(ngram) {
102
+ const slug = ngram
103
+ .join("-")
104
+ .toLowerCase()
105
+ .replace(/[^a-z0-9-]+/g, "-")
106
+ .replace(/-+/g, "-")
107
+ .replace(/^-+|-+$/g, "");
108
+ return slug.length > 0 ? slug : "sequence";
109
+ }
110
+ /**
111
+ * Mine repeated tool-sequence n-grams from SUCCESSFUL trajectories. A candidate
112
+ * must occur at least `minOccurrences` times across at least `minSessions`
113
+ * distinct sessions — so a pattern repeated within a single session is rejected.
114
+ * Sorted by occurrences then n-gram length, both descending.
115
+ */
116
+ export function findCandidates(trajectories, opts = {}) {
117
+ const minOccurrences = opts.minOccurrences ?? DEFAULT_MIN_OCCURRENCES;
118
+ const minSessions = opts.minSessions ?? DEFAULT_MIN_SESSIONS;
119
+ const aggregates = new Map();
120
+ for (const trajectory of trajectories) {
121
+ if (!trajectory.succeeded)
122
+ continue;
123
+ const sequence = toolSequence(trajectory);
124
+ const outcome = trajectory.successReason ?? "unknown";
125
+ for (const size of NGRAM_SIZES) {
126
+ for (let i = 0; i + size <= sequence.length; i += 1) {
127
+ const ngram = sequence.slice(i, i + size);
128
+ const key = ngram.join(">");
129
+ let aggregate = aggregates.get(key);
130
+ if (!aggregate) {
131
+ aggregate = { ngram, occurrences: 0, sessions: new Set(), outcomes: new Set() };
132
+ aggregates.set(key, aggregate);
133
+ }
134
+ aggregate.occurrences += 1;
135
+ aggregate.sessions.add(trajectory.session);
136
+ aggregate.outcomes.add(outcome);
137
+ }
138
+ }
139
+ }
140
+ const candidates = [];
141
+ for (const aggregate of aggregates.values()) {
142
+ if (aggregate.occurrences < minOccurrences)
143
+ continue;
144
+ if (aggregate.sessions.size < minSessions)
145
+ continue;
146
+ candidates.push({
147
+ id: `draft-${slugifyNgram(aggregate.ngram)}`,
148
+ ngram: aggregate.ngram,
149
+ occurrences: aggregate.occurrences,
150
+ sessions: [...aggregate.sessions],
151
+ outcomes: [...aggregate.outcomes],
152
+ });
153
+ }
154
+ candidates.sort((a, b) => b.occurrences !== a.occurrences ? b.occurrences - a.occurrences : b.ngram.length - a.ngram.length);
155
+ return candidates;
156
+ }
157
+ /** Turn a candidate into a DRAFT instinct with a placeholder body for the user to fill in. */
158
+ export function draftFromCandidate(candidate) {
159
+ const arrow = candidate.ngram.join(" → ");
160
+ const outcome = candidate.outcomes.join(", ");
161
+ return {
162
+ id: candidate.id,
163
+ trigger: `Auto-detected pattern: ${candidate.ngram.join(" then ")} (seen ${candidate.occurrences}x across ${candidate.sessions.length} sessions)`,
164
+ body: [
165
+ "When this situation recurs, follow the proven sequence that worked before:",
166
+ "",
167
+ ` ${arrow}`,
168
+ "",
169
+ `This pattern succeeded in ${candidate.occurrences} run(s) across ${candidate.sessions.length} session(s) (outcome: ${outcome}).`,
170
+ "Replace this placeholder with the concrete steps, preconditions, and gotchas before promoting —",
171
+ "the tool sequence alone is evidence, not a recipe.",
172
+ ].join("\n"),
173
+ confidence: DRAFT_CONFIDENCE,
174
+ domain: "workflow",
175
+ ngram: candidate.ngram,
176
+ occurrences: candidate.occurrences,
177
+ sessions: candidate.sessions.length,
178
+ outcome,
179
+ };
180
+ }
181
+ /**
182
+ * Serialize a draft to the instinct YAML format (key: value lines, `---`, body)
183
+ * so it round-trips through the same parser that reads live instincts. Stored
184
+ * under drafts/ so it is not picked up as a live instinct until promoted.
185
+ */
186
+ export function serializeDraft(draft) {
187
+ return [
188
+ `id: ${draft.id}`,
189
+ `trigger: "${draft.trigger}"`,
190
+ `confidence: ${draft.confidence}`,
191
+ `domain: ${draft.domain}`,
192
+ "source: distilled",
193
+ "status: draft",
194
+ `evidence_ngram: "${draft.ngram.join(">")}"`,
195
+ `evidence_occurrences: ${draft.occurrences}`,
196
+ `evidence_sessions: ${draft.sessions}`,
197
+ `evidence_outcome: "${draft.outcome}"`,
198
+ "---",
199
+ draft.body,
200
+ "",
201
+ ].join("\n");
202
+ }
203
+ /** Render candidates as a markdown block for the MCP tool output. */
204
+ export function formatCandidates(candidates, limit = 10) {
205
+ if (candidates.length === 0) {
206
+ return "No distillation candidates found. A candidate needs a tool sequence that recurred across multiple successful sessions. Keep working — patterns accrue as the observation log grows.";
207
+ }
208
+ const shown = candidates.slice(0, limit);
209
+ const lines = [
210
+ `## Distillation Candidates (${candidates.length})`,
211
+ "",
212
+ "Repeated tool sequences from successful sessions. Propose a draft with `ci_distill_propose id=<id>`, edit its body, then `ci_distill_promote id=<id>`.",
213
+ "",
214
+ ];
215
+ for (const candidate of shown) {
216
+ lines.push(`- **${candidate.id}**`, ` Sequence: ${candidate.ngram.join(" → ")}`, ` Seen ${candidate.occurrences}x across ${candidate.sessions.length} session(s) — outcome: ${candidate.outcomes.join(", ")}`);
217
+ }
218
+ if (candidates.length > limit) {
219
+ lines.push("", `_…and ${candidates.length - limit} more._`);
220
+ }
221
+ return lines.join("\n");
222
+ }
File without changes
File without changes
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # continuous-improvement
2
2
 
3
- > Stops Claude Code from skipping research, claiming 'done' without verifying, and repeating yesterday's mistakes. The 7 Laws of AI Agent Discipline — 13 enforcement skills, gating hooks, and the Mulahazah auto-leveling instinct engine.
3
+ > Stops Claude Code from skipping research, claiming 'done' without verifying, and repeating yesterday's mistakes. The 7 Laws of AI Agent Discipline — 25 bundled skills, gating hooks, the Mulahazah auto-leveling instinct engine, and a GitHub Action transcript linter.
4
4
 
5
5
  ## What This Is
6
6
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "continuous-improvement",
3
- "version": "3.9.2",
4
- "description": "Stops Claude Code from skipping research, claiming 'done' without verifying, and repeating yesterday's mistakes. The 7 Laws of AI Agent Discipline — 13 enforcement skills, gating hooks, the Mulahazah auto-leveling instinct engine, and a GitHub Action transcript linter. Beginner: one /plugin install command. Expert: adds MCP tools and session hooks.",
3
+ "version": "3.11.0",
4
+ "description": "Stops Claude Code from skipping research, claiming 'done' without verifying, and repeating yesterday's mistakes. The 7 Laws of AI Agent Discipline — 25 bundled skills, gating hooks, the Mulahazah auto-leveling instinct engine, and a GitHub Action transcript linter. Beginner: one /plugin install command. Expert: adds MCP tools and session hooks.",
5
5
  "keywords": [
6
6
  "claude-code",
7
7
  "claude-code-skill",
@@ -22,7 +22,7 @@
22
22
  "type": "git",
23
23
  "url": "git+https://github.com/naimkatiman/continuous-improvement.git"
24
24
  },
25
- "homepage": "https://github.com/naimkatiman/continuous-improvement#readme",
25
+ "homepage": "https://continuous-improvement.dev",
26
26
  "bugs": {
27
27
  "url": "https://github.com/naimkatiman/continuous-improvement/issues"
28
28
  },
@@ -32,21 +32,25 @@
32
32
  "ci": "bin/unified-cli.mjs"
33
33
  },
34
34
  "scripts": {
35
- "build": "tsc -p tsconfig.json && node bin/generate-plugin-manifests.mjs",
35
+ "build": "tsc -p tsconfig.json && node bin/generate-plugin-manifests.mjs && node -e \"const fs=require('node:fs'); for (const f of fs.readdirSync('bin')) { if (f.endsWith('.mjs')) fs.chmodSync('bin/'+f, 0o755); } for (const f of fs.readdirSync('hooks')) { if (f.endsWith('.mjs')) fs.chmodSync('hooks/'+f, 0o755); } for (const f of fs.readdirSync('lib')) { if (f.endsWith('.mjs')) fs.chmodSync('lib/'+f, 0o755); } for (const f of fs.readdirSync('plugins/continuous-improvement/bin')) { if (f.endsWith('.mjs')) fs.chmodSync('plugins/continuous-improvement/bin/'+f, 0o755); } for (const f of fs.readdirSync('plugins/continuous-improvement/lib')) { if (f.endsWith('.mjs')) fs.chmodSync('plugins/continuous-improvement/lib/'+f, 0o755); } for (const f of fs.readdirSync('plugins/continuous-improvement/hooks')) { if (f.endsWith('.mjs')) fs.chmodSync('plugins/continuous-improvement/hooks/'+f, 0o755); } for (const f of fs.readdirSync('scripts')) { if (f.endsWith('.mjs')) fs.chmodSync('scripts/'+f, 0o755); } for (const f of fs.readdirSync('synthetic-checks')) { if (f.endsWith('.mjs')) fs.chmodSync('synthetic-checks/'+f, 0o755); } \"",
36
36
  "typecheck": "tsc -p tsconfig.json --noEmit",
37
- "clean": "node -e \"const fs=require('node:fs'); for (const dir of ['bin','test','lib']) { if (!fs.existsSync(dir)) continue; for (const file of fs.readdirSync(dir)) { if (file.endsWith('.mjs')) fs.rmSync(dir + '/' + file, { force: true }); } }\"",
37
+ "clean": "node -e \"const fs=require('node:fs'); for (const dir of ['bin','hooks','test','lib']) { if (!fs.existsSync(dir)) continue; for (const file of fs.readdirSync(dir)) { if (file.endsWith('.mjs')) fs.rmSync(dir+'/'+file, { force: true }); } }\"",
38
38
  "hooks:stats": "node bin/hook-stats.mjs",
39
39
  "test": "npm run build && node --test test/*.test.mjs",
40
40
  "lint": "node bin/lint-transcript.mjs --help",
41
- "verify:generated": "npm run build && git diff --exit-code -- .claude-plugin bin test lib plugins",
41
+ "verify:generated": "npm run build && git diff --exit-code -- .claude-plugin bin hooks test lib plugins",
42
42
  "verify:skill-mirror": "node bin/check-skill-mirror.mjs",
43
43
  "verify:skill-tiers": "node bin/check-skill-tiers.mjs",
44
44
  "verify:skill-law-tag": "node bin/check-skill-law-tag.mjs",
45
+ "verify:skill-count": "node bin/check-skill-count.mjs",
45
46
  "verify:docs-substrings": "node bin/check-docs-substrings.mjs",
46
47
  "verify:everything-mirror": "node bin/check-everything-mirror.mjs",
47
48
  "verify:routing-targets": "node bin/check-routing-targets.mjs",
48
49
  "verify:doc-runtime-claims": "node bin/check-doc-runtime-claims.mjs",
49
- "verify:all": "npm run verify:skill-mirror && npm run verify:skill-tiers && npm run verify:skill-law-tag && npm run verify:docs-substrings && npm run verify:everything-mirror && npm run verify:routing-targets && npm run verify:doc-runtime-claims && npm run typecheck"
50
+ "verify:test-imports-only": "node bin/check-test-imports-only.mjs",
51
+ "verify:scripts-citation-drift": "node bin/check-scripts-citation-drift.mjs",
52
+ "verify:third-party-shape": "node bin/check-third-party-shape.mjs",
53
+ "verify:all": "npm run verify:skill-mirror && npm run verify:skill-tiers && npm run verify:skill-law-tag && npm run verify:skill-count && npm run verify:docs-substrings && npm run verify:everything-mirror && npm run verify:routing-targets && npm run verify:doc-runtime-claims && npm run verify:test-imports-only && npm run verify:scripts-citation-drift && npm run verify:third-party-shape && npm run typecheck"
50
54
  },
51
55
  "files": [
52
56
  ".claude-plugin/",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "continuous-improvement",
3
- "version": "3.9.2",
3
+ "version": "3.11.0",
4
4
  "mode": "beginner",
5
5
  "description": "Beginner mode: see what your agent learned, list its instincts, and request a session reflection. Bundles four discipline skills (gateguard, para-memory-files, tdd-workflow, verification-loop) so research, memory, tests, and verification happen by default.",
6
6
  "tools": [
@@ -15,6 +15,10 @@
15
15
  {
16
16
  "name": "ci_reflect",
17
17
  "what": "Reflect on what you did this session"
18
+ },
19
+ {
20
+ "name": "ci_gateguard_clear",
21
+ "what": "Clear the GateGuard gate for files after presenting facts"
18
22
  }
19
23
  ],
20
24
  "setup": {
@@ -46,8 +50,9 @@
46
50
  "hooks": {
47
51
  "included": [
48
52
  "PreToolUse",
49
- "PostToolUse"
53
+ "PostToolUse",
54
+ "UserPromptSubmit"
50
55
  ],
51
- "description": "Silently captures every tool call as observations. Lightweight and non-blocking."
56
+ "description": "Silently captures every tool call as observations and routes prompts to the matching discipline skill via the route table. Lightweight and non-blocking."
52
57
  }
53
58
  }
@@ -7,8 +7,8 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "continuous-improvement",
10
- "description": "Stops Claude Code from skipping research, claiming 'done' without verifying, and repeating yesterday's mistakes. The 7 Laws of AI Agent Discipline — 13 enforcement skills, gating hooks, and the Mulahazah auto-leveling instinct engine.",
11
- "version": "3.9.2",
10
+ "description": "Stops Claude Code from skipping research, claiming 'done' without verifying, and repeating yesterday's mistakes. The 7 Laws of AI Agent Discipline — 25 bundled skills, gating hooks, the Mulahazah auto-leveling instinct engine, and a GitHub Action transcript linter.",
11
+ "version": "3.11.0",
12
12
  "source": "./",
13
13
  "author": {
14
14
  "name": "naimkatiman"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "continuous-improvement",
3
- "version": "3.9.2",
4
- "description": "Stops Claude Code from skipping research, claiming 'done' without verifying, and repeating yesterday's mistakes. The 7 Laws of AI Agent Discipline — 13 enforcement skills, gating hooks, and the Mulahazah auto-leveling instinct engine.",
3
+ "version": "3.11.0",
4
+ "description": "Stops Claude Code from skipping research, claiming 'done' without verifying, and repeating yesterday's mistakes. The 7 Laws of AI Agent Discipline — 25 bundled skills, gating hooks, the Mulahazah auto-leveling instinct engine, and a GitHub Action transcript linter.",
5
5
  "author": {
6
6
  "name": "naimkatiman",
7
7
  "url": "https://github.com/naimkatiman"
@@ -40,7 +40,7 @@ Pick this only when **independent** investigations can run in parallel and produ
40
40
 
41
41
  - `/ship` → fans out to `code-reviewer` + `security-auditor` + `test-engineer` in parallel, then synthesizes their reports into a go/no-go decision
42
42
 
43
- This is the only orchestration pattern this repo endorses. See [references/orchestration-patterns.md](../references/orchestration-patterns.md) for the full pattern catalog and anti-patterns.
43
+ This is the only orchestration pattern this repo endorses. See `references/orchestration-patterns.md` for the full pattern catalog and anti-patterns.
44
44
 
45
45
  ## Decision matrix
46
46
 
@@ -107,7 +107,7 @@ The personas in this repo are designed to work as Claude Code subagents and as A
107
107
  - **As subagents:** auto-discovered when this plugin is enabled (no path config needed). Use the Agent tool with `subagent_type: code-reviewer` (or `security-auditor`, `test-engineer`). `/ship` is the canonical example.
108
108
  - **As Agent Teams teammates** (experimental, requires `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`): reference the same persona name when spawning a teammate. The persona's body is **appended to** the teammate's system prompt as additional instructions (not a replacement), so your persona text sits on top of the team-coordination instructions the lead installs (SendMessage, task-list tools, etc.).
109
109
 
110
- Subagents only report results back to the main agent. Agent Teams let teammates message each other directly. Use subagents when reports are enough; use Agent Teams when sub-agents need to challenge each other's findings (e.g. competing-hypothesis debugging). See [references/orchestration-patterns.md](../references/orchestration-patterns.md) for the full mapping.
110
+ Subagents only report results back to the main agent. Agent Teams let teammates message each other directly. Use subagents when reports are enough; use Agent Teams when sub-agents need to challenge each other's findings (e.g. competing-hypothesis debugging). See `references/orchestration-patterns.md` for the full mapping.
111
111
 
112
112
  Plugin agents do not support `hooks`, `mcpServers`, or `permissionMode` frontmatter — those fields are silently ignored. Avoid relying on them when authoring new personas here.
113
113
 
File without changes
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * gateguard-clear — record GateGuard clearance for files from the Bash route.
4
+ *
5
+ * The GateGuard PreToolUse hook blocks the first Edit/Write per file and prints
6
+ * the session-state path in its block reason. After presenting the required
7
+ * facts, run this to clear the gate so the retry is allowed. Bash is not gated
8
+ * (unless the command is destructive), so this surface always works — including
9
+ * where the ci_gateguard_clear MCP tool is not connected.
10
+ *
11
+ * Usage:
12
+ * node bin/gateguard-clear.mjs <file_path> [<file_path>...] [--state <path>]
13
+ *
14
+ * Default resolves the session dir canonically, the same way the hook does.
15
+ * --state <path> writes that exact gateguard-session.json — the path the block
16
+ * reason prints — bypassing resolution for any residual env mismatch.
17
+ */
18
+ import { dirname, join } from "node:path";
19
+ import { MAX_CLEARED_FILES, clearFiles, resolveSessionDir, } from "../lib/gateguard-state.mjs";
20
+ function main() {
21
+ const argv = process.argv.slice(2);
22
+ const files = [];
23
+ let stateFile = "";
24
+ for (let i = 0; i < argv.length; i += 1) {
25
+ const arg = argv[i];
26
+ if (arg === "--state") {
27
+ stateFile = argv[i + 1] ?? "";
28
+ i += 1;
29
+ }
30
+ else {
31
+ files.push(arg);
32
+ }
33
+ }
34
+ if (argv.includes("--state") && stateFile === "") {
35
+ process.stderr.write("--state requires a <gateguard-session.json> path argument\n");
36
+ process.exit(2);
37
+ }
38
+ if (files.length === 0) {
39
+ process.stderr.write("usage: gateguard-clear <file_path> [<file_path>...] [--state <gateguard-session.json>]\n");
40
+ process.exit(2);
41
+ }
42
+ // clearFiles writes <sessionDir>/gateguard-session.json. With --state the
43
+ // caller hands us the full state-file path the block reason printed, so the
44
+ // session dir is its parent.
45
+ const sessionDir = stateFile ? dirname(stateFile) : resolveSessionDir();
46
+ const { cleared, skippedForCap } = clearFiles(sessionDir, files);
47
+ process.stdout.write(`Cleared ${cleared.length}: ${cleared.length > 0 ? cleared.join(", ") : "(none — already cleared)"}\n`);
48
+ if (skippedForCap.length > 0) {
49
+ process.stdout.write(`Skipped — session cap of ${MAX_CLEARED_FILES} reached: ${skippedForCap.join(", ")}\n`);
50
+ }
51
+ process.stdout.write(`State: ${join(sessionDir, "gateguard-session.json")}\n`);
52
+ }
53
+ main();