continuous-improvement 3.15.0 → 3.17.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 (32) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +20 -0
  3. package/README.md +5 -4
  4. package/bin/check-skill-count-prose.mjs +168 -0
  5. package/bin/install.mjs +46 -1
  6. package/bin/lint-transcript.mjs +15 -3
  7. package/bin/mcp-server.mjs +1 -0
  8. package/commands/intent-driven-development.md +36 -0
  9. package/commands/roast.md +34 -0
  10. package/hooks/workflow-distill.mjs +145 -0
  11. package/lib/plugin-metadata.mjs +8 -3
  12. package/lib/version-check.mjs +115 -0
  13. package/llms.txt +1 -1
  14. package/package.json +4 -3
  15. package/plugins/beginner.json +1 -1
  16. package/plugins/continuous-improvement/.claude-plugin/marketplace.json +2 -2
  17. package/plugins/continuous-improvement/.claude-plugin/plugin.json +2 -2
  18. package/plugins/continuous-improvement/bin/mcp-server.mjs +1 -0
  19. package/plugins/continuous-improvement/commands/intent-driven-development.md +36 -0
  20. package/plugins/continuous-improvement/commands/roast.md +34 -0
  21. package/plugins/continuous-improvement/hooks/hooks.json +6 -1
  22. package/plugins/continuous-improvement/hooks/workflow-distill.mjs +145 -0
  23. package/plugins/continuous-improvement/lib/plugin-metadata.mjs +8 -3
  24. package/plugins/continuous-improvement/skills/README.md +2 -0
  25. package/plugins/continuous-improvement/skills/intent-driven-development/SKILL.md +161 -0
  26. package/plugins/continuous-improvement/skills/roast/SKILL.md +108 -0
  27. package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +12 -32
  28. package/plugins/expert.json +1 -1
  29. package/skills/README.md +1 -1
  30. package/skills/intent-driven-development.md +161 -0
  31. package/skills/roast.md +108 -0
  32. package/skills/strategic-compact.md +12 -32
@@ -7,8 +7,8 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "continuous-improvement",
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 25 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.15.0",
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 27 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.17.0",
12
12
  "source": "./plugins/continuous-improvement",
13
13
  "author": {
14
14
  "name": "naimkatiman"
package/CHANGELOG.md CHANGED
@@ -4,6 +4,26 @@ All notable changes to this skill are documented here.
4
4
 
5
5
  ---
6
6
 
7
+ ## [3.17.0] — 2026-06-28
8
+
9
+ ### Added
10
+
11
+ - **`/intent-driven-development`**: turn an ambiguous or high-impact change into verifiable acceptance criteria before you build. Converts a fuzzy request into observable `AC-NNN` criteria with named verification methods and a `[revised]` protocol that forbids silently dropping a criterion mid-build, so "done" is falsifiable and the agreed plan is held sacred (Law 2). Tier 2 (expert install). Brings the bundle to 27 skills. (#258)
12
+
13
+ ## [3.16.0] — 2026-06-27
14
+
15
+ ### Added
16
+
17
+ - **`/roast` — a 5-persona adversarial idea council that pressure-tests a plan before any code is written** — routes a proposed idea or plan through five distinct critic personas (each attacking a different failure axis) and reconciles their objections into a go / revise / kill verdict. Catches misalignment at Law 1 (Research) before it lands in the diff. Brings the bundle to 26 skills. (#255, #256)
18
+ - **npm-install users get nudged when a newer version is published** — the installer compares the running version against the registry `latest` and surfaces an upgrade hint instead of silently running stale. (#252)
19
+ - **Hook nudge to distill a verified Workflow run into a reusable instinct** — a completed multi-agent Workflow's verified trajectory no longer evaporates with the session; the agent is prompted to capture it as a draft instinct. (#251)
20
+ - **`lint-transcript` GitHub Action IO + fleet docs** — the transcript linter ships defined Action inputs/outputs for CI wiring, with fleet-usage documentation. (#250)
21
+ - **Skill use-case decision guide** — a when-to-reach-for-each-skill map so the right skill is picked without scanning all of them. (#254)
22
+
23
+ ### Changed
24
+
25
+ - **`skill-count` prose is now gated against the actual bundle** — the verify suite fails if any doc claims a skill count that disagrees with the shipped skill set; synced all prose to 26 after `/roast`. (#256)
26
+
7
27
  ## [3.15.0] — 2026-06-21
8
28
 
9
29
  ### Added
package/README.md CHANGED
@@ -82,7 +82,7 @@ You have used Claude Code (or any agentic coding tool) long enough to recognize
82
82
 
83
83
  | # | Failure mode | What you see | Which Law fires | What enforces it |
84
84
  |---|---|---|---|---|
85
- | 1 | **Misalignment** | The agent doesn't do what you want — invents requirements, reinvents helpers that already exist | Law 1 (Research) | [`grill-me`](skills/grill-me.md), [`grill-with-docs`](skills/grill-with-docs.md), [`gateguard`](skills/gateguard.md), [`workspace-surface-audit`](skills/workspace-surface-audit.md) |
85
+ | 1 | **Misalignment** | The agent doesn't do what you want — invents requirements, reinvents helpers that already exist, or builds the wrong thing before anyone challenged the idea | Law 1 (Research) | [`roast`](skills/roast.md), [`grill-me`](skills/grill-me.md), [`grill-with-docs`](skills/grill-with-docs.md), [`gateguard`](skills/gateguard.md), [`workspace-surface-audit`](skills/workspace-surface-audit.md) |
86
86
  | 2 | **No shared language** | The agent uses 20 words where 1 would do; jargon decoded fresh every session; variable names drift from domain terms | Law 2 (Plan), Law 7 (Learn) | [`grill-with-docs`](skills/grill-with-docs.md) (writes & maintains `CONTEXT.md`), [`token-budget-advisor`](skills/token-budget-advisor.md), [`strategic-compact`](skills/strategic-compact.md) |
87
87
  | 3 | **No feedback loop** | The code doesn't work — agent claims "done" without running build, tests, or healthcheck | Law 4 (Verify) | [`tdd-workflow`](skills/tdd-workflow.md), [`verification-loop`](skills/verification-loop.md), [`deploy-receipt`](skills/deploy-receipt.md) |
88
88
  | 4 | **Design rot** | Ball-of-mud accelerates — agent bundles three concerns into one PR, stacks untested changes, ignores prior architectural decisions | Law 2 (Plan), Law 3 (One Thing) | [`superpowers:writing-plans`](https://github.com/obra/superpowers/blob/main/skills/writing-plans/SKILL.md), [`safety-guard`](skills/safety-guard.md), [`worktree-safety`](skills/worktree-safety.md), [`wild-risa-balance`](skills/wild-risa-balance.md) |
@@ -149,7 +149,7 @@ npx continuous-improvement install --pack react # optional: react | python | g
149
149
  ```
150
150
 
151
151
  Verify: run `/dashboard` in Claude Code — you should see instinct health and observation count.
152
- Update later with `/plugin marketplace update continuous-improvement` or by re-running the npx command.
152
+ Update later with `/plugin marketplace update continuous-improvement` or by re-running the npx command. When you run the npx installer, it makes one throttled, fail-open read of the public npm registry and prints a one-line notice if a newer version is published (no telemetry — nothing about you is sent). Silence it with `CLAUDE_CI_UPDATE_CHECK=off`.
153
153
 
154
154
  ### Troubleshooting install
155
155
 
@@ -172,6 +172,7 @@ The framework has documented operator-level modes that change hook behavior with
172
172
  | `CLAUDE_THREE_SECTION_CLOSE_DISABLED=1` | `three-section-close.mjs` short-circuits before any enforcement or telemetry. Use when end-of-turn reflection should run as internal thinking rather than visible "What has been done / What is next / Recommendation" sections. Public default unchanged — the rule still fires for everyone else. | bash/zsh: `export CLAUDE_THREE_SECTION_CLOSE_DISABLED=1` in `~/.bashrc` / `~/.zshrc`. PowerShell: `$env:CLAUDE_THREE_SECTION_CLOSE_DISABLED=1` (session) or `[Environment]::SetEnvironmentVariable('CLAUDE_THREE_SECTION_CLOSE_DISABLED','1','User')` (persistent). |
173
173
  | `CLAUDE_GOAL_DRIFT_GATE` | `goal-drift-stop.mjs` (a `Stop` hook) scores each turn's activity against the `## Goal` in `task_plan.md` and acts on drift. `warn` (default) prints a one-line stderr notice and never blocks; `block` re-prompts a substantive wrap-up that has drifted off-goal so the goal gates the close; `off` disables it. Reads the same observation feed as Mulahazah; fails open on any error. | bash/zsh: `export CLAUDE_GOAL_DRIFT_GATE=block` in `~/.bashrc` / `~/.zshrc`. PowerShell: `$env:CLAUDE_GOAL_DRIFT_GATE='block'` (session) or `[Environment]::SetEnvironmentVariable('CLAUDE_GOAL_DRIFT_GATE','block','User')` (persistent). |
174
174
  | `CLAUDE_RECALL_BRIEFING=1` | `hooks/recall-briefing.mjs` (a UserPromptSubmit hook) makes episodic memory proactive: on the first substantive prompt of a session it searches this project's past observations (BM25) and injects a one-time `<system-reminder>` with the most relevant prior activity, so the agent reuses a past fix instead of re-deriving it. Opt-in and default off; it is an amplifier, never a gate — it cannot block a prompt and fails open. The `ci_recall` MCP tool stays available for explicit, deeper searches. | bash/zsh: `export CLAUDE_RECALL_BRIEFING=1` in `~/.bashrc` / `~/.zshrc`. PowerShell: `$env:CLAUDE_RECALL_BRIEFING=1` (session) or `[Environment]::SetEnvironmentVariable('CLAUDE_RECALL_BRIEFING','1','User')` (persistent). |
175
+ | `CLAUDE_WORKFLOW_DISTILL_NUDGE=on` | `hooks/workflow-distill.mjs` (a `Stop` hook) closes the orchestration-to-memory loop: when a native Workflow run's output then passed a verify in the same session, it prints a one-line stderr nudge to run the `ci_distill_from_workflow` MCP tool, so an expensive multi-agent run leaves a durable Mulahazah draft instinct instead of evaporating. `on` enables it; default (unset or any other value) is off. Opt-in amplifier, never a gate — it cannot block the Stop, dedupes per run, and fails open. | bash/zsh: `export CLAUDE_WORKFLOW_DISTILL_NUDGE=on` in `~/.bashrc` / `~/.zshrc`. PowerShell: `$env:CLAUDE_WORKFLOW_DISTILL_NUDGE='on'` (session) or `[Environment]::SetEnvironmentVariable('CLAUDE_WORKFLOW_DISTILL_NUDGE','on','User')` (persistent). |
175
176
 
176
177
  ### Works with other agents
177
178
 
@@ -260,7 +261,7 @@ All 18 ship in the marketplace bundle. The Beginner install gets all of them —
260
261
 
261
262
  ## Skills
262
263
 
263
- The plugin ships **25 skills** — 1 core + 1 featured + 6 tier-1 + 14 tier-2 + 3 always-bundled. Beginner install gets tier-1, featured, and the always-bundled companion; Expert adds tier-2, the MCP server, and observation hooks. Full catalog with per-skill descriptions, Law tagging, and drop-in single-file install: [docs/skills.md](docs/skills.md). Adding a 26th skill: [CONTRIBUTING.md § Evolution — adding a new skill](CONTRIBUTING.md#evolution--adding-a-new-skill).
264
+ The plugin ships **27 skills** — 1 core + 1 featured + 6 tier-1 + 16 tier-2 + 3 always-bundled. Beginner install gets tier-1, featured, and the always-bundled companion; Expert adds tier-2, the MCP server, and observation hooks. Full catalog with per-skill descriptions, Law tagging, and drop-in single-file install: [docs/skills.md](docs/skills.md). Adding a 28th skill: [CONTRIBUTING.md § Evolution — adding a new skill](CONTRIBUTING.md#evolution--adding-a-new-skill).
264
265
 
265
266
  ---
266
267
 
@@ -319,7 +320,7 @@ Authored end-to-end with `/superpowers` and `/proceed-with-the-recommendation`:
319
320
 
320
321
  - [QUICKSTART.md](QUICKSTART.md) — 2-minute setup
321
322
  - [SKILL.md](SKILL.md) — full 7 Laws spec
322
- - [docs/skills.md](docs/skills.md) — full 26-skill catalog
323
+ - [docs/skills.md](docs/skills.md) — full 27-skill catalog
323
324
  - [examples/](examples/) — bug fix, feature build, refactor walkthroughs
324
325
  - [templates/insights-claude-md.md](templates/insights-claude-md.md) — paste-in CLAUDE.md blocks for verification discipline, environment notes, think-before-acting, and git/deploy workflow (sourced from the 28-day usage report)
325
326
  - [CONTRIBUTING.md](CONTRIBUTING.md) — architecture, repo internals, adding a new skill
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Skill Count Prose Check
4
+ *
5
+ * Sibling to `verify:skill-count`. That lint gates the literal phrase
6
+ * "N bundled skills" in the 5 generator-owned manifest surfaces. This lint
7
+ * gates the *human-facing* prose — the phrasings the marketing/docs copy
8
+ * actually uses, which no other invariant checks and which therefore rot
9
+ * silently every time a skill is added without a full prose cascade.
10
+ *
11
+ * Origin: PR #255 (`/roast`, the 26th skill) bumped the gated "N bundled
12
+ * skills" manifests but left README.md / docs/skills.md / docs/skill-use-cases.md
13
+ * / CONTRIBUTING.md / docs/using-this-plugin.md at "25 skills / 14 tier-2".
14
+ * verify:all stayed green because nothing checked those surfaces.
15
+ * `reports/daily-improvement.md` logs three prior rounds of the same drift.
16
+ *
17
+ * Single source of truth: the skill set on disk. The total and the
18
+ * core/featured/tier-1/tier-2/companion breakdown are *derived* from
19
+ * `skills/*.md` + the root `SKILL.md` frontmatter via the same primitives the
20
+ * tier lint uses (`discoverSkillSources`, `parseSkillFrontmatter`,
21
+ * `normalizeTier`). Nothing is hardcoded — add or retire a skill and this lint
22
+ * recomputes the expected numbers, then names every doc that disagrees.
23
+ *
24
+ * Checked surfaces (file → which derived claims it must contain):
25
+ * - README.md breakdown, total-skills, next-ordinal
26
+ * - docs/skills.md breakdown, total-skills, total-catalog, next-ordinal
27
+ * - docs/skill-use-cases.md breakdown, total-skills
28
+ * - CONTRIBUTING.md total-skills
29
+ * - docs/using-this-plugin.md total-catalog
30
+ *
31
+ * Usage:
32
+ * node bin/check-skill-count-prose.mjs # Check the current repo
33
+ * node bin/check-skill-count-prose.mjs <repo-root> # Check a specific repo root
34
+ *
35
+ * Exit codes:
36
+ * 0 — every checked surface states the bundle-derived count
37
+ * 1 — at least one surface states a stale count, or a surface file is missing
38
+ */
39
+ import { readFileSync } from "node:fs";
40
+ import { join } from "node:path";
41
+ import { argv, cwd, exit } from "node:process";
42
+ import { normalizeTier, parseSkillFrontmatter } from "../lib/skill-tiers.mjs";
43
+ import { discoverSkillSources } from "./check-skill-tiers.mjs";
44
+ /** Derive the total + per-tier breakdown from `skills/` + root SKILL.md frontmatter. */
45
+ export function deriveCounts(repoRoot) {
46
+ const sources = discoverSkillSources(repoRoot);
47
+ const tally = { core: 0, featured: 0, tier1: 0, tier2: 0, companion: 0, unknown: 0 };
48
+ for (const src of sources) {
49
+ const front = parseSkillFrontmatter(readFileSync(src.path, "utf8"));
50
+ switch (normalizeTier(front.tier)) {
51
+ case "core":
52
+ tally.core++;
53
+ break;
54
+ case "featured":
55
+ tally.featured++;
56
+ break;
57
+ case "1":
58
+ tally.tier1++;
59
+ break;
60
+ case "2":
61
+ tally.tier2++;
62
+ break;
63
+ case "companion":
64
+ tally.companion++;
65
+ break;
66
+ default:
67
+ tally.unknown++;
68
+ break;
69
+ }
70
+ }
71
+ const total = sources.length;
72
+ return { ...tally, total, next: total + 1 };
73
+ }
74
+ /** English ordinal: 1→1st, 2→2nd, 3→3rd, 11→11th, 21→21st, 27→27th. */
75
+ export function ordinal(n) {
76
+ const mod100 = n % 100;
77
+ if (mod100 >= 11 && mod100 <= 13)
78
+ return `${n}th`;
79
+ switch (n % 10) {
80
+ case 1:
81
+ return `${n}st`;
82
+ case 2:
83
+ return `${n}nd`;
84
+ case 3:
85
+ return `${n}rd`;
86
+ default:
87
+ return `${n}th`;
88
+ }
89
+ }
90
+ /** The exact substring a surface must contain for the given check kind. */
91
+ export function expectedFor(check, c) {
92
+ switch (check) {
93
+ case "breakdown":
94
+ return `${c.core} core + ${c.featured} featured + ${c.tier1} tier-1 + ${c.tier2} tier-2 + ${c.companion} always-bundled`;
95
+ case "total-skills":
96
+ return `${c.total} skills`;
97
+ case "total-catalog":
98
+ return `${c.total}-skill catalog`;
99
+ case "next-ordinal":
100
+ return `${ordinal(c.next)} skill`;
101
+ }
102
+ }
103
+ export const PROSE_SURFACES = [
104
+ { file: "README.md", checks: ["breakdown", "total-skills", "next-ordinal"] },
105
+ {
106
+ file: "docs/skills.md",
107
+ checks: ["breakdown", "total-skills", "total-catalog", "next-ordinal"],
108
+ },
109
+ { file: "docs/skill-use-cases.md", checks: ["breakdown", "total-skills"] },
110
+ { file: "CONTRIBUTING.md", checks: ["total-skills"] },
111
+ { file: "docs/using-this-plugin.md", checks: ["total-catalog"] },
112
+ ];
113
+ /**
114
+ * Assert every surface contains every derived claim it owns. `counts` defaults
115
+ * to the value derived from `repoRoot`; pass it explicitly to test the
116
+ * surface-matching logic in isolation.
117
+ */
118
+ export function checkProseSurfaces(repoRoot, counts, surfaces = PROSE_SURFACES) {
119
+ const c = counts ?? deriveCounts(repoRoot);
120
+ const failures = [];
121
+ for (const surface of surfaces) {
122
+ let content;
123
+ try {
124
+ content = readFileSync(join(repoRoot, surface.file), "utf8");
125
+ }
126
+ catch {
127
+ content = null;
128
+ }
129
+ for (const check of surface.checks) {
130
+ const expected = expectedFor(check, c);
131
+ if (content === null) {
132
+ failures.push({ file: surface.file, check, expected, reason: "target-missing" });
133
+ continue;
134
+ }
135
+ if (!content.includes(expected)) {
136
+ failures.push({ file: surface.file, check, expected, reason: "stale" });
137
+ }
138
+ }
139
+ }
140
+ return failures;
141
+ }
142
+ function main() {
143
+ const repoRoot = argv[2] ?? cwd();
144
+ const counts = deriveCounts(repoRoot);
145
+ const failures = checkProseSurfaces(repoRoot, counts);
146
+ if (failures.length === 0) {
147
+ console.log(`OK skill-count-prose: all ${PROSE_SURFACES.length} doc surface(s) state the derived count (total=${counts.total}: ${expectedFor("breakdown", counts)}).`);
148
+ exit(0);
149
+ }
150
+ console.error(`FAIL skill-count-prose: ${failures.length} doc prose claim(s) do not match the bundle-derived count of ${counts.total}.`);
151
+ console.error(`Source of truth: skills/ frontmatter → ${expectedFor("breakdown", counts)} = ${counts.total} skills; next skill is the ${ordinal(counts.next)}.`);
152
+ console.error("");
153
+ for (const f of failures) {
154
+ if (f.reason === "target-missing") {
155
+ console.error(` ${f.file} — file not found (expected to contain "${f.expected}")`);
156
+ }
157
+ else {
158
+ console.error(` ${f.file} — missing "${f.expected}" [${f.check}]`);
159
+ }
160
+ }
161
+ console.error("");
162
+ console.error("Fix: bump the prose in the named file(s) to the derived count. When a skill is genuinely added or retired, this lint enumerates every human-facing surface that needs the same change.");
163
+ exit(1);
164
+ }
165
+ const invokedDirectly = argv[1] !== undefined && import.meta.url.endsWith(argv[1].replace(/\\/g, "/"));
166
+ if (invokedDirectly || argv[1]?.endsWith("check-skill-count-prose.mjs")) {
167
+ main();
168
+ }
package/bin/install.mjs CHANGED
@@ -15,8 +15,9 @@ import { homedir } from "node:os";
15
15
  import { dirname, join } from "node:path";
16
16
  import { fileURLToPath } from "node:url";
17
17
  import { createHash } from "node:crypto";
18
- import { getToolNames } from "../lib/plugin-metadata.mjs";
18
+ import { PACKAGE_NAME, VERSION, getToolNames } from "../lib/plugin-metadata.mjs";
19
19
  import { TARGET_IDS, planTargetWrites, resolveTargets } from "../lib/install-targets.mjs";
20
+ import { evaluateUpdateCheck, fetchLatestNpmVersion, isThrottled, pendingNotice, } from "../lib/version-check.mjs";
20
21
  const __filename = fileURLToPath(import.meta.url);
21
22
  const __dirname = dirname(__filename);
22
23
  const SKILL_SOURCE = join(__dirname, "..", "SKILL.md");
@@ -694,3 +695,47 @@ Next steps:
694
695
  ${INSTALL_MODE === "expert" ? `\nMCP tools available (${getToolNames("expert").length}): ${getToolNames("expert").join(", ")}` : ""}
695
696
  Available instinct packs: npx continuous-improvement install --pack react|python|go|meta
696
697
  `);
698
+ // Update-available nudge for the npm/CLI install path (the marketplace path is
699
+ // covered by Claude Code's native plugin auto-update). Reads the public npm
700
+ // registry only — no telemetry. Throttled, default-on, off via
701
+ // CLAUDE_CI_UPDATE_CHECK=off. Fully fail-open: it can never change the
702
+ // installer's outcome. See docs/plans/2026-06-25-version-check-nudge.md.
703
+ async function maybeNotifyUpdate() {
704
+ if ((process.env.CLAUDE_CI_UPDATE_CHECK ?? "on").trim().toLowerCase() === "off")
705
+ return;
706
+ const cacheFile = join(getHomeDir(), ".claude", "instincts", "global", "update-check.json");
707
+ const now = Date.now();
708
+ let cache = null;
709
+ try {
710
+ if (existsSync(cacheFile))
711
+ cache = JSON.parse(readFileSync(cacheFile, "utf8"));
712
+ }
713
+ catch {
714
+ cache = null;
715
+ }
716
+ if (isThrottled(cache, now)) {
717
+ const notice = pendingNotice(cache, VERSION);
718
+ if (notice)
719
+ console.log(`\n${notice}`);
720
+ return;
721
+ }
722
+ const remote = await fetchLatestNpmVersion(PACKAGE_NAME);
723
+ const decision = evaluateUpdateCheck({ local: VERSION, remote, now });
724
+ if (decision.notice)
725
+ console.log(`\n${decision.notice}`);
726
+ if (decision.nextCache) {
727
+ try {
728
+ mkdirSync(dirname(cacheFile), { recursive: true });
729
+ writeFileSync(cacheFile, JSON.stringify(decision.nextCache) + "\n", "utf8");
730
+ }
731
+ catch {
732
+ // cache persistence is best-effort; never throw
733
+ }
734
+ }
735
+ }
736
+ try {
737
+ await maybeNotifyUpdate();
738
+ }
739
+ catch {
740
+ // a version check must never change the installer's outcome
741
+ }
@@ -160,6 +160,12 @@ function formatReport(result) {
160
160
  return lines.join("\n");
161
161
  }
162
162
  const args = process.argv.slice(2);
163
+ function actionInput(name) {
164
+ return (process.env[`INPUT_${name.toUpperCase()}`] ?? "").trim();
165
+ }
166
+ function actionInputBoolean(name) {
167
+ return /^(1|true|yes)$/i.test(actionInput(name));
168
+ }
163
169
  if (args.includes("--help") || args.includes("-h")) {
164
170
  console.log(`
165
171
  Agent Transcript Linter — The 7 Laws of AI Agent Discipline
@@ -176,7 +182,7 @@ Options:
176
182
  `);
177
183
  process.exit(0);
178
184
  }
179
- const isStrict = args.includes("--strict");
185
+ const isStrict = args.includes("--strict") || actionInputBoolean("strict");
180
186
  const isJson = args.includes("--json");
181
187
  const isStdin = args.includes("--stdin");
182
188
  async function main() {
@@ -190,7 +196,9 @@ async function main() {
190
196
  }
191
197
  }
192
198
  else {
193
- const filePath = args.find((arg) => !arg.startsWith("--"));
199
+ const filePath = args.find((arg) => !arg.startsWith("--"))
200
+ || actionInput("transcript-path")
201
+ || actionInput("observations-path");
194
202
  if (!filePath) {
195
203
  console.error("Error: provide a file path or use --stdin");
196
204
  process.exit(1);
@@ -213,16 +221,20 @@ async function main() {
213
221
  process.exit(0);
214
222
  }
215
223
  const result = analyzeTranscript(events, parseFailures);
224
+ const report = formatReport(result);
216
225
  if (isJson) {
217
226
  console.log(JSON.stringify(result, null, 2));
218
227
  }
219
228
  else {
220
- console.log(formatReport(result));
229
+ console.log(report);
221
230
  }
222
231
  if (process.env.GITHUB_OUTPUT) {
223
232
  const outputLines = [
224
233
  `violations=${result.violations.length}`,
225
234
  `score=${result.score}`,
235
+ `report<<CI_REPORT_EOF`,
236
+ report,
237
+ "CI_REPORT_EOF",
226
238
  ];
227
239
  const { appendFileSync } = await import("node:fs");
228
240
  for (const line of outputLines) {
@@ -219,6 +219,7 @@ function readDistillObservations(projectHash) {
219
219
  tool: getString(observation.tool),
220
220
  input_summary: getString(observation.input_summary),
221
221
  output_summary: getString(observation.output_summary),
222
+ event: getString(observation.event),
222
223
  }));
223
224
  }
224
225
  function detectLevel(projectHash) {
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: intent-driven-development
3
+ description: "Turn an ambiguous or high-impact change into scoped, verifiable acceptance criteria (observable AC-NNN, explicit scope, named verification methods, and a [revised] protocol that forbids silently dropping a criterion) before or alongside implementation. Enforces Law 2 (Plan Is Sacred)."
4
+ argument-hint: "[the change to scope into acceptance criteria]"
5
+ ---
6
+
7
+ # /intent-driven-development
8
+
9
+ Convert an ambiguous or high-impact request into observable acceptance criteria before you build, so "done" is a fact two people would agree on and the agreed plan is held sacred (Law 2). Produce useful criteria without ceremony: inspect context first, expose only genuine ambiguity, choose verification that fits the risk.
10
+
11
+ ## Trigger phrases
12
+
13
+ - `/intent-driven-development`
14
+ - `/intent-driven-development <the change>`
15
+ - "define acceptance criteria"
16
+ - "scope this change" / "make this testable"
17
+ - "de-risk this before we build it"
18
+ - "prepare implementation requirements for another agent"
19
+
20
+ Do not trigger for trivial edits, one-line fixes, active debugging, code review, or requests whose acceptance conditions are already clear.
21
+
22
+ ## What happens
23
+
24
+ 1. **Inspect and scope.** Read the repo, docs, schemas, and tests for technical facts before asking. Capture product or business constraints only from the user or a product artifact, never inferred from code.
25
+ 2. **Choose depth.** Quick Capture (3-7 criteria, low or moderate risk) or Full Acceptance Brief (security, data, migration, cross-system, or handoff).
26
+ 3. **Write criteria.** Each `AC-NNN` names a scenario, a trigger, an expected observable result, a prohibited side effect when meaningful, a verification method, and a priority. No vague words without defined evidence.
27
+ 4. **Proceed or hand off.** Record the criteria and continue for a clear request; present blockers and wait when a change is risky. If a criterion cannot be met mid-build, mark it `[revised]`, increment the revision, and re-present only the changed criteria.
28
+
29
+ ## Skill file
30
+
31
+ Full behavior is defined in [`skills/intent-driven-development.md`](../skills/intent-driven-development.md).
32
+
33
+ ## Pairs with
34
+
35
+ - `/grill-me`: grill-me clarifies a fuzzy input; this skill turns the agreed intent into verifiable criteria.
36
+ - `/roast`: roast validates the idea, then scope the survivor into acceptance criteria.
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: roast
3
+ description: "Convene a 5-persona adversarial council (Contrarian, Expansionist, Logician, Researcher, Buyer) to pressure-test an idea, then deliver one GO / RESHAPE / KILL verdict plus the cheapest 48-hour test to de-risk it. Enforces Law 1 (Research Before Executing)."
4
+ argument-hint: "[the idea to roast]"
5
+ ---
6
+
7
+ # /roast
8
+
9
+ Pressure-test an idea before you build it. Convene a council of five independent persona agents who attack the idea from every angle, then act as the Judge and return one decisive verdict — so Law 1 (Research Before Executing) is satisfied on the *idea* itself, not just the plan.
10
+
11
+ ## Trigger phrases
12
+
13
+ - `/roast`
14
+ - `/roast <the idea>`
15
+ - "roast this idea"
16
+ - "convene the council"
17
+ - "pressure-test this" / "stress-test this idea"
18
+ - "validate this business idea"
19
+ - "give me a brutal second opinion before I build this"
20
+
21
+ ## What happens
22
+
23
+ 1. **Brief.** Read the idea from the argument (if given) and ask up to 3-4 clarifying questions in one batch — the idea, the buyer + money model, your edge, your constraints. Skip the questions if the user says "just run it."
24
+ 2. **Council (parallel).** Spin up all five personas in parallel, each pasted the same brief: Contrarian (assume it fails), Expansionist (the 10x case), Logician (first-principles, no web), Researcher (web evidence + competitors), Buyer (role-play the target customer). Each returns a stance, 3-5 sharp points, the one thing you must hear, and a 1-10 score.
25
+ 3. **Verdict.** Act as the Judge: resolve the council's tension, fold in the economics lens, and return one `GO / RESHAPE / KILL` call with the biggest risk, biggest upside, money read, and — most importantly — the cheapest 48-hour test to validate the riskiest assumption before building anything.
26
+
27
+ ## Skill file
28
+
29
+ Full behavior is defined in [`skills/roast.md`](../skills/roast.md).
30
+
31
+ ## Pairs with
32
+
33
+ - `/grill-me` — roast validates the idea; grill-me then hardens the plan.
34
+ - `/proceed-with-the-recommendation` — walk the verdict's next steps under the 7 Laws.
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ // workflow-distill.mts — Stop hook (opt-in, default off) that nudges the operator
3
+ // to persist a verified native Workflow run as a Mulahazah draft instinct via the
4
+ // ci_distill_from_workflow MCP tool. This is the one integration a per-turn
5
+ // orchestration primitive cannot do for itself: make the lesson of an expensive
6
+ // multi-agent run survive the run instead of evaporating when the turn ends — the
7
+ // fast-follow deferred in docs/plans/2026-06-08-workflow-instinct-bridge.md.
8
+ //
9
+ // Mode via CLAUDE_WORKFLOW_DISTILL_NUDGE: "on" | "off" (default).
10
+ // - off (default): no-op. Operators who do not use native Workflows are never
11
+ // nagged.
12
+ // - on: if the session's observation feed shows a verified Workflow run that
13
+ // has not already been nudged, print ONE stderr line suggesting
14
+ // ci_distill_from_workflow. It is an amplifier, never a gate — it cannot
15
+ // block the Stop and writes nothing to stdout.
16
+ //
17
+ // Project-hash resolution is byte-identical to bin/observe.mts and
18
+ // hooks/goal-drift-stop.mts so this hook reads the SAME observations.jsonl the
19
+ // observer writes. The "is this run verified" decision is the pure, already-tested
20
+ // workflowRunFromObservations (src/lib/skill-distill.mts), which fails closed:
21
+ // no Workflow row, unparseable meta, or no following verify-exit-0 => null => no
22
+ // nudge. Per-run dedup state lives in
23
+ // ~/.claude/instincts/<project-hash>/workflow-distill-state.json keyed by run
24
+ // name + verify command, so a run is nudged at most once. Fail-open by
25
+ // construction: any error exits 0 and never blocks. No network. 5s hook budget.
26
+ import { execFileSync } from "node:child_process";
27
+ import { createHash } from "node:crypto";
28
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
29
+ import { join } from "node:path";
30
+ import { resolveHomeDir } from "../lib/resolve-home-dir.mjs";
31
+ import { workflowRunFromObservations } from "../lib/skill-distill.mjs";
32
+ function safeJsonParse(text) {
33
+ try {
34
+ return JSON.parse(text);
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ function resolveMode() {
41
+ return (process.env.CLAUDE_WORKFLOW_DISTILL_NUDGE ?? "off").trim().toLowerCase() === "on" ? "on" : "off";
42
+ }
43
+ // Mirrors bin/observe.mts:resolveProjectRoot — the same basis the observer uses
44
+ // to bucket observations.jsonl, so the hash here resolves to the same file.
45
+ function resolveProjectRoot() {
46
+ const fromEnv = process.env.CLAUDE_PROJECT_DIR;
47
+ if (fromEnv)
48
+ return fromEnv;
49
+ try {
50
+ const root = execFileSync("git", ["rev-parse", "--show-toplevel"], {
51
+ encoding: "utf8",
52
+ stdio: ["ignore", "pipe", "ignore"],
53
+ }).trim();
54
+ if (root)
55
+ return root;
56
+ }
57
+ catch {
58
+ // not a git repo
59
+ }
60
+ return "global";
61
+ }
62
+ function projectHash(root) {
63
+ return createHash("sha256").update(root).digest("hex").slice(0, 12);
64
+ }
65
+ function readObservations(instinctsProjectDir) {
66
+ const file = join(instinctsProjectDir, "observations.jsonl");
67
+ try {
68
+ if (!existsSync(file))
69
+ return [];
70
+ const lines = readFileSync(file, "utf8")
71
+ .split("\n")
72
+ .filter((line) => line.trim().length > 0);
73
+ const out = [];
74
+ // A workflow row plus its following verify both sit near the tail; a bounded
75
+ // window keeps the 5s budget safe on a long-lived feed.
76
+ for (const line of lines.slice(-5000)) {
77
+ const row = safeJsonParse(line);
78
+ if (!row)
79
+ continue;
80
+ out.push({
81
+ ts: typeof row.ts === "string" ? row.ts : "",
82
+ session: typeof row.session === "string" ? row.session : "",
83
+ session_id: typeof row.session_id === "string" ? row.session_id : "",
84
+ tool: typeof row.tool === "string" ? row.tool : "",
85
+ input_summary: typeof row.input_summary === "string" ? row.input_summary : "",
86
+ output_summary: typeof row.output_summary === "string" ? row.output_summary : "",
87
+ });
88
+ }
89
+ return out;
90
+ }
91
+ catch {
92
+ return [];
93
+ }
94
+ }
95
+ function readNudgedKeys(instinctsProjectDir) {
96
+ const file = join(instinctsProjectDir, "workflow-distill-state.json");
97
+ try {
98
+ if (!existsSync(file))
99
+ return new Set();
100
+ const parsed = safeJsonParse(readFileSync(file, "utf8"));
101
+ const arr = parsed && Array.isArray(parsed.nudged) ? parsed.nudged : [];
102
+ return new Set(arr.filter((x) => typeof x === "string"));
103
+ }
104
+ catch {
105
+ return new Set();
106
+ }
107
+ }
108
+ function persistNudged(instinctsProjectDir, keys) {
109
+ try {
110
+ mkdirSync(instinctsProjectDir, { recursive: true });
111
+ writeFileSync(join(instinctsProjectDir, "workflow-distill-state.json"), JSON.stringify({ ts: new Date().toISOString(), nudged: [...keys] }) + "\n", "utf8");
112
+ }
113
+ catch {
114
+ // dedup persistence is best-effort; never throw
115
+ }
116
+ }
117
+ function main() {
118
+ if (resolveMode() === "off")
119
+ return;
120
+ const home = resolveHomeDir();
121
+ if (!home)
122
+ return;
123
+ const projectRoot = resolveProjectRoot();
124
+ const instinctsProjectDir = join(home, ".claude", "instincts", projectHash(projectRoot));
125
+ const observations = readObservations(instinctsProjectDir);
126
+ if (observations.length === 0)
127
+ return;
128
+ const run = workflowRunFromObservations(observations);
129
+ if (!run)
130
+ return; // fail closed: no verified run, nothing to nudge
131
+ const runKey = `${run.name}::${run.verifyCommand}`;
132
+ const nudged = readNudgedKeys(instinctsProjectDir);
133
+ if (nudged.has(runKey))
134
+ return; // already nudged this run — stay quiet
135
+ process.stderr.write(`[continuous-improvement] workflow-distill: verified workflow run "${run.name}" detected — ` +
136
+ "run the ci_distill_from_workflow MCP tool to persist it as a Mulahazah draft instinct.\n");
137
+ nudged.add(runKey);
138
+ persistNudged(instinctsProjectDir, nudged);
139
+ }
140
+ try {
141
+ main();
142
+ }
143
+ catch {
144
+ // fail open — never block the session due to a hook bug
145
+ }
@@ -26,7 +26,7 @@ const KEYWORDS = [
26
26
  "transcript-linter",
27
27
  ];
28
28
  const CLAUDE_PLUGIN_CATEGORY = "productivity";
29
- const SHARED_PLUGIN_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 25 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.";
29
+ const SHARED_PLUGIN_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 27 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.";
30
30
  // Four vendored upstream companions registered alongside the CI plugin.
31
31
  // Each entry points at a pinned-SHA snapshot under third-party/<name>/.
32
32
  // See third-party/MANIFEST.md for refresh recipes and per-snapshot
@@ -492,6 +492,11 @@ export function getPluginHooksConfig() {
492
492
  command: "node \"${CLAUDE_PLUGIN_ROOT}/hooks/goal-drift-stop.mjs\"",
493
493
  timeout: 5,
494
494
  };
495
+ const workflowDistillCommand = {
496
+ type: "command",
497
+ command: "node \"${CLAUDE_PLUGIN_ROOT}/hooks/workflow-distill.mjs\"",
498
+ timeout: 5,
499
+ };
495
500
  const routePromptCommand = {
496
501
  type: "command",
497
502
  command: "node \"${CLAUDE_PLUGIN_ROOT}/hooks/route-prompt.mjs\"",
@@ -503,7 +508,7 @@ export function getPluginHooksConfig() {
503
508
  timeout: 5,
504
509
  };
505
510
  return {
506
- description: "Gateguard fact-forcing PreToolUse, companion-preference enforcement, observation, session lifecycle, 3-section-close discipline, goal-drift Stop gate, and UserPromptSubmit lazy-routing plus opt-in proactive recall-briefing hooks for continuous-improvement.",
511
+ description: "Gateguard fact-forcing PreToolUse, companion-preference enforcement, observation, session lifecycle, 3-section-close discipline, goal-drift Stop gate, opt-in workflow-distill Stop nudge, and UserPromptSubmit lazy-routing plus opt-in proactive recall-briefing hooks for continuous-improvement.",
507
512
  hooks: {
508
513
  // gateguard runs FIRST on PreToolUse so its block decision short-circuits
509
514
  // before companion-preference sees the call. companion-preference runs
@@ -527,7 +532,7 @@ export function getPluginHooksConfig() {
527
532
  UserPromptSubmit: [{ hooks: [routePromptCommand, recallBriefingCommand] }],
528
533
  SessionStart: [{ hooks: [sessionCommand] }],
529
534
  SessionEnd: [{ hooks: [sessionCommand] }],
530
- Stop: [{ hooks: [threeSectionCloseCommand, goalDriftStopCommand] }],
535
+ Stop: [{ hooks: [threeSectionCloseCommand, goalDriftStopCommand, workflowDistillCommand] }],
531
536
  },
532
537
  };
533
538
  }