continuous-improvement 3.22.1 → 3.24.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 (72) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +23 -0
  3. package/QUICKSTART.md +19 -20
  4. package/README.md +72 -19
  5. package/SKILL.md +4 -0
  6. package/bin/companion-preference-status.mjs +2 -5
  7. package/bin/generate-plugin-manifests.mjs +21 -2
  8. package/bin/harvest-friction.mjs +10 -8
  9. package/bin/install.mjs +208 -33
  10. package/bin/mcp-server.mjs +4 -9
  11. package/bin/observe.mjs +3 -3
  12. package/bin/reconcile-instinct-hashes.mjs +226 -0
  13. package/commands/discipline.md +5 -2
  14. package/commands/reconcile.md +1 -1
  15. package/commands/ship.md +5 -49
  16. package/commands/superpowers.md +1 -1
  17. package/commands/verify-install.md +8 -3
  18. package/hooks/companion-preference.mjs +2 -5
  19. package/hooks/config-guard.mjs +94 -0
  20. package/hooks/gateguard.mjs +39 -39
  21. package/hooks/goal-drift-stop.mjs +2 -2
  22. package/hooks/query-cost-nudge.mjs +2 -2
  23. package/hooks/recall-briefing.mjs +2 -2
  24. package/hooks/route-prompt.mjs +2 -5
  25. package/hooks/session.mjs +2 -2
  26. package/hooks/workflow-distill.mjs +2 -2
  27. package/lib/config-guard-gate.mjs +243 -0
  28. package/lib/destructive-bash.mjs +216 -0
  29. package/lib/gateguard-state.mjs +5 -1
  30. package/lib/plugin-metadata.mjs +12 -1
  31. package/lib/skill-catalog.mjs +169 -0
  32. package/llms.txt +11 -0
  33. package/package.json +1 -1
  34. package/plugins/beginner.json +2 -2
  35. package/plugins/continuous-improvement/.claude-plugin/marketplace.json +1 -1
  36. package/plugins/continuous-improvement/.claude-plugin/plugin.json +1 -1
  37. package/plugins/continuous-improvement/README.md +1 -2
  38. package/plugins/continuous-improvement/bin/mcp-server.mjs +4 -9
  39. package/plugins/continuous-improvement/bin/observe.mjs +3 -3
  40. package/plugins/continuous-improvement/commands/discipline.md +5 -2
  41. package/plugins/continuous-improvement/commands/reconcile.md +1 -1
  42. package/plugins/continuous-improvement/commands/ship.md +5 -49
  43. package/plugins/continuous-improvement/commands/superpowers.md +1 -1
  44. package/plugins/continuous-improvement/commands/verify-install.md +8 -3
  45. package/plugins/continuous-improvement/hooks/companion-preference.mjs +2 -5
  46. package/plugins/continuous-improvement/hooks/config-guard.mjs +94 -0
  47. package/plugins/continuous-improvement/hooks/gateguard.mjs +39 -39
  48. package/plugins/continuous-improvement/hooks/goal-drift-stop.mjs +2 -2
  49. package/plugins/continuous-improvement/hooks/hooks.json +10 -0
  50. package/plugins/continuous-improvement/hooks/query-cost-nudge.mjs +2 -2
  51. package/plugins/continuous-improvement/hooks/recall-briefing.mjs +2 -2
  52. package/plugins/continuous-improvement/hooks/route-prompt.mjs +2 -5
  53. package/plugins/continuous-improvement/hooks/session.mjs +2 -2
  54. package/plugins/continuous-improvement/hooks/workflow-distill.mjs +2 -2
  55. package/plugins/continuous-improvement/lib/config-guard-gate.mjs +243 -0
  56. package/plugins/continuous-improvement/lib/destructive-bash.mjs +216 -0
  57. package/plugins/continuous-improvement/lib/gateguard-state.mjs +5 -1
  58. package/plugins/continuous-improvement/lib/plugin-metadata.mjs +12 -1
  59. package/plugins/continuous-improvement/skills/README.md +1 -1
  60. package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +4 -0
  61. package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +1 -1
  62. package/plugins/continuous-improvement/skills/gateguard/SKILL.md +17 -2
  63. package/plugins/continuous-improvement/skills/reconcile/SKILL.md +0 -1
  64. package/plugins/continuous-improvement/skills/ship/SKILL.md +139 -0
  65. package/plugins/expert.json +1 -1
  66. package/skills/README.md +2 -2
  67. package/skills/deploy-receipt.md +1 -1
  68. package/skills/gateguard.md +17 -2
  69. package/skills/reconcile.md +0 -1
  70. package/skills/ship.md +139 -0
  71. package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +0 -77
  72. package/skills/safety-guard.md +0 -77
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Skill -> enforcing hook filename. Explicit because hook filenames describe
3
+ * the event they fire on, not the skill they serve. Adding a hook without
4
+ * adding its row here makes the catalog under-claim, which is the safe
5
+ * direction.
6
+ */
7
+ export const HOOK_BY_SKILL = {
8
+ gateguard: "gateguard.mjs",
9
+ "goal-monitor": "goal-drift-stop.mjs",
10
+ recall: "recall-briefing.mjs",
11
+ superpowers: "companion-preference.mjs",
12
+ "verification-loop": "typecheck-stop.mjs",
13
+ "skill-distillation": "workflow-distill.mjs",
14
+ };
15
+ const TIER_LABEL = {
16
+ core: "Core",
17
+ featured: "Featured",
18
+ "1": "Tier 1 — beginner",
19
+ "2": "Tier 2 — expert",
20
+ companion: "Always bundled",
21
+ unknown: "Unclassified",
22
+ };
23
+ const TIER_ORDER = ["core", "featured", "1", "2", "companion", "unknown"];
24
+ const ENFORCEMENT_TITLE = {
25
+ hook: "Enforced at the tool boundary by a hook — it fires whether or not the model cooperates.",
26
+ command: "Invoked by a slash command. Runs when you ask for it.",
27
+ prose: "Model-side discipline only. Nothing blocks and nothing fires automatically.",
28
+ };
29
+ /** Lift the Law tag out of a Law-tagged description. */
30
+ export function lawOf(description) {
31
+ if (!description)
32
+ return undefined;
33
+ if (/\ball\s+7\s+Laws\b/i.test(description))
34
+ return "all 7";
35
+ if (/\bLaw\s+activator\b/i.test(description))
36
+ return "activator";
37
+ const multi = description.match(/\bLaw\s*([1-7])\s*\+\s*([1-7])\b/i);
38
+ if (multi)
39
+ return `${multi[1]} + ${multi[2]}`;
40
+ const single = description.match(/\bLaw\s*([1-7])\b/i);
41
+ return single ? single[1] : undefined;
42
+ }
43
+ /** Resolve the enforcement surface for one skill from the shipped file set. */
44
+ export function enforcementOf(name, commandNames) {
45
+ const hookFile = HOOK_BY_SKILL[name];
46
+ if (hookFile)
47
+ return { enforcement: "hook", hookFile };
48
+ if (commandNames.has(name))
49
+ return { enforcement: "command" };
50
+ return { enforcement: "prose" };
51
+ }
52
+ function escapeHtml(value) {
53
+ return value
54
+ .replace(/&/g, "&")
55
+ .replace(/</g, "&lt;")
56
+ .replace(/>/g, "&gt;")
57
+ .replace(/"/g, "&quot;");
58
+ }
59
+ /** Strip the "Enforces Law N (…) of the 7 Laws…" preamble; keep what it does. */
60
+ export function summarize(description) {
61
+ if (!description)
62
+ return "";
63
+ return description
64
+ .replace(/^Enforces\s+(all\s+7\s+Laws|Law\s*[1-7](\s*\+\s*[1-7])?)[^.]*\.\s*/i, "")
65
+ .replace(/^Use this skill to\s*/i, "")
66
+ .trim();
67
+ }
68
+ const STYLE = `
69
+ :root { color-scheme: light dark; --bg:#fbfbfa; --fg:#1a1a19; --muted:#6b6b66;
70
+ --line:#e3e3df; --card:#fff; --hook:#0f6f4b; --hookbg:#e4f3ec;
71
+ --cmd:#1b4f8a; --cmdbg:#e5eefa; --prose:#8a5a12; --prosebg:#faf0dc; }
72
+ @media (prefers-color-scheme: dark) { :root { --bg:#121211; --fg:#ececeb;
73
+ --muted:#9a9a94; --line:#2c2c29; --card:#1b1b1a; --hook:#6fd3a8; --hookbg:#12332a;
74
+ --cmd:#8fbdf0; --cmdbg:#132840; --prose:#e3b464; --prosebg:#3a2c12; } }
75
+ :root[data-theme="dark"] { --bg:#121211; --fg:#ececeb; --muted:#9a9a94; --line:#2c2c29;
76
+ --card:#1b1b1a; --hook:#6fd3a8; --hookbg:#12332a; --cmd:#8fbdf0; --cmdbg:#132840;
77
+ --prose:#e3b464; --prosebg:#3a2c12; }
78
+ :root[data-theme="light"] { --bg:#fbfbfa; --fg:#1a1a19; --muted:#6b6b66; --line:#e3e3df;
79
+ --card:#fff; --hook:#0f6f4b; --hookbg:#e4f3ec; --cmd:#1b4f8a; --cmdbg:#e5eefa;
80
+ --prose:#8a5a12; --prosebg:#faf0dc; }
81
+ body { margin:0; padding:2.5rem 1.25rem 4rem; background:var(--bg); color:var(--fg);
82
+ font:16px/1.6 ui-sans-serif,-apple-system,"Segoe UI",Roboto,sans-serif; }
83
+ .wrap { max-width:70rem; margin:0 auto; }
84
+ h1 { font-size:1.75rem; margin:0 0 .35rem; letter-spacing:-.015em; }
85
+ .sub { color:var(--muted); margin:0 0 1.25rem; max-width:52rem; }
86
+ h2 { font-size:1rem; text-transform:uppercase; letter-spacing:.08em; color:var(--muted);
87
+ margin:2.5rem 0 .75rem; font-weight:600; }
88
+ .legend { display:flex; flex-wrap:wrap; gap:1rem; margin:0 0 1rem; padding:0; list-style:none; }
89
+ .legend li { color:var(--muted); font-size:.85rem; }
90
+ .scroll { overflow-x:auto; border:1px solid var(--line); border-radius:.6rem; background:var(--card); }
91
+ table { border-collapse:collapse; width:100%; min-width:44rem; }
92
+ th, td { text-align:left; padding:.7rem .85rem; border-bottom:1px solid var(--line); vertical-align:top; }
93
+ th { font-size:.78rem; text-transform:uppercase; letter-spacing:.06em; color:var(--muted); font-weight:600; }
94
+ tr:last-child td { border-bottom:0; }
95
+ td.name { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.88rem; white-space:nowrap; }
96
+ td.law { color:var(--muted); white-space:nowrap; font-variant-numeric:tabular-nums; }
97
+ td.what { min-width:22rem; }
98
+ .badge { display:inline-block; padding:.12rem .5rem; border-radius:1rem; font-size:.75rem;
99
+ font-weight:600; white-space:nowrap; }
100
+ .badge.hook { color:var(--hook); background:var(--hookbg); }
101
+ .badge.command { color:var(--cmd); background:var(--cmdbg); }
102
+ .badge.prose { color:var(--prose); background:var(--prosebg); }
103
+ .hookfile { display:block; margin-top:.25rem; font-family:ui-monospace,monospace;
104
+ font-size:.72rem; color:var(--muted); }
105
+ footer { margin-top:3rem; color:var(--muted); font-size:.85rem; max-width:52rem; }
106
+ code { font-family:ui-monospace,monospace; font-size:.9em; }
107
+ `;
108
+ /**
109
+ * Render the full catalog page. Pure — takes the resolved skill list and
110
+ * returns the complete HTML document.
111
+ */
112
+ export function renderSkillCatalogHtml(skills) {
113
+ const counts = { hook: 0, command: 0, prose: 0 };
114
+ for (const s of skills)
115
+ counts[s.enforcement]++;
116
+ const sections = [];
117
+ for (const tier of TIER_ORDER) {
118
+ const rows = skills.filter((s) => s.tier === tier);
119
+ if (rows.length === 0)
120
+ continue;
121
+ const body = rows
122
+ .map((s) => {
123
+ const badge = `<span class="badge ${s.enforcement}" title="${escapeHtml(ENFORCEMENT_TITLE[s.enforcement])}">` +
124
+ `${s.enforcement}</span>` +
125
+ (s.hookFile ? `<span class="hookfile">hooks/${escapeHtml(s.hookFile)}</span>` : "");
126
+ return (" <tr>" +
127
+ `<td class="name">${escapeHtml(s.name)}</td>` +
128
+ `<td class="law">${escapeHtml(s.law ?? "—")}</td>` +
129
+ `<td>${badge}</td>` +
130
+ `<td class="what">${escapeHtml(summarize(s.description))}</td>` +
131
+ "</tr>");
132
+ })
133
+ .join("\n");
134
+ sections.push(` <h2>${escapeHtml(TIER_LABEL[tier])} (${rows.length})</h2>\n` +
135
+ ' <div class="scroll">\n <table>\n' +
136
+ " <thead><tr><th>Skill</th><th>Law</th><th>Enforcement</th><th>What it does</th></tr></thead>\n" +
137
+ ` <tbody>\n${body}\n </tbody>\n` +
138
+ " </table>\n </div>");
139
+ }
140
+ return [
141
+ "<!doctype html>",
142
+ '<html lang="en">',
143
+ "<head>",
144
+ ' <meta charset="utf-8">',
145
+ ' <meta name="viewport" content="width=device-width,initial-scale=1">',
146
+ ` <title>Skill catalog — continuous-improvement (${skills.length} skills)</title>`,
147
+ " <!-- GENERATED by npm run build from skills/*.md frontmatter. Do not edit by hand. -->",
148
+ ` <style>${STYLE} </style>`,
149
+ "</head>",
150
+ "<body>",
151
+ ' <div class="wrap">',
152
+ " <h1>Skill catalog</h1>",
153
+ ` <p class="sub">${skills.length} bundled skills, generated from <code>skills/*.md</code> frontmatter. ` +
154
+ "The <strong>Enforcement</strong> column is the point of this page: it states what actually backs each skill, " +
155
+ "derived from the shipped file set rather than from the skill's own prose. " +
156
+ `Today ${counts.hook} are enforced by a hook, ${counts.command} by a slash command, and ${counts.prose} by model-side discipline alone.</p>`,
157
+ ' <ul class="legend">',
158
+ ' <li><span class="badge hook">hook</span> fires at the tool boundary; model cooperation not required</li>',
159
+ ' <li><span class="badge command">command</span> runs when you invoke it</li>',
160
+ ' <li><span class="badge prose">prose</span> model-side discipline only — nothing blocks</li>',
161
+ " </ul>",
162
+ sections.join("\n"),
163
+ ' <footer>A skill may only claim enforcement it ships. A <span class="badge prose">prose</span> skill that describes a runtime gate is a bug — that is what retired <code>safety-guard</code> on 2026-08-07. See <code>docs/plans/2026-08-07-six-rules-context-engineering.md</code>.</footer>',
164
+ " </div>",
165
+ "</body>",
166
+ "</html>",
167
+ "",
168
+ ].join("\n");
169
+ }
package/llms.txt CHANGED
@@ -6,6 +6,17 @@
6
6
 
7
7
  The persistent-memory and discipline layer for AI coding agents. It carries the corrections Claude has already received from one session into the next, grounds each edit in real facts before it lands, and learns from every session so its competence compounds over time — research, plan, execute one thing at a time, verify, reflect, iterate, learn — building behavioral instincts via the Mulahazah learning system, so the same correction never has to be given twice and each run starts smarter than the last. Orchestration tools run a task; this is the layer that makes the lessons survive the run.
8
8
 
9
+ Why these seven: every red flag an agent says ("this should work", "I'll remember", "next time I'll") is a wish standing in for a check. The Laws are one old sentence turned into checks an agent can run on itself: the wise one takes account of himself and works for what comes after; the weak one follows his impulse and merely wishes (Jami` at-Tirmidhi 2459). Before saying done: did I check, or did I hope? Sources and the mapping to each Law: docs/philosophy.md.
10
+
11
+ What the gate can and cannot do: hooks/gateguard.mjs denies the first Edit/Write/MultiEdit per file until a four-item fact list is presented and the printed clear command is run (honor system, 50 files per session); destructive Bash on a fixed blocklist is denied on every call with no clearance route; Bash file writes are not gated. Goal-drift warns by default (CLAUDE_GOAL_DRIFT_GATE=block to refuse), typecheck gate and recall briefing are opt-in.
12
+
13
+ Smarter models do not retire this product. Planning etiquette and "remember to verify" reminders merge into the model over time. The runtime gate, this-repo memory, and proof that a change worked do not. Keep goal-driven execution plus research / verify / learn guardrails; retire scaffolding when the native harness covers it (see skills/model-forward.md).
14
+
15
+ How you actually benefit:
16
+ 1. Beginner install (or `npx continuous-improvement install`) — gateguard fires on Edit/Write; no prompt prefix required.
17
+ 2. After a real session run `/seven-laws` — capture is silent; instincts form when you close the loop. `/recall` for "have I hit this before?". `/planning-with-files` writes `task_plan.md`.
18
+ 3. Expert mode for MCP tools, `/harvest`, `/distill`, and optional `CLAUDE_RECALL_BRIEFING=1`. Empty harvest/distill on day 1 means missing observation history, not a broken command.
19
+
9
20
  ## Install
10
21
 
11
22
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "continuous-improvement",
3
- "version": "3.22.1",
3
+ "version": "3.24.0",
4
4
  "description": "Claude Code that gets sharper every session: the persistent-memory and runtime-discipline layer built on the 7 Laws of AI Agent Discipline. It grounds every edit in real facts before it lands and, through the Mulahazah engine, turns each fix into a reusable instinct, so a lesson learned once is applied automatically next time with no re-teaching. Shipped as 28 bundled skills, instinct-aware hooks, an MCP toolset for recall and reflection, and a GitHub Action transcript linter that feeds real work history back into sharper instincts. Beginner: one /plugin install command. Expert: adds MCP tools and session hooks.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "continuous-improvement",
3
- "version": "3.22.1",
3
+ "version": "3.24.0",
4
4
  "mode": "beginner",
5
- "description": "Beginner mode: see what your agent learned, list its instincts, and request a session reflection. Bundles three grounding skills (gateguard, tdd-workflow, verification-loop) so research, memory, tests, and verification happen by default — every edit starts from facts, not guesses.",
5
+ "description": "Beginner mode: see what your agent learned, list its instincts, and request a session reflection. Bundles the ship fast path plus grounding skills (gateguard, tdd-workflow, verification-loop) so one-defect delivery, research, tests, and verification happen by default — every edit starts from facts, not guesses.",
6
6
  "tools": [
7
7
  {
8
8
  "name": "ci_status",
@@ -8,7 +8,7 @@
8
8
  {
9
9
  "name": "continuous-improvement",
10
10
  "description": "The persistent-memory and runtime-discipline layer for Claude Code. It remembers the corrections you already gave, grounds every edit in real facts before it lands, and — through the Mulahazah engine — turns each fix into a reusable instinct, so a lesson learned once is applied automatically next time with no re-teaching. Built on the 7 Laws of AI Agent Discipline (research, plan, verify, reflect, learn) and shipped as 28 bundled skills, instinct-aware hooks, an MCP toolset for recall and reflection, and a GitHub Action transcript linter that feeds real work history back into sharper instincts.",
11
- "version": "3.22.1",
11
+ "version": "3.24.0",
12
12
  "source": "./",
13
13
  "author": {
14
14
  "name": "naimkatiman"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "continuous-improvement",
3
- "version": "3.22.1",
3
+ "version": "3.24.0",
4
4
  "description": "The persistent-memory and runtime-discipline layer for Claude Code. It remembers the corrections you already gave, grounds every edit in real facts before it lands, and — through the Mulahazah engine — turns each fix into a reusable instinct, so a lesson learned once is applied automatically next time with no re-teaching. Built on the 7 Laws of AI Agent Discipline (research, plan, verify, reflect, learn) and shipped as 28 bundled skills, instinct-aware hooks, an MCP toolset for recall and reflection, and a GitHub Action transcript linter that feeds real work history back into sharper instincts.",
5
5
  "author": {
6
6
  "name": "naimkatiman",
@@ -36,8 +36,7 @@ the trade-off is fallback quality vs dedicated-skill quality.
36
36
  - `tdd-workflow` — RED/GREEN/REFACTOR + 80% coverage gate
37
37
  - `workspace-surface-audit` — environment + capability audit
38
38
  - Tier-1/Tier-2 enforcement skills (`gateguard`, `verification-loop`,
39
- `safety-guard`, `token-budget-advisor`,
40
- `strategic-compact`, `wild-risa-balance`)
39
+ `token-budget-advisor`, `strategic-compact`, `wild-risa-balance`)
41
40
 
42
41
  **Optional companions the orchestrator routes to (install separately if
43
42
  you want the dedicated skill instead of the inline fallback):**
@@ -16,12 +16,11 @@ import { homedir } from "node:os";
16
16
  import { basename, dirname, join, resolve } from "node:path";
17
17
  import { createInterface } from "node:readline";
18
18
  import { fileURLToPath } from "node:url";
19
- import { createHash } from "node:crypto";
20
19
  import { PACKAGE_NAME, VERSION, getToolDefinitions, isPluginMode, } from "../lib/plugin-metadata.mjs";
21
20
  import { formatDriftReport, parseGoalFromPlan, scoreObservations, } from "../lib/goal-state.mjs";
22
21
  import { buildIndex, formatRecallHits, parseSince, query as queryRecall, } from "../lib/recall-index.mjs";
23
22
  import { draftFromCandidate, draftFromWorkflowRun, extractTrajectories, findCandidates, formatCandidates, serializeDraft, workflowRunFromObservations, } from "../lib/skill-distill.mjs";
24
- import { MAX_CLEARED_FILES, canonicalizeFileKey, clearFiles, resolveInstinctsRoot, resolveSessionDir, } from "../lib/gateguard-state.mjs";
23
+ import { MAX_CLEARED_FILES, canonicalizeFileKey, clearFiles, hashProjectRoot, resolveInstinctsRoot, resolveProjectRoot, resolveSessionDir, } from "../lib/gateguard-state.mjs";
25
24
  function getHomeDir() {
26
25
  return process.env.HOME || process.env.USERPROFILE || homedir();
27
26
  }
@@ -93,14 +92,10 @@ const modeIndex = args.indexOf("--mode");
93
92
  const requestedMode = args[modeIndex + 1];
94
93
  const MODE = isPluginMode(requestedMode) ? requestedMode : "beginner";
95
94
  function getProjectHash() {
96
- try {
97
- const root = execSync("git rev-parse --show-toplevel 2>/dev/null", { encoding: "utf8" }).trim();
98
- const hash = createHash("sha256").update(root).digest("hex").slice(0, 12);
99
- return { root, hash, name: basename(root) };
100
- }
101
- catch {
95
+ const root = resolveProjectRoot();
96
+ if (root === "global")
102
97
  return { root: "global", hash: "global", name: "global" };
103
- }
98
+ return { root, hash: hashProjectRoot(root), name: basename(root) };
104
99
  }
105
100
  function readInstincts(projectHash) {
106
101
  const instincts = [];
@@ -16,10 +16,10 @@
16
16
  //
17
17
  // See docs/plans/2026-05-05-node-observer-rich-schema.md for the full design.
18
18
  import { execFileSync } from "node:child_process";
19
- import { createHash } from "node:crypto";
20
19
  import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
21
20
  import { homedir } from "node:os";
22
21
  import { basename, join } from "node:path";
22
+ import { canonicalizeProjectRoot, hashProjectRoot } from "../lib/gateguard-state.mjs";
23
23
  import { parseHookPayload, summariseInput, summariseOutput } from "../lib/observe-event.mjs";
24
24
  const ROTATION_LINE_THRESHOLD = 10_000;
25
25
  const ARCHIVE_RETENTION = 10;
@@ -40,8 +40,8 @@ function runObserver() {
40
40
  const payload = parseHookPayload(raw);
41
41
  if (!payload)
42
42
  return;
43
- const projectRoot = resolveProjectRoot();
44
- const projectHash = createHash("sha256").update(projectRoot).digest("hex").slice(0, 12);
43
+ const projectRoot = canonicalizeProjectRoot(resolveProjectRoot());
44
+ const projectHash = hashProjectRoot(projectRoot);
45
45
  const projectName = basename(projectRoot.replace(/\.git$/, ""));
46
46
  const instinctsDir = join(getHomeDir(), ".claude", "instincts");
47
47
  const projectDir = join(instinctsDir, projectHash);
@@ -19,6 +19,8 @@ Print this card and check yourself against each law.
19
19
  | 6 | **Iterate One Change** | Am I changing one thing at a time? | "And also..." |
20
20
  | 7 | **Learn From Every Session** | Did I capture this as an instinct? | "Next time I'll..." |
21
21
 
22
+ Read the seven as three moments around every act. **Before** (Laws 1, 2): set the terms. **During** (Laws 3, 6): watch yourself. **After** (Laws 4, 5, 7): settle the account and carry it forward. Every check is an audit you run on yourself; every red flag is you hoping instead. The sentence this comes from, and its sources: `docs/philosophy.md`.
23
+
22
24
  ## Operator Stakes
23
25
 
24
26
  The Laws above are the *how*. These five principles are the *why*: code ships from your account, the incident lands on your pager, the bill hits your budget. Each one pairs with the Law that prevents it from going wrong.
@@ -31,7 +33,7 @@ The Laws above are the *how*. These five principles are the *why*: code ships fr
31
33
  | 4 | **Problem framing** | Builds the websocket chat the ticket asked for | Finds out users wanted faster support replies, not chat | 1 |
32
34
  | 5 | **Constraints management** | Calls the $0.02/image model on every upload | Does the math, adds client-side validation + caching + cheaper triage model | 2 |
33
35
 
34
- Code is a liability, not an asset. Speed without these five turns into someone else's incident at 3am — except the someone is you.
36
+ Code is a liability, not an asset. Speed without these five turns into someone else's incident at 3am — except the someone is you. The other half of the why is not fear: the session ends and the context is gone, so the only work that survives is what you verified and wrote down for the one who comes after, whether that is tomorrow's session or the engineer who inherits the repo.
35
37
 
36
38
  ## Goal-Driven Execution maps onto the Laws
37
39
 
@@ -61,5 +63,6 @@ Before saying "Done", verify ALL:
61
63
  - [ ] I checked the **actual** result (not assumed)
62
64
  - [ ] Build passes
63
65
  - [ ] I can explain the change in one sentence
66
+ - [ ] For each item above I checked, not hoped
64
67
 
65
- If you're skipping a step, that's the step you need most.
68
+ If you're skipping a step, that's the step you need most. The step you skip is the one you are hoping through.
@@ -95,7 +95,7 @@ git branch -d <type>/<slug> # delete the merged feature branch (safe
95
95
  ## Pairs with
96
96
 
97
97
  - **`reconcile`** skill — the discipline this command runs.
98
- - **`gateguard`** / **`safety-guard`** runtime + destructive-op guardrails.
98
+ - **`gateguard`** the runtime gate for mutating tool calls and destructive shell.
99
99
  - **`recall`** — recall whether the same git op failed here before.
100
100
  - **`audit`** — the loop that often produces the fix `/reconcile` then ships.
101
101
  - **`/ship`** — the TDD-gated single-defect variant; `commit-commands:commit-push-pr` is the external-plugin equivalent of the commit → PR tail.
@@ -1,57 +1,13 @@
1
1
  ---
2
2
  name: ship
3
- description: "Single-defect fast path walk one bug from ground-truth audit through a TDD fix, full verification, a single-concern commit, and an open PR, then stop. Never auto-merges, never deploys. For multi-PR rollouts use /release-train instead."
3
+ description: "Compatibility entry point for the native ship skill. Passes one defect request through unchanged."
4
+ argument-hint: "[one-line defect description]"
4
5
  ---
5
6
 
6
7
  # /ship
7
8
 
8
- The one-defect fast path. `/release-train` is for stacked multi-PR rollouts and `/proceed-with-the-recommendation` walks an arbitrary recommendation list; `/ship` is the common case: fix one defect, open one PR, hand it back for review.
9
+ Invoke the native `ship` skill with this complete defect request:
9
10
 
10
- Pure routing over existing skills. It adds no new orchestration logic and it does NOT bypass branch protection, force-push, auto-merge, or deploy.
11
+ $ARGUMENTS
11
12
 
12
- ## Usage
13
-
14
- ```
15
- /ship <one-line description of the defect>
16
- ```
17
-
18
- If the description is ambiguous or names more than one concern, `/ship` halts and asks you to narrow it — one defect per run.
19
-
20
- ## Behavior
21
-
22
- In order, for the single defect:
23
-
24
- 1. **Ground truth** — `reconcile` (or its inline fallback): confirm the working tree is clean and on a feature branch cut from an up-to-date `origin/<base>`. If on a protected branch or a stale base, halt and ask.
25
- 2. **Reproduce (RED)** — `tdd-workflow`: write a failing test that reproduces the defect; watch it fail. Pre-test implementation code is deleted, not kept.
26
- 3. **Fix (GREEN)** — write the minimal change that makes the test pass; watch it pass. One concern only.
27
- 4. **Verify** — `verification-loop`: run the project's verify ladder (build, types, tests). Build-green is evidence of mechanism, not of the fix — confirm the defect itself no longer reproduces.
28
- 5. **Commit** — one commit, one concern, staged by explicit filename (never `git add -A`). Use a Windows-safe commit message: a single-line `-m` (repeat `-m` for paragraphs) or `git commit -F <tempfile>` — no multi-line here-docs/here-strings.
29
- 6. **Open PR** — `commit-commands:commit-push-pr` (or `gh pr create`): push the branch and open a single-concern PR that cites the plan or issue. **Stop here.** The merge is yours.
30
- 7. **Deploy receipt (advisory)** — after you merge, `deploy-receipt` verifies the deployed SHA matches the merge SHA. Advisory only; `/ship` does not deploy.
31
-
32
- ## Hard stops (halt and ask, never improvise)
33
-
34
- - Ambiguous or multi-concern defect description.
35
- - Working tree not clean, or branch is protected / cut from a stale base.
36
- - Any verification step fails with a non-obvious fix.
37
- - The fix would touch more than 15 non-generated files (that is no longer one concern — split it, or use `/release-train`).
38
- - Push would target a protected branch.
39
-
40
- ## Anti-patterns this command refuses
41
-
42
- - **Auto-merge.** Never merges the PR it opens, even when CI is green.
43
- - **Deploy.** Never runs a deploy; `deploy-receipt` only verifies after you merge.
44
- - **Bypass.** No `--admin`, `--force`, `--no-verify`.
45
- - **Bundled concerns.** Will not fold an unrelated fix into the same commit; logs it as a deferred follow-up instead.
46
-
47
- ## Composition
48
-
49
- Routes through, in order: `reconcile` → `tdd-workflow` → `verification-loop` → `commit-commands:commit-push-pr` → `deploy-receipt`. Each step falls back to its inline behavior when the preferred skill is not installed.
50
-
51
- ## Example
52
-
53
- ```
54
- /ship registration form accepts a negative deposit amount
55
- ```
56
-
57
- Reconciles git state, writes a failing test asserting deposits must be positive, implements the guard, runs the verify ladder, commits one concern with a single-line message, opens the PR, and stops for your review.
13
+ Follow that skill exactly. Do not reconstruct or duplicate its Git, worktree, TDD, return, cleanup, merge, or deploy rules here. If the native skill is unavailable, stop and tell the operator to update or reinstall `continuous-improvement`.
@@ -13,7 +13,7 @@ The 7 Laws define *what* discipline must be applied. `/superpowers` decides *whi
13
13
 
14
14
  | Source | Where it lives | Examples of what it routes to |
15
15
  |---|---|---|
16
- | `continuous-improvement` (this plugin) | bundled — always present | `gateguard` (Law 1), `tdd-workflow` (Law 3+4), `verification-loop` (Law 4), `wild-risa-balance` (Law 2), `safety-guard` (Law 3), `proceed-with-the-recommendation` (all 7), `ralph` (Law 6), `workspace-surface-audit` (Law 1) |
16
+ | `continuous-improvement` (this plugin) | bundled — always present | `gateguard` (Law 1), `tdd-workflow` (Law 3+4), `verification-loop` (Law 4), `wild-risa-balance` (Law 2), `proceed-with-the-recommendation` (all 7), `ralph` (Law 6), `workspace-surface-audit` (Law 1) |
17
17
  | `obra/superpowers` (Jesse Vincent) | vendored at `third-party/superpowers/`, pinned SHA `f2cbfbe` (v5.1.0) | `superpowers:brainstorming`, `:writing-plans`, `:executing-plans`, `:test-driven-development`, `:systematic-debugging`, `:requesting-code-review`, `:receiving-code-review`, `:verification-before-completion`, `:dispatching-parallel-agents`, `:using-git-worktrees`, `:finishing-a-development-branch`, `:subagent-driven-development`, `:writing-skills`, `:using-superpowers` |
18
18
  | `addyosmani/agent-skills` | vendored at `third-party/addy-agent-skills/`, pinned SHA `742dca5` (v1.0.0) | `spec-driven-development`, `source-driven-development`, `context-engineering`, `idea-refine`, `incremental-implementation`, `code-review-and-quality`, `code-simplification`, `security-and-hardening`, `debugging-and-error-recovery`, `performance-optimization`, `api-and-interface-design`, `frontend-ui-engineering`, `browser-testing-with-devtools`, `ci-cd-and-automation`, `deprecation-and-migration`, `documentation-and-adrs`, `git-workflow-and-versioning`, `planning-and-task-breakdown`, `shipping-and-launch` |
19
19
  | `ruflo-swarm` (ruvnet) | vendored at `third-party/ruflo-swarm/`, pinned SHA `addb5cd` (v0.2.0) | `swarm-init`, `monitor-stream`; `swarm_*` and `agent_*` MCP tools; `/swarm`, `/watch` |
@@ -29,9 +29,14 @@ with the text `probe`) **without presenting any research first**.
29
29
 
30
30
  - If the hook **blocks** the write with a fact-list reason — the runtime layer is
31
31
  wired. Record `gateguard: ✓`. Do not retry the write; the block is the pass.
32
- - If the write **goes through** with no pause — the hook did not load. Record
33
- `gateguard: (hooks/gateguard.mjs not wired see README Troubleshooting install)`.
34
- Delete the probe file if it was created.
32
+ - If the write **goes through** with no pause — either the hook did not load, or
33
+ `CI_GATEGUARD_EXCLUDE` is set to a fragment that matches the probe path (a
34
+ catch-all such as `/` or `.` matches every path and switches the file gate off;
35
+ the hook prints a one-line stderr notice when an exclusion fires). Run
36
+ `echo "$CI_GATEGUARD_EXCLUDE"` first. If it is empty, record
37
+ `gateguard: ✗ (hooks/gateguard.mjs not wired — see README → Troubleshooting install)`;
38
+ if it is set, record `gateguard: ✗ (excluded by CI_GATEGUARD_EXCLUDE=<value>; unset it or
39
+ narrow the fragment)`. Delete the probe file if it was created.
35
40
 
36
41
  ## Check 3 — observation capture recording
37
42
 
@@ -30,10 +30,10 @@
30
30
  * suite or a follow-up audit walks the table against this map.
31
31
  */
32
32
  import { execFileSync } from "node:child_process";
33
- import { createHash } from "node:crypto";
34
33
  import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
35
34
  import { homedir } from "node:os";
36
35
  import { join } from "node:path";
36
+ import { hashProjectRoot } from "../lib/gateguard-state.mjs";
37
37
  const OVERRIDES = {
38
38
  "tdd-workflow": {
39
39
  companion: "superpowers:test-driven-development",
@@ -125,10 +125,7 @@ function resolveProjectRoot() {
125
125
  return "global";
126
126
  }
127
127
  function telemetryPath(home) {
128
- const hash = createHash("sha256")
129
- .update(resolveProjectRoot())
130
- .digest("hex")
131
- .slice(0, 12);
128
+ const hash = hashProjectRoot(resolveProjectRoot());
132
129
  return join(home, ".claude", "instincts", hash, "companion-preference.jsonl");
133
130
  }
134
131
  /**
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Runtime PreToolUse config-guard hook.
4
+ *
5
+ * Stdin : JSON { tool_name, tool_input }
6
+ * Stdout : empty on allow / warn (warn prints to stderr); on block, the
7
+ * documented PreToolUse shape:
8
+ * { hookSpecificOutput: { hookEventName: "PreToolUse",
9
+ * permissionDecision: "deny", permissionDecisionReason } }
10
+ * Exit : 0 always (decision is in stdout; fail-open on any error).
11
+ *
12
+ * Guards the files that wire the guardrails: `.claude/settings*.json`,
13
+ * `.mcp.json`, `hooks.json`, `.claude/hooks/`, `.claude/plugins/`,
14
+ * `.claude-plugin/`, and the `claude plugin|mcp|config` CLI forms that edit
15
+ * them. Pure logic in ../lib/config-guard-gate.mjs.
16
+ *
17
+ * Mode via CI_CONFIG_GUARD: "warn" (default) | "block" | "off".
18
+ * warn : print a one-line notice to stderr; never blocks.
19
+ * block : emit the PreToolUse deny shape.
20
+ * off : no-op.
21
+ * One-call bypass: CI_CONFIG_GUARD_ALLOW=true allows the call and says so.
22
+ *
23
+ * Registered with a tool matcher (Bash|Edit|MultiEdit|Write|NotebookEdit) so
24
+ * read-only tools never spawn it. No network. No git. Fail-open.
25
+ */
26
+ import { readFileSync } from "node:fs";
27
+ import { classifyMutation, decide, parseMode } from "../lib/config-guard-gate.mjs";
28
+ function readStdinSync() {
29
+ try {
30
+ return readFileSync(0, "utf8");
31
+ }
32
+ catch {
33
+ return "";
34
+ }
35
+ }
36
+ function safeJsonParse(text) {
37
+ try {
38
+ return JSON.parse(text);
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ }
44
+ function buildReason(toolName, hit, mode) {
45
+ const what = hit.via === "claude-cli"
46
+ ? `\`${hit.target}\` edits the plugin / MCP / settings configuration`
47
+ : `${toolName} would modify ${hit.target} (matches "${hit.pattern}")`;
48
+ return [
49
+ `config-guard: ${what}, one of the files that wires the guardrails (settings, MCP config, hooks, installed plugins).`,
50
+ "If this is intended, rerun this one call with CI_CONFIG_GUARD_ALLOW=true, or set CI_CONFIG_GUARD=off for the session.",
51
+ mode === "block"
52
+ ? "You are seeing a deny because CI_CONFIG_GUARD=block; the default is warn."
53
+ : "This is a warning (CI_CONFIG_GUARD=warn, the default); set CI_CONFIG_GUARD=block to deny instead.",
54
+ ].join("\n");
55
+ }
56
+ function main() {
57
+ const mode = parseMode(process.env.CI_CONFIG_GUARD);
58
+ if (mode === "off")
59
+ return;
60
+ const payload = safeJsonParse(readStdinSync());
61
+ if (!payload || typeof payload !== "object")
62
+ return;
63
+ const obj = payload;
64
+ const toolName = typeof obj.tool_name === "string" ? obj.tool_name : "";
65
+ const toolInput = obj.tool_input && typeof obj.tool_input === "object" ? obj.tool_input : {};
66
+ const hit = classifyMutation(toolName, toolInput);
67
+ if (!hit)
68
+ return;
69
+ if (String(process.env.CI_CONFIG_GUARD_ALLOW ?? "").trim().toLowerCase() === "true") {
70
+ process.stderr.write(`[continuous-improvement] config-guard: CI_CONFIG_GUARD_ALLOW=true let ${toolName} touch ${hit.target} on this call.\n`);
71
+ return;
72
+ }
73
+ const decision = decide(mode, true, buildReason(toolName, hit, mode));
74
+ if (decision.action === "block") {
75
+ process.stdout.write(`${JSON.stringify({
76
+ hookSpecificOutput: {
77
+ hookEventName: "PreToolUse",
78
+ permissionDecision: "deny",
79
+ permissionDecisionReason: decision.reason,
80
+ },
81
+ })}\n`);
82
+ return;
83
+ }
84
+ if (decision.action === "warn") {
85
+ process.stderr.write(`[continuous-improvement] ${decision.reason.split("\n")[0]}\n`);
86
+ }
87
+ }
88
+ try {
89
+ main();
90
+ }
91
+ catch {
92
+ // fail-open: never block a session on a hook error
93
+ }
94
+ process.exit(0);