continuous-improvement 3.9.2 → 3.12.3
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.
- package/.claude-plugin/marketplace.json +3 -3
- package/CHANGELOG.md +95 -0
- package/LICENSE +21 -21
- package/QUICKSTART.md +13 -8
- package/README.md +94 -162
- package/SKILL.md +1 -1
- package/bin/analyze.sh +161 -161
- package/bin/backfill.mjs +19 -19
- package/bin/check-docs-substrings.mjs +73 -0
- package/bin/check-scripts-citation-drift.mjs +210 -0
- package/bin/check-skill-count.mjs +110 -0
- package/bin/check-test-imports-only.mjs +126 -0
- package/bin/check-tool-count.mjs +129 -0
- package/bin/companion-preference-status.mjs +231 -0
- package/bin/gateguard-clear.mjs +53 -0
- package/bin/generate-plugin-manifests.mjs +8 -1
- package/bin/harvest-friction.mjs +1 -1
- package/bin/hook-stats.mjs +21 -21
- package/bin/install.mjs +185 -28
- package/bin/mcp-server.mjs +216 -3
- package/bin/refresh-third-party.mjs +315 -313
- package/commands/audit.md +34 -0
- package/commands/companion-preference.md +58 -0
- package/commands/continuous-improvement.md +115 -115
- package/commands/dashboard.md +56 -56
- package/commands/discipline.md +14 -0
- package/commands/distill.md +39 -0
- package/commands/goal-check.md +53 -0
- package/commands/grill-me.md +40 -0
- package/commands/grill-with-docs.md +38 -0
- package/commands/handoff.md +42 -0
- package/commands/harvest.md +1 -1
- package/commands/proceed-with-the-recommendation.md +20 -0
- package/commands/recall.md +49 -0
- package/commands/reconcile.md +47 -0
- package/commands/seven-laws.md +16 -16
- package/commands/superpowers.md +3 -3
- package/commands/verify-install.md +55 -0
- package/commands/workspace-surface-audit.md +77 -77
- package/hooks/companion-preference.mjs +190 -0
- package/hooks/gateguard.mjs +72 -25
- package/hooks/goal-drift-stop.mjs +183 -0
- package/hooks/observe.sh +15 -1
- package/hooks/recall-briefing.mjs +167 -0
- package/hooks/route-prompt.mjs +180 -0
- package/hooks/route-table.json +35 -0
- package/hooks/session.sh +106 -106
- package/hooks/three-section-close.mjs +134 -132
- package/instinct-packs/go.json +58 -58
- package/instinct-packs/meta.json +16 -16
- package/instinct-packs/python.json +58 -58
- package/instinct-packs/react.json +58 -58
- package/lib/gateguard-state.mjs +54 -2
- package/lib/goal-drift-gate.mjs +50 -0
- package/lib/goal-state.mjs +285 -0
- package/lib/plugin-metadata.mjs +134 -15
- package/lib/recall-briefing.mjs +57 -0
- package/lib/recall-index.mjs +175 -0
- package/lib/skill-distill.mjs +222 -0
- package/llms.txt +2 -2
- package/package.json +12 -7
- package/plugins/beginner.json +9 -4
- package/plugins/continuous-improvement/.claude-plugin/marketplace.json +2 -2
- package/plugins/continuous-improvement/.claude-plugin/plugin.json +2 -2
- package/plugins/continuous-improvement/LICENSE +21 -21
- package/plugins/continuous-improvement/agents/README.md +3 -3
- package/plugins/continuous-improvement/bin/backfill.mjs +19 -19
- package/plugins/continuous-improvement/bin/gateguard-clear.mjs +53 -0
- package/plugins/continuous-improvement/bin/mcp-server.mjs +216 -3
- package/plugins/continuous-improvement/commands/audit.md +34 -0
- package/plugins/continuous-improvement/commands/companion-preference.md +58 -0
- package/plugins/continuous-improvement/commands/continuous-improvement.md +115 -115
- package/plugins/continuous-improvement/commands/dashboard.md +56 -56
- package/plugins/continuous-improvement/commands/discipline.md +14 -0
- package/plugins/continuous-improvement/commands/distill.md +39 -0
- package/plugins/continuous-improvement/commands/goal-check.md +53 -0
- package/plugins/continuous-improvement/commands/grill-me.md +40 -0
- package/plugins/continuous-improvement/commands/grill-with-docs.md +38 -0
- package/plugins/continuous-improvement/commands/handoff.md +42 -0
- package/plugins/continuous-improvement/commands/harvest.md +1 -1
- package/plugins/continuous-improvement/commands/proceed-with-the-recommendation.md +20 -0
- package/plugins/continuous-improvement/commands/recall.md +49 -0
- package/plugins/continuous-improvement/commands/reconcile.md +47 -0
- package/plugins/continuous-improvement/commands/seven-laws.md +16 -16
- package/plugins/continuous-improvement/commands/superpowers.md +3 -3
- package/plugins/continuous-improvement/commands/verify-install.md +55 -0
- package/plugins/continuous-improvement/commands/workspace-surface-audit.md +77 -77
- package/plugins/continuous-improvement/hooks/companion-preference.mjs +190 -0
- package/plugins/continuous-improvement/hooks/gateguard.mjs +72 -25
- package/plugins/continuous-improvement/hooks/goal-drift-stop.mjs +183 -0
- package/plugins/continuous-improvement/hooks/hooks.json +23 -2
- package/plugins/continuous-improvement/hooks/observe.sh +15 -1
- package/plugins/continuous-improvement/hooks/recall-briefing.mjs +167 -0
- package/plugins/continuous-improvement/hooks/route-prompt.mjs +180 -0
- package/plugins/continuous-improvement/hooks/route-table.json +35 -0
- package/plugins/continuous-improvement/hooks/session.sh +106 -106
- package/plugins/continuous-improvement/hooks/three-section-close.mjs +134 -132
- package/plugins/continuous-improvement/instinct-packs/go.json +58 -58
- package/plugins/continuous-improvement/instinct-packs/meta.json +16 -16
- package/plugins/continuous-improvement/instinct-packs/python.json +58 -58
- package/plugins/continuous-improvement/instinct-packs/react.json +58 -58
- package/plugins/continuous-improvement/lib/gateguard-state.mjs +137 -0
- package/plugins/continuous-improvement/lib/goal-drift-gate.mjs +50 -0
- package/plugins/continuous-improvement/lib/goal-state.mjs +285 -0
- package/plugins/continuous-improvement/lib/plugin-metadata.mjs +134 -15
- package/plugins/continuous-improvement/lib/recall-briefing.mjs +57 -0
- package/plugins/continuous-improvement/lib/recall-index.mjs +175 -0
- package/plugins/continuous-improvement/lib/skill-distill.mjs +222 -0
- package/plugins/continuous-improvement/skills/README.md +8 -0
- package/plugins/continuous-improvement/skills/audit/SKILL.md +73 -0
- package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +1 -1
- package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +13 -17
- package/plugins/continuous-improvement/skills/gateguard/SKILL.md +36 -17
- package/plugins/continuous-improvement/skills/goal-monitor/SKILL.md +81 -0
- package/plugins/continuous-improvement/skills/grill-me/SKILL.md +66 -0
- package/plugins/continuous-improvement/skills/grill-with-docs/SKILL.md +252 -0
- package/plugins/continuous-improvement/skills/handoff/SKILL.md +59 -0
- package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +1 -1
- package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +82 -6
- package/plugins/continuous-improvement/skills/ralph/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/recall/SKILL.md +50 -0
- package/plugins/continuous-improvement/skills/reconcile/SKILL.md +80 -0
- package/plugins/continuous-improvement/skills/recovery-classification/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/skill-distillation/SKILL.md +57 -0
- package/plugins/continuous-improvement/skills/state-reconciliation/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/superpowers/SKILL.md +77 -3
- package/plugins/continuous-improvement/skills/tdd-workflow/SKILL.md +411 -411
- package/plugins/continuous-improvement/skills/token-budget-advisor/SKILL.md +1 -1
- package/plugins/continuous-improvement/skills/verification-loop/SKILL.md +28 -20
- package/plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md +1 -0
- package/plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md +1 -1
- package/plugins/continuous-improvement/skills/worktree-safety/SKILL.md +3 -2
- package/plugins/expert.json +28 -3
- package/skills/README.md +3 -0
- package/skills/audit.md +73 -0
- package/skills/deploy-receipt.md +13 -17
- package/skills/gateguard.md +36 -17
- package/skills/goal-monitor.md +81 -0
- package/skills/grill-me.md +66 -0
- package/skills/grill-with-docs.md +252 -0
- package/skills/handoff.md +59 -0
- package/skills/para-memory-files.md +1 -1
- package/skills/proceed-with-the-recommendation.md +82 -6
- package/skills/ralph.md +1 -0
- package/skills/recall.md +50 -0
- package/skills/reconcile.md +80 -0
- package/skills/recovery-classification.md +1 -0
- package/skills/safety-guard.md +1 -0
- package/skills/skill-distillation.md +57 -0
- package/skills/state-reconciliation.md +1 -0
- package/skills/strategic-compact.md +1 -0
- package/skills/superpowers.md +77 -3
- package/skills/tdd-workflow.md +411 -411
- package/skills/token-budget-advisor.md +1 -1
- package/skills/verification-loop.md +28 -20
- package/skills/wild-risa-balance.md +1 -0
- package/skills/workspace-surface-audit.md +1 -1
- package/skills/worktree-safety.md +3 -2
package/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# continuous-improvement
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Makes Claude Code reason harder, recall past corrections, and learn from every session so its competence compounds run over run. The Mulahazah engine turns each fix into a reusable instinct, so a lesson learned once is applied automatically next time — 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.
|
|
4
4
|
|
|
5
5
|
## What This Is
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
An intelligence amplifier for AI coding agents. It makes Claude reason at a higher level on every task, recall the corrections it has already received, and learn from each 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.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "continuous-improvement",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.12.3",
|
|
4
|
+
"description": "Makes Claude Code reason harder, recall past corrections, and learn from every session so its competence compounds run over run. The Mulahazah engine turns each fix into a reusable instinct, so a lesson learned once is applied automatically next time — 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. 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://
|
|
25
|
+
"homepage": "https://continuous-improvement.dev",
|
|
26
26
|
"bugs": {
|
|
27
27
|
"url": "https://github.com/naimkatiman/continuous-improvement/issues"
|
|
28
28
|
},
|
|
@@ -32,21 +32,26 @@
|
|
|
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
|
|
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:
|
|
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:tool-count": "node bin/check-tool-count.mjs",
|
|
54
|
+
"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 verify:tool-count && npm run typecheck"
|
|
50
55
|
},
|
|
51
56
|
"files": [
|
|
52
57
|
".claude-plugin/",
|
package/plugins/beginner.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "continuous-improvement",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.12.3",
|
|
4
4
|
"mode": "beginner",
|
|
5
|
-
"description": "Beginner mode: see what your agent learned, list its instincts, and request a session reflection. Bundles four
|
|
5
|
+
"description": "Beginner mode: see what your agent learned, list its instincts, and request a session reflection. Bundles four grounding skills (gateguard, para-memory-files, tdd-workflow, verification-loop) so research, memory, tests, and verification happen by default — every edit starts from facts, not guesses.",
|
|
6
6
|
"tools": [
|
|
7
7
|
{
|
|
8
8
|
"name": "ci_status",
|
|
@@ -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 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": "
|
|
11
|
-
"version": "3.
|
|
10
|
+
"description": "Makes Claude Code reason harder, recall past corrections, and learn from every session so its competence compounds run over run. The Mulahazah engine turns each fix into a reusable instinct, so a lesson learned once is applied automatically next time — 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.12.3",
|
|
12
12
|
"source": "./",
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "naimkatiman"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "continuous-improvement",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.12.3",
|
|
4
|
+
"description": "Makes Claude Code reason harder, recall past corrections, and learn from every session so its competence compounds run over run. The Mulahazah engine turns each fix into a reusable instinct, so a lesson learned once is applied automatically next time — 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.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "naimkatiman",
|
|
7
7
|
"url": "https://github.com/naimkatiman"
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Naim Katiman
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Naim Katiman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -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
|
|
43
|
+
This is the only orchestration pattern this repo endorses. See the **Decision matrix** below for when to fan out versus invoke a single persona.
|
|
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).
|
|
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).
|
|
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
|
|
|
@@ -117,4 +117,4 @@ Plugin agents do not support `hooks`, `mcpServers`, or `permissionMode` frontmat
|
|
|
117
117
|
2. Define the role, scope, output format, and rules.
|
|
118
118
|
3. Add a **Composition** block at the bottom (Invoke directly when / Invoke via / Do not invoke from another persona).
|
|
119
119
|
4. Add the persona to the table at the top of this file.
|
|
120
|
-
5. If the persona enables a new orchestration pattern, document it in
|
|
120
|
+
5. If the persona enables a new orchestration pattern, document it in the **Decision matrix** above rather than inventing the pattern in the persona file itself.
|
|
@@ -27,25 +27,25 @@ const args = process.argv.slice(2);
|
|
|
27
27
|
const DRY_RUN = args.includes("--dry-run");
|
|
28
28
|
const HELP = args.includes("--help") || args.includes("-h");
|
|
29
29
|
if (HELP) {
|
|
30
|
-
console.log(`
|
|
31
|
-
backfill — Tag legacy thin-schema observation rows.
|
|
32
|
-
|
|
33
|
-
Usage:
|
|
34
|
-
npx continuous-improvement backfill Tag rows in place
|
|
35
|
-
npx continuous-improvement backfill --dry-run Report counts, write nothing
|
|
36
|
-
|
|
37
|
-
What it does:
|
|
38
|
-
Walks ~/.claude/instincts/<hash>/observations.jsonl files and adds a
|
|
39
|
-
schema field ("thin" or "rich") to every row that lacks one. Thin rows
|
|
40
|
-
came from the legacy bash fallback (jq missing) and have no input_summary;
|
|
41
|
-
rich rows came from the Node observer and have full tool_input.command /
|
|
42
|
-
Edit.file_path / etc.
|
|
43
|
-
|
|
44
|
-
Output:
|
|
45
|
-
- observations.jsonl rewritten in place (original kept as .bak)
|
|
46
|
-
- backfill-summary.json with per-project counts
|
|
47
|
-
|
|
48
|
-
Idempotent. Always exits 0 — failures go to stderr only.
|
|
30
|
+
console.log(`
|
|
31
|
+
backfill — Tag legacy thin-schema observation rows.
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
npx continuous-improvement backfill Tag rows in place
|
|
35
|
+
npx continuous-improvement backfill --dry-run Report counts, write nothing
|
|
36
|
+
|
|
37
|
+
What it does:
|
|
38
|
+
Walks ~/.claude/instincts/<hash>/observations.jsonl files and adds a
|
|
39
|
+
schema field ("thin" or "rich") to every row that lacks one. Thin rows
|
|
40
|
+
came from the legacy bash fallback (jq missing) and have no input_summary;
|
|
41
|
+
rich rows came from the Node observer and have full tool_input.command /
|
|
42
|
+
Edit.file_path / etc.
|
|
43
|
+
|
|
44
|
+
Output:
|
|
45
|
+
- observations.jsonl rewritten in place (original kept as .bak)
|
|
46
|
+
- backfill-summary.json with per-project counts
|
|
47
|
+
|
|
48
|
+
Idempotent. Always exits 0 — failures go to stderr only.
|
|
49
49
|
`);
|
|
50
50
|
process.exit(0);
|
|
51
51
|
}
|
|
@@ -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();
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* continuous-improvement MCP Server
|
|
4
4
|
*
|
|
5
5
|
* Exposes instincts, observations, and reflection as MCP tools + resources.
|
|
6
|
-
* Two modes: beginner (
|
|
6
|
+
* Two modes: beginner (4 tools) and expert (all tools).
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* node bin/mcp-server.mjs # default: beginner mode
|
|
@@ -11,13 +11,17 @@
|
|
|
11
11
|
* node bin/mcp-server.mjs --mode beginner # explicit beginner
|
|
12
12
|
*/
|
|
13
13
|
import { execSync } from "node:child_process";
|
|
14
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
15
15
|
import { homedir } from "node:os";
|
|
16
16
|
import { basename, dirname, join } from "node:path";
|
|
17
17
|
import { createInterface } from "node:readline";
|
|
18
18
|
import { fileURLToPath } from "node:url";
|
|
19
19
|
import { createHash } from "node:crypto";
|
|
20
20
|
import { PACKAGE_NAME, VERSION, getToolDefinitions, isPluginMode, } from "../lib/plugin-metadata.mjs";
|
|
21
|
+
import { formatDriftReport, parseGoalFromPlan, scoreObservations, } from "../lib/goal-state.mjs";
|
|
22
|
+
import { buildIndex, formatRecallHits, parseSince, query as queryRecall, } from "../lib/recall-index.mjs";
|
|
23
|
+
import { draftFromCandidate, extractTrajectories, findCandidates, formatCandidates, serializeDraft, } from "../lib/skill-distill.mjs";
|
|
24
|
+
import { MAX_CLEARED_FILES, clearFiles, resolveSessionDir, } from "../lib/gateguard-state.mjs";
|
|
21
25
|
function getHomeDir() {
|
|
22
26
|
return process.env.HOME || process.env.USERPROFILE || homedir();
|
|
23
27
|
}
|
|
@@ -32,6 +36,12 @@ function getString(value, fallback = "") {
|
|
|
32
36
|
function getNumber(value, fallback = 0) {
|
|
33
37
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
34
38
|
}
|
|
39
|
+
// Draft ids are derived from slugified tool n-grams (src/lib/skill-distill.mts)
|
|
40
|
+
// and are joined into a filesystem path, so a caller-supplied id must match the
|
|
41
|
+
// safe shape before it is used to read/write/delete a draft file.
|
|
42
|
+
function isSafeDraftId(id) {
|
|
43
|
+
return /^draft-[a-z0-9-]+$/.test(id);
|
|
44
|
+
}
|
|
35
45
|
function getBoolean(value, fallback = false) {
|
|
36
46
|
return typeof value === "boolean" ? value : fallback;
|
|
37
47
|
}
|
|
@@ -174,6 +184,12 @@ function countObservations(projectHash) {
|
|
|
174
184
|
}
|
|
175
185
|
}
|
|
176
186
|
function getRecentObservations(projectHash, limit = 50) {
|
|
187
|
+
// Clamp a non-positive or non-integer limit to the default. slice(-0) would
|
|
188
|
+
// otherwise return the ENTIRE history (the limit:0 boundary), and a negative
|
|
189
|
+
// limit would drop rows from the front instead of taking the tail. ci_goal_check
|
|
190
|
+
// pre-rejects bad limits with a clear error(); this guards ci_observations and
|
|
191
|
+
// any other caller that passes a user-supplied limit straight through.
|
|
192
|
+
const cappedLimit = Number.isInteger(limit) && limit > 0 ? limit : 50;
|
|
177
193
|
const observationsFile = join(INSTINCTS_DIR, projectHash, "observations.jsonl");
|
|
178
194
|
if (!existsSync(observationsFile)) {
|
|
179
195
|
return [];
|
|
@@ -182,7 +198,7 @@ function getRecentObservations(projectHash, limit = 50) {
|
|
|
182
198
|
const lines = readFileSync(observationsFile, "utf8")
|
|
183
199
|
.split("\n")
|
|
184
200
|
.filter((line) => line.trim().length > 0);
|
|
185
|
-
return lines.slice(-
|
|
201
|
+
return lines.slice(-cappedLimit).flatMap((line) => {
|
|
186
202
|
try {
|
|
187
203
|
return [JSON.parse(line)];
|
|
188
204
|
}
|
|
@@ -195,6 +211,16 @@ function getRecentObservations(projectHash, limit = 50) {
|
|
|
195
211
|
return [];
|
|
196
212
|
}
|
|
197
213
|
}
|
|
214
|
+
function readDistillObservations(projectHash) {
|
|
215
|
+
return getRecentObservations(projectHash, 100000).map((observation) => ({
|
|
216
|
+
ts: getString(observation.ts),
|
|
217
|
+
session: getString(observation.session),
|
|
218
|
+
session_id: getString(observation.session_id),
|
|
219
|
+
tool: getString(observation.tool),
|
|
220
|
+
input_summary: getString(observation.input_summary),
|
|
221
|
+
output_summary: getString(observation.output_summary),
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
198
224
|
function detectLevel(projectHash) {
|
|
199
225
|
const observationCount = countObservations(projectHash);
|
|
200
226
|
const instincts = readInstincts(projectHash);
|
|
@@ -480,6 +506,33 @@ function handleTool(name, params) {
|
|
|
480
506
|
].join("\n");
|
|
481
507
|
return text(reflection);
|
|
482
508
|
}
|
|
509
|
+
case "ci_gateguard_clear": {
|
|
510
|
+
// Beginner-available on purpose: the GateGuard hook fires for every
|
|
511
|
+
// install, so the clearance action must too. Resolves the session dir via
|
|
512
|
+
// gateguard-state (canonical), the same way the hook does, so the marker
|
|
513
|
+
// lands where the hook looks regardless of how each process spelled the
|
|
514
|
+
// project root.
|
|
515
|
+
const rawList = Array.isArray(params.file_paths) ? params.file_paths : [];
|
|
516
|
+
const listPaths = rawList.filter((value) => typeof value === "string" && value.length > 0);
|
|
517
|
+
const single = getString(params.file_path).trim();
|
|
518
|
+
const paths = single ? [...listPaths, single] : listPaths;
|
|
519
|
+
if (paths.length === 0) {
|
|
520
|
+
return error("file_paths is required — pass the file path(s) named in the GateGuard block reason, e.g. { file_paths: [\"src/x.ts\"] }.");
|
|
521
|
+
}
|
|
522
|
+
const sessionDir = resolveSessionDir();
|
|
523
|
+
const { cleared, skippedForCap } = clearFiles(sessionDir, paths);
|
|
524
|
+
const lines = [
|
|
525
|
+
"## GateGuard clearance",
|
|
526
|
+
"",
|
|
527
|
+
`**State file:** ${join(sessionDir, "gateguard-session.json")}`,
|
|
528
|
+
`**Cleared (${cleared.length}):** ${cleared.length > 0 ? cleared.join(", ") : "(none — already cleared)"}`,
|
|
529
|
+
];
|
|
530
|
+
if (skippedForCap.length > 0) {
|
|
531
|
+
lines.push(`**Skipped — session cap of ${MAX_CLEARED_FILES} reached (${skippedForCap.length}):** ${skippedForCap.join(", ")}`, "Start a new session to reset the gate.");
|
|
532
|
+
}
|
|
533
|
+
lines.push("", "Retry the Edit/Write now — it will pass.");
|
|
534
|
+
return text(lines.join("\n"));
|
|
535
|
+
}
|
|
483
536
|
case "ci_reinforce": {
|
|
484
537
|
if (MODE !== "expert") {
|
|
485
538
|
return error("ci_reinforce requires expert mode. Start server with --mode expert");
|
|
@@ -665,6 +718,166 @@ function handleTool(name, params) {
|
|
|
665
718
|
}
|
|
666
719
|
return text(lines.join("\n"));
|
|
667
720
|
}
|
|
721
|
+
case "ci_goal_check": {
|
|
722
|
+
if (MODE !== "expert") {
|
|
723
|
+
return error("ci_goal_check requires expert mode");
|
|
724
|
+
}
|
|
725
|
+
const limit = getNumber(params.limit, 30);
|
|
726
|
+
if (!Number.isInteger(limit) || limit <= 0) {
|
|
727
|
+
return error(`limit must be a positive integer; got ${limit}. Omit it to score the default 30 most recent observations.`);
|
|
728
|
+
}
|
|
729
|
+
const explicit = getString(params.goal_file).trim();
|
|
730
|
+
const workspaceRoot = getWorkspaceRoot();
|
|
731
|
+
const candidates = explicit
|
|
732
|
+
? [explicit]
|
|
733
|
+
: [
|
|
734
|
+
join(workspaceRoot, PLANNING_FILES.taskPlan),
|
|
735
|
+
join(INSTINCTS_DIR, project.hash, "goal.md"),
|
|
736
|
+
];
|
|
737
|
+
let goalContent = "";
|
|
738
|
+
let goalSource = "";
|
|
739
|
+
for (const candidate of candidates) {
|
|
740
|
+
if (!existsSync(candidate)) {
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
try {
|
|
744
|
+
goalContent = readFileSync(candidate, "utf8");
|
|
745
|
+
goalSource = candidate;
|
|
746
|
+
break;
|
|
747
|
+
}
|
|
748
|
+
catch {
|
|
749
|
+
// try the next candidate
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
if (!goalContent) {
|
|
753
|
+
return text(`No goal source found. Looked for: ${candidates.join(", ")}.\nRun ci_plan_init (or /planning-with-files) to create ${PLANNING_FILES.taskPlan} with a '## Goal' section.`);
|
|
754
|
+
}
|
|
755
|
+
const goal = parseGoalFromPlan(goalContent);
|
|
756
|
+
if (!goal) {
|
|
757
|
+
return text(`Found ${goalSource} but it has no '## Goal' section. Add one — ci_plan_init seeds it. Optional '## Goal Keywords' and '## Goal Scope' sections sharpen the drift signal.`);
|
|
758
|
+
}
|
|
759
|
+
const goalObservations = getRecentObservations(project.hash, limit).map((observation) => ({
|
|
760
|
+
ts: getString(observation.ts),
|
|
761
|
+
tool: getString(observation.tool),
|
|
762
|
+
input_summary: getString(observation.input_summary),
|
|
763
|
+
output_summary: getString(observation.output_summary),
|
|
764
|
+
}));
|
|
765
|
+
const report = scoreObservations(goalObservations, goal, { window: limit });
|
|
766
|
+
return text(`## Goal Check\n\n**Goal source:** ${goalSource}\n\n${formatDriftReport(report)}`);
|
|
767
|
+
}
|
|
768
|
+
case "ci_recall": {
|
|
769
|
+
if (MODE !== "expert") {
|
|
770
|
+
return error("ci_recall requires expert mode");
|
|
771
|
+
}
|
|
772
|
+
const queryString = getString(params.query).trim();
|
|
773
|
+
if (!queryString) {
|
|
774
|
+
return error("query is required");
|
|
775
|
+
}
|
|
776
|
+
const k = getNumber(params.k, 5);
|
|
777
|
+
const since = getString(params.since).trim();
|
|
778
|
+
if (since && parseSince(since, Date.now()) === null) {
|
|
779
|
+
return error(`Could not parse since="${since}". Use an ISO timestamp (e.g. 2026-05-01) or a relative window like 7d, 24h, or 30m.`);
|
|
780
|
+
}
|
|
781
|
+
// Recall searches the full history, not just the recent window.
|
|
782
|
+
const recallObservations = getRecentObservations(project.hash, 100000).map((observation) => ({
|
|
783
|
+
ts: getString(observation.ts),
|
|
784
|
+
session: getString(observation.session),
|
|
785
|
+
session_id: getString(observation.session_id),
|
|
786
|
+
tool: getString(observation.tool),
|
|
787
|
+
input_summary: getString(observation.input_summary),
|
|
788
|
+
output_summary: getString(observation.output_summary),
|
|
789
|
+
}));
|
|
790
|
+
if (recallObservations.length === 0) {
|
|
791
|
+
return text("No observations yet. Hooks capture tool calls automatically; recall searches that history.");
|
|
792
|
+
}
|
|
793
|
+
const index = buildIndex(recallObservations);
|
|
794
|
+
const hits = queryRecall(index, queryString, { k, since: since || undefined });
|
|
795
|
+
return text(formatRecallHits(hits, queryString));
|
|
796
|
+
}
|
|
797
|
+
case "ci_distill_candidates": {
|
|
798
|
+
if (MODE !== "expert") {
|
|
799
|
+
return error("ci_distill_candidates requires expert mode");
|
|
800
|
+
}
|
|
801
|
+
const distillObservations = readDistillObservations(project.hash);
|
|
802
|
+
const candidates = findCandidates(extractTrajectories(distillObservations));
|
|
803
|
+
return text(formatCandidates(candidates));
|
|
804
|
+
}
|
|
805
|
+
case "ci_distill_propose": {
|
|
806
|
+
if (MODE !== "expert") {
|
|
807
|
+
return error("ci_distill_propose requires expert mode");
|
|
808
|
+
}
|
|
809
|
+
const id = getString(params.id).trim();
|
|
810
|
+
if (!id) {
|
|
811
|
+
return error("id is required — run ci_distill_candidates to list current candidate ids");
|
|
812
|
+
}
|
|
813
|
+
if (!isSafeDraftId(id)) {
|
|
814
|
+
return error(`Invalid draft id "${id}". Draft ids look like draft-<slug> (lowercase letters, digits, hyphens).`);
|
|
815
|
+
}
|
|
816
|
+
const distillObservations = readDistillObservations(project.hash);
|
|
817
|
+
const candidate = findCandidates(extractTrajectories(distillObservations)).find((entry) => entry.id === id);
|
|
818
|
+
if (!candidate) {
|
|
819
|
+
return error(`No candidate "${id}". Run ci_distill_candidates to list current ids.`);
|
|
820
|
+
}
|
|
821
|
+
const draft = serializeDraft(draftFromCandidate(candidate));
|
|
822
|
+
const draftsDir = join(INSTINCTS_DIR, project.hash, "drafts");
|
|
823
|
+
mkdirSync(draftsDir, { recursive: true });
|
|
824
|
+
const draftPath = join(draftsDir, `${id}.yaml`);
|
|
825
|
+
writeFileSync(draftPath, draft);
|
|
826
|
+
return text([
|
|
827
|
+
"## Draft written",
|
|
828
|
+
"",
|
|
829
|
+
`**Path:** ${draftPath}`,
|
|
830
|
+
"",
|
|
831
|
+
"Edit the body to capture the real recipe (preconditions, concrete steps, gotchas), then promote with:",
|
|
832
|
+
"",
|
|
833
|
+
` ci_distill_promote id=${id}`,
|
|
834
|
+
"",
|
|
835
|
+
"```yaml",
|
|
836
|
+
draft.trimEnd(),
|
|
837
|
+
"```",
|
|
838
|
+
].join("\n"));
|
|
839
|
+
}
|
|
840
|
+
case "ci_distill_promote": {
|
|
841
|
+
if (MODE !== "expert") {
|
|
842
|
+
return error("ci_distill_promote requires expert mode");
|
|
843
|
+
}
|
|
844
|
+
const id = getString(params.id).trim();
|
|
845
|
+
if (!id) {
|
|
846
|
+
return error("id is required");
|
|
847
|
+
}
|
|
848
|
+
if (!isSafeDraftId(id)) {
|
|
849
|
+
return error(`Invalid draft id "${id}". Draft ids look like draft-<slug> (lowercase letters, digits, hyphens).`);
|
|
850
|
+
}
|
|
851
|
+
const draftPath = join(INSTINCTS_DIR, project.hash, "drafts", `${id}.yaml`);
|
|
852
|
+
if (!existsSync(draftPath)) {
|
|
853
|
+
return error(`No draft at ${draftPath}. Run ci_distill_propose id=${id} first.`);
|
|
854
|
+
}
|
|
855
|
+
let parsed = null;
|
|
856
|
+
try {
|
|
857
|
+
parsed = parseYamlInstinct(readFileSync(draftPath, "utf8"));
|
|
858
|
+
}
|
|
859
|
+
catch {
|
|
860
|
+
parsed = null;
|
|
861
|
+
}
|
|
862
|
+
if (!parsed) {
|
|
863
|
+
return error(`Draft ${draftPath} could not be parsed as an instinct. Check the YAML shape.`);
|
|
864
|
+
}
|
|
865
|
+
const promoted = {
|
|
866
|
+
...parsed,
|
|
867
|
+
confidence: 0.5,
|
|
868
|
+
source: "distilled",
|
|
869
|
+
scope: "project",
|
|
870
|
+
observation_count: 1,
|
|
871
|
+
};
|
|
872
|
+
writeInstinct(project.hash, promoted);
|
|
873
|
+
try {
|
|
874
|
+
rmSync(draftPath);
|
|
875
|
+
}
|
|
876
|
+
catch {
|
|
877
|
+
// best-effort cleanup; the live instinct is already written
|
|
878
|
+
}
|
|
879
|
+
return text(`Promoted **${promoted.id}** to a project instinct at confidence ${promoted.confidence} (SUGGEST tier). The draft has been consumed.`);
|
|
880
|
+
}
|
|
668
881
|
case "ci_dashboard": {
|
|
669
882
|
if (MODE !== "expert") {
|
|
670
883
|
return error("ci_dashboard requires expert mode");
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audit
|
|
3
|
+
description: Audit a window of recent commits for real defects, confirm each finding before fixing, verify every surface a fix touches, then report confirmed/dismissed/no-op with evidence. Enforces Law 4 (Verify Before Reporting).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /audit — Confirm Recent Commits Before You Trust Them
|
|
7
|
+
|
|
8
|
+
Run the audit-driven loop over recent work: a merged commit with green CI is a claim, not a proof.
|
|
9
|
+
|
|
10
|
+
## What it does
|
|
11
|
+
|
|
12
|
+
Takes a commit window, hunts for real defects one concern at a time, proves each finding against the actual code (false positives die before any edit), fixes on a branch with the smallest diff, verifies every surface the fix touches, and reports honestly. Backed by the `audit` skill.
|
|
13
|
+
|
|
14
|
+
## The loop
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
1. Scope git log to pick the window (e.g. HEAD~10..HEAD, or main since last release)
|
|
18
|
+
2. Find one pass per dimension: value/economy drift, concurrency, surface coverage, type/contract
|
|
19
|
+
3. Confirm read the actual lines; state in one sentence why it is real, or dismiss it
|
|
20
|
+
4. Fix one concern per commit; prefer a failing test first, then green
|
|
21
|
+
5. Verify exercise EVERY surface (backend, frontend, admin, cache, migration), not just the edited one
|
|
22
|
+
6. Report confirmed (with the proof), dismissed (with why), no-op (in scope, nothing to change)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Default skeptical
|
|
26
|
+
|
|
27
|
+
Findings are hypotheses. Default each to a false positive until the code proves the bug — defaulting to "real" is how plausible-but-wrong fixes ship. For a thorough audit, fan the find pass out across dimensions with parallel reviewers, then verify each survivor adversarially.
|
|
28
|
+
|
|
29
|
+
## Pairs with
|
|
30
|
+
|
|
31
|
+
- **`audit`** skill — the discipline this command runs.
|
|
32
|
+
- **`code-review`** / **`security-review`** — the per-dimension passes.
|
|
33
|
+
- **`reconcile`** — the safe branch→PR path once the audit produces a fix.
|
|
34
|
+
- **`recall`** — check whether a finding was already hit and fixed before.
|