@infinitedusky/indusk-mcp 0.7.2 → 0.8.5
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/hooks/check-gates.js +58 -4
- package/hooks/validate-impl-structure.js +235 -0
- package/package.json +1 -1
- package/skills/document.md +107 -38
- package/skills/onboard.md +61 -0
- package/skills/plan.md +26 -2
- package/skills/work.md +69 -1
package/hooks/check-gates.js
CHANGED
|
@@ -27,7 +27,34 @@ if (!filePath.endsWith("/impl.md") && !filePath.endsWith("\\impl.md")) {
|
|
|
27
27
|
|
|
28
28
|
// Check for skip-gates escape hatch
|
|
29
29
|
const newContent = toolInput.new_string ?? toolInput.content ?? "";
|
|
30
|
-
|
|
30
|
+
|
|
31
|
+
// Read gate policy from the impl file and settings
|
|
32
|
+
function readGatePolicy() {
|
|
33
|
+
try {
|
|
34
|
+
const content = readFileSync(filePath, "utf-8");
|
|
35
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n/);
|
|
36
|
+
if (fmMatch) {
|
|
37
|
+
const policyMatch = fmMatch[1].match(/gate_policy:\s*(strict|ask|auto)/);
|
|
38
|
+
if (policyMatch) return policyMatch[1];
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// ignore
|
|
42
|
+
}
|
|
43
|
+
// Check project settings
|
|
44
|
+
try {
|
|
45
|
+
const settingsPath = `${event.cwd}/.claude/settings.json`;
|
|
46
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
47
|
+
if (settings.indusk?.gate_policy) return settings.indusk.gate_policy;
|
|
48
|
+
} catch {
|
|
49
|
+
// ignore
|
|
50
|
+
}
|
|
51
|
+
return "ask"; // default
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const gatePolicy = readGatePolicy();
|
|
55
|
+
|
|
56
|
+
// In strict mode, skip-gates escape hatch is not allowed
|
|
57
|
+
if (newContent.includes("<!-- skip-gates -->") && gatePolicy !== "strict") {
|
|
31
58
|
process.exit(0);
|
|
32
59
|
}
|
|
33
60
|
|
|
@@ -80,6 +107,22 @@ if (event.tool_name === "Edit" && oldContent) {
|
|
|
80
107
|
process.exit(0);
|
|
81
108
|
}
|
|
82
109
|
|
|
110
|
+
// Detect workflow type from content frontmatter
|
|
111
|
+
function detectWorkflow(content) {
|
|
112
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n/);
|
|
113
|
+
const fm = fmMatch ? fmMatch[1] : "";
|
|
114
|
+
const m = fm.match(/workflow:\s*(bugfix|refactor|feature|spike)/);
|
|
115
|
+
return m ? m[1] : "feature";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Which gate types are required per workflow
|
|
119
|
+
const WORKFLOW_GATES = {
|
|
120
|
+
feature: ["verification", "context", "document"],
|
|
121
|
+
refactor: ["verification", "context", "document"],
|
|
122
|
+
bugfix: ["verification", "document"],
|
|
123
|
+
spike: [],
|
|
124
|
+
};
|
|
125
|
+
|
|
83
126
|
// Parse phases from the NEW content (after edit) and OLD content (before edit)
|
|
84
127
|
function parsePhases(content) {
|
|
85
128
|
// Strip frontmatter
|
|
@@ -131,6 +174,8 @@ function parsePhases(content) {
|
|
|
131
174
|
return phases;
|
|
132
175
|
}
|
|
133
176
|
|
|
177
|
+
const workflow = detectWorkflow(fullContent);
|
|
178
|
+
const requiredGates = WORKFLOW_GATES[workflow] || WORKFLOW_GATES.feature;
|
|
134
179
|
const oldPhases = parsePhases(fullContent);
|
|
135
180
|
const newPhases = parsePhases(newFullContent);
|
|
136
181
|
|
|
@@ -171,15 +216,24 @@ for (const item of newlyChecked) {
|
|
|
171
216
|
for (const phase of oldPhases) {
|
|
172
217
|
if (phase.number >= item.phase) break;
|
|
173
218
|
|
|
219
|
+
const isOverridden = (text) =>
|
|
220
|
+
gatePolicy !== "strict" &&
|
|
221
|
+
(text.includes("(none needed)") ||
|
|
222
|
+
text.includes("(not applicable)") ||
|
|
223
|
+
text.includes("skip-reason:"));
|
|
224
|
+
|
|
174
225
|
const uncheckedGates = phase.items.filter(
|
|
175
|
-
(i) =>
|
|
176
|
-
!i.checked && (i.gate === "verification" || i.gate === "context" || i.gate === "document"),
|
|
226
|
+
(i) => !i.checked && !isOverridden(i.text) && requiredGates.includes(i.gate),
|
|
177
227
|
);
|
|
178
228
|
|
|
179
229
|
if (uncheckedGates.length > 0) {
|
|
180
230
|
const missing = uncheckedGates.map((i) => ` [${i.gate}] ${i.text}`).join("\n");
|
|
231
|
+
const skipHint =
|
|
232
|
+
gatePolicy === "strict"
|
|
233
|
+
? "Gate policy is 'strict' — no overrides allowed.\n"
|
|
234
|
+
: "To skip a gate item, ask the user first, then mark with (none needed) or skip-reason: {why}\n";
|
|
181
235
|
process.stderr.write(
|
|
182
|
-
`Phase ${item.phase} blocked: complete Phase ${phase.number} gates first:\n${missing}\n`,
|
|
236
|
+
`Phase ${item.phase} blocked (policy: ${gatePolicy}): complete Phase ${phase.number} gates first:\n${missing}\n${skipHint}`,
|
|
183
237
|
);
|
|
184
238
|
process.exit(2);
|
|
185
239
|
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PreToolUse hook: validates that impl phases have all four gate sections.
|
|
4
|
+
*
|
|
5
|
+
* Every phase must have: implementation items, Verification, Context, Document.
|
|
6
|
+
* Sections can opt out with (none needed), (not applicable), or skip-reason: {why}.
|
|
7
|
+
*
|
|
8
|
+
* Exit 0 = allow the edit
|
|
9
|
+
* Exit 2 = block the edit (stderr sent to agent as feedback)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
13
|
+
|
|
14
|
+
// Read hook input from stdin
|
|
15
|
+
let input = "";
|
|
16
|
+
for await (const chunk of process.stdin) {
|
|
17
|
+
input += chunk;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const event = JSON.parse(input);
|
|
21
|
+
const toolInput = event.tool_input ?? {};
|
|
22
|
+
const filePath = toolInput.file_path ?? "";
|
|
23
|
+
|
|
24
|
+
// Fast path: not an impl.md file
|
|
25
|
+
if (!filePath.endsWith("/impl.md") && !filePath.endsWith("\\impl.md")) {
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Check for skip-gates escape hatch
|
|
30
|
+
const newContent = toolInput.new_string ?? toolInput.content ?? "";
|
|
31
|
+
|
|
32
|
+
// Read gate policy
|
|
33
|
+
function readGatePolicy() {
|
|
34
|
+
// Check the content being written for a gate_policy in frontmatter
|
|
35
|
+
const contentToCheck = toolInput.content ?? toolInput.new_string ?? "";
|
|
36
|
+
const fmMatch = contentToCheck.match(/gate_policy:\s*(strict|ask|auto)/);
|
|
37
|
+
if (fmMatch) return fmMatch[1];
|
|
38
|
+
// Check existing file
|
|
39
|
+
try {
|
|
40
|
+
const existing = readFileSync(filePath, "utf-8");
|
|
41
|
+
const existingFm = existing.match(/^---\n([\s\S]*?)\n---\n/);
|
|
42
|
+
if (existingFm) {
|
|
43
|
+
const m = existingFm[1].match(/gate_policy:\s*(strict|ask|auto)/);
|
|
44
|
+
if (m) return m[1];
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
// ignore
|
|
48
|
+
}
|
|
49
|
+
// Check project settings
|
|
50
|
+
try {
|
|
51
|
+
const settingsPath = `${event.cwd}/.claude/settings.json`;
|
|
52
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
53
|
+
if (settings.indusk?.gate_policy) return settings.indusk.gate_policy;
|
|
54
|
+
} catch {
|
|
55
|
+
// ignore
|
|
56
|
+
}
|
|
57
|
+
return "ask";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const gatePolicy = readGatePolicy();
|
|
61
|
+
|
|
62
|
+
if (newContent.includes("<!-- skip-gates -->") && gatePolicy !== "strict") {
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Determine the full new content after edit
|
|
67
|
+
let newFullContent;
|
|
68
|
+
if (event.tool_name === "Edit" && toolInput.old_string) {
|
|
69
|
+
try {
|
|
70
|
+
const diskContent = readFileSync(filePath, "utf-8");
|
|
71
|
+
newFullContent = diskContent.replace(toolInput.old_string, newContent);
|
|
72
|
+
} catch {
|
|
73
|
+
// File doesn't exist yet — will be created by Write
|
|
74
|
+
newFullContent = newContent;
|
|
75
|
+
}
|
|
76
|
+
} else if (event.tool_name === "Write") {
|
|
77
|
+
newFullContent = toolInput.content ?? "";
|
|
78
|
+
} else {
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Only validate if this edit is adding/modifying phase structure
|
|
83
|
+
// Check if the edit contains phase headers
|
|
84
|
+
const editContent = toolInput.new_string ?? toolInput.content ?? "";
|
|
85
|
+
const hasPhaseHeader = /###\s+Phase\s+\d+/.test(editContent);
|
|
86
|
+
const hasChecklistItem = /- \[ \]/.test(editContent);
|
|
87
|
+
|
|
88
|
+
// If the edit doesn't touch phase structure, allow it
|
|
89
|
+
if (!hasPhaseHeader && !hasChecklistItem) {
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Parse frontmatter to detect workflow type
|
|
94
|
+
const fmMatch = newFullContent.match(/^---\n([\s\S]*?)\n---\n/);
|
|
95
|
+
const frontmatter = fmMatch ? fmMatch[1] : "";
|
|
96
|
+
const body = fmMatch ? newFullContent.slice(fmMatch[0].length) : newFullContent;
|
|
97
|
+
|
|
98
|
+
// Detect workflow type from frontmatter (workflow: bugfix|refactor|feature)
|
|
99
|
+
// or infer from plan structure
|
|
100
|
+
const workflowMatch = frontmatter.match(/workflow:\s*(bugfix|refactor|feature|spike)/);
|
|
101
|
+
const workflow = workflowMatch ? workflowMatch[1] : "feature";
|
|
102
|
+
|
|
103
|
+
// Different workflows have different requirements
|
|
104
|
+
const requirements = {
|
|
105
|
+
feature: { verification: true, context: true, document: true },
|
|
106
|
+
refactor: { verification: true, context: true, document: true },
|
|
107
|
+
bugfix: { verification: true, context: false, document: true },
|
|
108
|
+
spike: { verification: false, context: false, document: false },
|
|
109
|
+
}[workflow];
|
|
110
|
+
const lines = body.split("\n");
|
|
111
|
+
|
|
112
|
+
const phases = [];
|
|
113
|
+
let currentPhase = null;
|
|
114
|
+
let currentSection = "implementation";
|
|
115
|
+
|
|
116
|
+
for (const line of lines) {
|
|
117
|
+
const phaseMatch = line.match(/^###\s+Phase\s+(\d+)[:\s]+(.*)/);
|
|
118
|
+
if (phaseMatch) {
|
|
119
|
+
if (currentPhase) phases.push(currentPhase);
|
|
120
|
+
currentPhase = {
|
|
121
|
+
number: parseInt(phaseMatch[1], 10),
|
|
122
|
+
name: phaseMatch[2].trim(),
|
|
123
|
+
hasImplementation: false,
|
|
124
|
+
hasVerification: false,
|
|
125
|
+
hasContext: false,
|
|
126
|
+
hasDocument: false,
|
|
127
|
+
verificationIsOptOut: false,
|
|
128
|
+
contextIsOptOut: false,
|
|
129
|
+
documentIsOptOut: false,
|
|
130
|
+
};
|
|
131
|
+
currentSection = "implementation";
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!currentPhase) continue;
|
|
136
|
+
|
|
137
|
+
// Detect gate section headers
|
|
138
|
+
const verMatch = line.match(/^####\s+Phase\s+\d+\s+Verification\b/);
|
|
139
|
+
if (verMatch) {
|
|
140
|
+
currentPhase.hasVerification = true;
|
|
141
|
+
currentSection = "verification";
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const ctxMatch = line.match(/^####\s+Phase\s+\d+\s+Context\b/);
|
|
146
|
+
if (ctxMatch) {
|
|
147
|
+
currentPhase.hasContext = true;
|
|
148
|
+
currentSection = "context";
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const docMatch = line.match(/^####\s+Phase\s+\d+\s+Document\b/);
|
|
153
|
+
if (docMatch) {
|
|
154
|
+
currentPhase.hasDocument = true;
|
|
155
|
+
currentSection = "document";
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check for implementation items
|
|
160
|
+
if (currentSection === "implementation" && /^-\s+\[[ x]\]/.test(line)) {
|
|
161
|
+
currentPhase.hasImplementation = true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Track opt-out content in gate sections
|
|
165
|
+
const isOptOutLine =
|
|
166
|
+
line.includes("(none needed)") ||
|
|
167
|
+
line.includes("(not applicable)") ||
|
|
168
|
+
line.includes("skip-reason:");
|
|
169
|
+
if (currentPhase && isOptOutLine) {
|
|
170
|
+
if (currentSection === "verification") currentPhase.verificationIsOptOut = true;
|
|
171
|
+
if (currentSection === "context") currentPhase.contextIsOptOut = true;
|
|
172
|
+
if (currentSection === "document") currentPhase.documentIsOptOut = true;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Forward intelligence doesn't count as a gate
|
|
176
|
+
if (line.match(/^####\s+Phase\s+\d+\s+Forward Intelligence\b/)) {
|
|
177
|
+
currentSection = "fi";
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (currentPhase) phases.push(currentPhase);
|
|
181
|
+
|
|
182
|
+
// Check for opt-out content in gate sections
|
|
183
|
+
// Re-scan to check if sections that exist have (none needed) or skip-reason:
|
|
184
|
+
const isOptedOut = (text) =>
|
|
185
|
+
text.includes("(none needed)") ||
|
|
186
|
+
text.includes("(not applicable)") ||
|
|
187
|
+
text.includes("skip-reason:");
|
|
188
|
+
|
|
189
|
+
// Validate each phase
|
|
190
|
+
const errors = [];
|
|
191
|
+
for (const phase of phases) {
|
|
192
|
+
if (!phase.hasImplementation) continue; // Skip phases with no impl items (might be a header-only outline)
|
|
193
|
+
|
|
194
|
+
const missing = [];
|
|
195
|
+
if (requirements.verification && !phase.hasVerification) missing.push("Verification");
|
|
196
|
+
if (requirements.context && !phase.hasContext) missing.push("Context");
|
|
197
|
+
if (requirements.document && !phase.hasDocument) missing.push("Document");
|
|
198
|
+
|
|
199
|
+
if (missing.length > 0) {
|
|
200
|
+
errors.push(`Phase ${phase.number} (${phase.name}) is missing: ${missing.join(", ")}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// In strict mode, opt-outs are not allowed — sections must have real items
|
|
204
|
+
if (gatePolicy === "strict") {
|
|
205
|
+
const optOuts = [];
|
|
206
|
+
if (requirements.verification && phase.hasVerification && phase.verificationIsOptOut)
|
|
207
|
+
optOuts.push("Verification");
|
|
208
|
+
if (requirements.context && phase.hasContext && phase.contextIsOptOut)
|
|
209
|
+
optOuts.push("Context");
|
|
210
|
+
if (requirements.document && phase.hasDocument && phase.documentIsOptOut)
|
|
211
|
+
optOuts.push("Document");
|
|
212
|
+
if (optOuts.length > 0) {
|
|
213
|
+
errors.push(
|
|
214
|
+
`Phase ${phase.number} (${phase.name}): ${optOuts.join(", ")} cannot use opt-outs in strict mode — add real items`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (errors.length > 0) {
|
|
221
|
+
const msg = errors.join("\n");
|
|
222
|
+
const reqNames = Object.entries(requirements)
|
|
223
|
+
.filter(([, v]) => v)
|
|
224
|
+
.map(([k]) => k.charAt(0).toUpperCase() + k.slice(1));
|
|
225
|
+
const skipHint =
|
|
226
|
+
gatePolicy === "strict"
|
|
227
|
+
? "Gate policy is 'strict' — all sections must have real items, no overrides.\n"
|
|
228
|
+
: "If a section isn't needed, add it with (none needed) or skip-reason: {why}\nExample: #### Phase 1 Document\\n(none needed)\n";
|
|
229
|
+
process.stderr.write(
|
|
230
|
+
`Impl structure incomplete (workflow: ${workflow}, policy: ${gatePolicy}):\n${msg}\n\nThis workflow requires: ${reqNames.join(", ")} sections per phase.\n${skipHint}To change requirements, add 'workflow: bugfix' to the impl frontmatter.\n`,
|
|
231
|
+
);
|
|
232
|
+
process.exit(2);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
process.exit(0);
|
package/package.json
CHANGED
package/skills/document.md
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: document
|
|
3
|
-
description:
|
|
3
|
+
description: Build and maintain the project encyclopedia — a human-readable record of what was built, why, and how. Every plan contributes to documentation. This is not optional metadata.
|
|
4
4
|
argument-hint: "[what to document or 'check']"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
You know how to maintain documentation in this project.
|
|
8
8
|
|
|
9
|
+
## Why Documentation Exists
|
|
10
|
+
|
|
11
|
+
Documentation is **the project's encyclopedia**. It is a human-readable record that any developer — today or a year from now — can read and understand:
|
|
12
|
+
|
|
13
|
+
- **What** was built and how it works
|
|
14
|
+
- **Why** it was built this way and not another
|
|
15
|
+
- **How** to use it, configure it, extend it
|
|
16
|
+
- **What changed** over time (changelogs, decision records)
|
|
17
|
+
|
|
18
|
+
This is NOT the same as CLAUDE.md (which is agent-facing project memory) or code comments (which are implementation details). Documentation is for humans who need to understand the project without reading every source file.
|
|
19
|
+
|
|
20
|
+
**Documentation is never optional.** The question is not "does this need docs?" — the question is "what docs does this need?" Even a bugfix updates the changelog. Even a refactor updates architecture diagrams. Even an internal change may need a decision record explaining why.
|
|
21
|
+
|
|
22
|
+
The fact that information exists in CLAUDE.md, planning docs, or code does NOT eliminate the need for documentation. Those are working artifacts. Documentation is the polished, organized, permanent record.
|
|
23
|
+
|
|
9
24
|
## What Document Does
|
|
10
25
|
|
|
11
26
|
Document is a per-phase gate during impl execution, alongside verify and context. The full phase order is:
|
|
@@ -14,14 +29,25 @@ Document is a per-phase gate during impl execution, alongside verify and context
|
|
|
14
29
|
implement → verify → context → document → advance
|
|
15
30
|
```
|
|
16
31
|
|
|
17
|
-
After context items are done, the document gate asks
|
|
32
|
+
After context items are done, the document gate asks:
|
|
33
|
+
|
|
34
|
+
**"What should a developer reading this project's docs learn from what this phase built?"**
|
|
18
35
|
|
|
19
|
-
**
|
|
36
|
+
To answer this accurately, **REQUIRED: call `query_dependencies`** on the key files changed in this phase to understand what was affected and how broadly.
|
|
20
37
|
|
|
21
|
-
|
|
38
|
+
For each phase, consider all of these:
|
|
22
39
|
|
|
23
|
-
|
|
24
|
-
|
|
40
|
+
| What happened | What to document |
|
|
41
|
+
|---|---|
|
|
42
|
+
| New feature or tool | Reference page + guide if complex |
|
|
43
|
+
| Architecture change | Update architecture page + diagrams |
|
|
44
|
+
| New decision (ADR accepted) | Decision page distilled from ADR |
|
|
45
|
+
| Bug fixed | Changelog entry + update affected reference pages |
|
|
46
|
+
| Refactor | Update architecture diagrams + any affected reference pages |
|
|
47
|
+
| New convention | Update conventions/reference page |
|
|
48
|
+
| API change | Update API reference |
|
|
49
|
+
| Configuration change | Update configuration reference |
|
|
50
|
+
| Lesson learned | Will go in lessons/ during retrospective |
|
|
25
51
|
|
|
26
52
|
## Where Docs Live
|
|
27
53
|
|
|
@@ -97,16 +123,75 @@ flowchart TD
|
|
|
97
123
|
|
|
98
124
|
**Never** use bare ` ```mermaid ` blocks without the wrapper. The diagrams are often too small to read inline, and the FullscreenDiagram gives users zoom and pan controls.
|
|
99
125
|
|
|
126
|
+
## Two Documentation Layers
|
|
127
|
+
|
|
128
|
+
### Standard Documentation (always)
|
|
129
|
+
|
|
130
|
+
What was built, how it works, why it's designed this way. This is the reference someone reads to understand the system. Exists regardless of mode.
|
|
131
|
+
|
|
132
|
+
### Learning Journal (teach mode only)
|
|
133
|
+
|
|
134
|
+
When running in teach mode (`/work teach`), documentation gains a second layer: **what we learned building it**. This captures:
|
|
135
|
+
|
|
136
|
+
- What surprised us during implementation
|
|
137
|
+
- Why we chose this approach over the alternatives we considered
|
|
138
|
+
- What was harder or easier than expected
|
|
139
|
+
- Conceptual connections — "this pattern is similar to X because..."
|
|
140
|
+
- What we'd do differently next time
|
|
141
|
+
|
|
142
|
+
Learning journal entries go in `apps/indusk-docs/src/lessons/` as standalone pages, or as `## What We Learned` sections within existing guide pages. They're written in first person and read like a developer's notebook — not formal reference docs.
|
|
143
|
+
|
|
144
|
+
In teach mode, every Document gate should produce both:
|
|
145
|
+
1. **Standard docs** — reference/guide updates (same as normal mode)
|
|
146
|
+
2. **Learning entry** — what the developer should take away from this phase
|
|
147
|
+
|
|
148
|
+
The learning journal is what makes teach mode more than just "go slow." It builds a permanent record of understanding alongside the permanent record of what was built.
|
|
149
|
+
|
|
150
|
+
## Documentation by Workflow Type
|
|
151
|
+
|
|
152
|
+
The depth varies by workflow type, but every workflow produces documentation.
|
|
153
|
+
|
|
154
|
+
### Feature (full documentation)
|
|
155
|
+
|
|
156
|
+
A feature is new functionality. It gets the full treatment:
|
|
157
|
+
- Write new reference pages for tools, APIs, or configuration added
|
|
158
|
+
- Write guide pages for workflows introduced
|
|
159
|
+
- Create Mermaid diagrams for architecture, flows, and relationships
|
|
160
|
+
- Update existing pages that reference the area you changed
|
|
161
|
+
- Add a changelog entry describing the feature
|
|
162
|
+
- If an ADR was accepted, create a decision page in `decisions/`
|
|
163
|
+
|
|
164
|
+
### Refactor (update existing docs)
|
|
165
|
+
|
|
166
|
+
A refactor restructures existing code. The docs must reflect the new reality:
|
|
167
|
+
- Update existing pages that reference moved/renamed code
|
|
168
|
+
- Update architecture diagrams to show the new structure
|
|
169
|
+
- Add a changelog entry explaining what was restructured and why
|
|
170
|
+
- If the refactor changes how developers interact with the code, update the relevant guide
|
|
171
|
+
|
|
172
|
+
### Bugfix (document the fix)
|
|
173
|
+
|
|
174
|
+
A bugfix solves a specific problem. Even small fixes leave a paper trail:
|
|
175
|
+
- Add a changelog entry describing the bug and the fix
|
|
176
|
+
- Update any docs that described the broken behavior
|
|
177
|
+
- If the bug revealed a gotcha, add it to the relevant reference page
|
|
178
|
+
- If the fix changes a public API or configuration, update that reference page
|
|
179
|
+
|
|
100
180
|
## Shaping Impl Documents
|
|
101
181
|
|
|
102
|
-
When writing an impl (via the plan skill), every phase
|
|
182
|
+
When writing an impl (via the plan skill), every phase gets a Document section:
|
|
103
183
|
|
|
104
184
|
```markdown
|
|
105
185
|
#### Phase N Document
|
|
106
186
|
- [ ] {Specific docs page to write or update}
|
|
187
|
+
- [ ] {Changelog entry}
|
|
107
188
|
```
|
|
108
189
|
|
|
109
|
-
The agent writing the impl must answer: **"What
|
|
190
|
+
The agent writing the impl must answer: **"What should a developer reading the docs learn from what this phase built?"**
|
|
191
|
+
|
|
192
|
+
Every phase should produce at minimum a changelog entry. Beyond that, consider: does this phase add, change, or remove something that appears in the docs? If yes, list the specific pages to create or update.
|
|
193
|
+
|
|
194
|
+
The `gate_policy` setting controls whether `(none needed)` is acceptable — in `strict` mode it is not. In `ask` mode, the agent must justify and get user approval before opting out. See the work skill for details.
|
|
110
195
|
|
|
111
196
|
### Document Items Are Blocking
|
|
112
197
|
|
|
@@ -118,37 +203,18 @@ implementation items → verification items → context items → document items
|
|
|
118
203
|
|
|
119
204
|
A phase is not complete until its document items are done.
|
|
120
205
|
|
|
121
|
-
## LLM-Readable
|
|
122
|
-
|
|
123
|
-
Every documentation page you create must have a corresponding **llms.txt** companion file. This makes the docs easy for AI agents to consume directly without HTML parsing.
|
|
124
|
-
|
|
125
|
-
### How It Works
|
|
126
|
-
|
|
127
|
-
For every page at `apps/indusk-docs/src/{path}.md`, create a matching file at `apps/indusk-docs/public/llms/{path}.txt`.
|
|
128
|
-
|
|
129
|
-
```
|
|
130
|
-
apps/indusk-docs/src/reference/skills/plan.md → apps/indusk-docs/public/llms/reference/skills/plan.txt
|
|
131
|
-
apps/indusk-docs/src/guide/getting-started.md → apps/indusk-docs/public/llms/guide/getting-started.txt
|
|
132
|
-
apps/indusk-docs/src/reference/tools/indusk-mcp.md → apps/indusk-docs/public/llms/reference/tools/indusk-mcp.txt
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Content Rules
|
|
136
|
-
|
|
137
|
-
The llms.txt file should contain the **same content** as the markdown page, with these adjustments:
|
|
138
|
-
|
|
139
|
-
- Strip Mermaid diagram blocks and FullscreenDiagram wrappers (diagrams aren't useful as text)
|
|
140
|
-
- Keep all tables, code blocks, headings, and prose
|
|
141
|
-
- Keep all examples — these are the most valuable part for LLMs
|
|
142
|
-
- Add a header line: `# {Page Title} — LLM-readable version`
|
|
143
|
-
- Add a source line: `Source: {relative path to the .md file}`
|
|
206
|
+
## LLM-Readable Output (llms.txt)
|
|
144
207
|
|
|
145
|
-
|
|
208
|
+
The docs site auto-generates LLM-friendly content via `vitepress-plugin-llms`. No manual work needed.
|
|
146
209
|
|
|
147
|
-
|
|
210
|
+
At build time, the plugin produces:
|
|
211
|
+
- `/llms.txt` — index with links to all pages (for LLM navigation)
|
|
212
|
+
- `/llms-full.txt` — entire docs concatenated into one markdown file (for full ingestion)
|
|
213
|
+
- Per-page `.md` files accessible directly
|
|
148
214
|
|
|
149
|
-
|
|
215
|
+
This follows the [llms.txt convention](https://llmstxt.org/) used by Vite, Vue.js, Vitest, Stripe, and Cloudflare.
|
|
150
216
|
|
|
151
|
-
|
|
217
|
+
**Do not** manually create llms.txt files — the plugin handles everything.
|
|
152
218
|
|
|
153
219
|
## Running the Docs Site
|
|
154
220
|
|
|
@@ -162,7 +228,10 @@ pnpm turbo build --filter=indusk-docs
|
|
|
162
228
|
|
|
163
229
|
## Important
|
|
164
230
|
|
|
165
|
-
- Documentation is
|
|
166
|
-
-
|
|
231
|
+
- **Documentation is the project's permanent record.** It outlives conversations, planning docs, and even the code itself. Write it like someone will read it a year from now with no other context.
|
|
232
|
+
- **Documentation is human-facing. CLAUDE.md is agent-facing.** They serve different audiences. CLAUDE.md helps the agent work. Docs help humans understand.
|
|
233
|
+
- **The existence of information elsewhere does not replace documentation.** ADRs, CLAUDE.md, planning docs, and code comments are working artifacts. Documentation is the polished, organized, permanent version.
|
|
234
|
+
- **Every plan contributes to documentation.** Features add pages. Refactors update pages. Bugfixes add changelog entries. There is no plan that produces zero documentation.
|
|
167
235
|
- Keep reference pages focused and scannable. Use tables and diagrams over paragraphs.
|
|
168
|
-
- The `decisions/` and `lessons/` sections are populated during retrospective
|
|
236
|
+
- The `decisions/` and `lessons/` sections are populated during retrospective, but decision pages can also be created during impl when an ADR is accepted.
|
|
237
|
+
- When in doubt, document more, not less. Excess documentation can be trimmed. Missing documentation is invisible.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: onboard
|
|
3
|
+
description: Get a new agent caught up on the project. Reads context, plans, lessons, and code graph health in one shot. Run at the start of every new session.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are starting a new session on this project. Before doing anything else, get caught up.
|
|
7
|
+
|
|
8
|
+
## Steps (execute in order)
|
|
9
|
+
|
|
10
|
+
### 1. Read Lessons
|
|
11
|
+
Call `list_lessons`. Read every lesson. These are rules learned from past mistakes — not suggestions. Internalize them before touching any code.
|
|
12
|
+
|
|
13
|
+
### 2. Check Infrastructure
|
|
14
|
+
Call `check_health`. Verify FalkorDB and CGC are running. If unhealthy, tell the user what's down and how to fix it.
|
|
15
|
+
|
|
16
|
+
### 3. Read Project Context
|
|
17
|
+
Call `get_context` to read CLAUDE.md. This contains:
|
|
18
|
+
- **Architecture** — what the project is, how it's structured
|
|
19
|
+
- **Conventions** — rules to follow (commit style, no DB from Next.js, no fallback URLs, etc.)
|
|
20
|
+
- **Key Decisions** — ADRs that have been accepted (with links)
|
|
21
|
+
- **Known Gotchas** — things that will bite you if you don't know about them
|
|
22
|
+
- **Current State** — what's been built, what's working, what's in progress
|
|
23
|
+
|
|
24
|
+
Read it fully. Don't skim.
|
|
25
|
+
|
|
26
|
+
### 4. Check Active Plans
|
|
27
|
+
Call `list_plans`. This shows every plan and its status. Pay attention to:
|
|
28
|
+
- Plans with status `in-progress` — these are actively being worked on
|
|
29
|
+
- The current phase of each active plan — this is where `/work` will pick up
|
|
30
|
+
- Dependencies between plans — don't start a blocked plan
|
|
31
|
+
|
|
32
|
+
### 5. Check Code Graph
|
|
33
|
+
Call `get_repository_stats` to understand the codebase size and structure. This gives you a sense of what's indexed and queryable.
|
|
34
|
+
|
|
35
|
+
### 6. Summarize
|
|
36
|
+
|
|
37
|
+
After completing steps 1-5, present a brief summary to the user:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
**Session ready.**
|
|
41
|
+
- Lessons: N loaded
|
|
42
|
+
- Infrastructure: [healthy / issues]
|
|
43
|
+
- Active plans: [list with current phase]
|
|
44
|
+
- Codebase: [N files indexed]
|
|
45
|
+
|
|
46
|
+
Ready to work. What would you like to do?
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## When to Use
|
|
50
|
+
|
|
51
|
+
- Start of every new Claude Code session
|
|
52
|
+
- When the user says "get caught up", "what's going on", "where are we"
|
|
53
|
+
- When context was compressed and you need to re-orient
|
|
54
|
+
- `/onboard` explicitly
|
|
55
|
+
|
|
56
|
+
## Important
|
|
57
|
+
|
|
58
|
+
- Do NOT skip any step. Each one prevents a class of mistake.
|
|
59
|
+
- Do NOT start coding before completing onboarding. The lessons and context exist because of past failures.
|
|
60
|
+
- If CLAUDE.md seems outdated, flag it to the user — it may need a `/context` update.
|
|
61
|
+
- If a plan's impl has unchecked items from a previous session, that's where `/work` picks up. Don't re-do completed work.
|
package/skills/plan.md
CHANGED
|
@@ -49,7 +49,14 @@ Workflow templates are in `templates/workflows/` in the package. They describe w
|
|
|
49
49
|
|
|
50
50
|
2. **Figure out where things stand.** If a plan folder already exists, read what's there. Check frontmatter statuses. The next document to write is the first one that's missing or incomplete.
|
|
51
51
|
|
|
52
|
-
3. **If starting fresh**,
|
|
52
|
+
3. **If starting fresh**, do a quick scan of the project (read CLAUDE.md, check the code graph) to understand the context. Then **ask the user discovery questions before doing any research or writing any documents.** The goal is to understand what they're trying to achieve, not just what they named the plan. Good discovery questions:
|
|
53
|
+
- "What problem are you trying to solve?" or "What should this feature do for your users?"
|
|
54
|
+
- "Is there anything specific you've already thought through or have strong opinions about?"
|
|
55
|
+
- "Are there any constraints I should know about — timeline, technology preferences, things to avoid?"
|
|
56
|
+
|
|
57
|
+
For non-developers especially, this conversation is critical. They may not know the right technical terms, but they know what they want. Draw that out before proceeding.
|
|
58
|
+
|
|
59
|
+
Once you understand the intent, create the plan folder and start with the first document for the workflow type:
|
|
53
60
|
- **feature**: start with research
|
|
54
61
|
- **bugfix**: start with brief (streamlined template)
|
|
55
62
|
- **refactor**: start with brief (includes boundary map)
|
|
@@ -62,12 +69,29 @@ Workflow templates are in `templates/workflows/` in the package. They describe w
|
|
|
62
69
|
- Include the graph findings in research.md — concrete numbers like "X has 12 dependents across 3 apps"
|
|
63
70
|
Document what you find. The research doc records findings and analysis, but saves the recommendation for the brief.
|
|
64
71
|
|
|
65
|
-
4. **If research is done**, write the brief. This is where a direction emerges from the research. The brief proposes what we're building and why, informed by what the research uncovered. Present
|
|
72
|
+
4. **If research is done**, write the brief. This is where a direction emerges from the research. The brief proposes what we're building and why, informed by what the research uncovered. **Present the brief and have a conversation about it.** Don't just ask "does this look good?" — walk the user through it: "Here's what I'm proposing we build. Does this match what you had in mind? Is there anything missing, or anything here you don't want?" Iterate until the user is genuinely happy with the direction, then mark it as `accepted`.
|
|
66
73
|
|
|
67
74
|
5. **If brief is accepted** and the workflow includes an ADR (feature only), write the ADR. The ADR formalizes the decisions that were discussed during research and led to the brief. It records what was chosen, what was rejected, and why. **After the ADR is accepted**, add a one-liner to CLAUDE.md's Key Decisions section per the context skill: `- {decision summary} — see planning/{plan}/adr.md`
|
|
68
75
|
|
|
69
76
|
6. **If ADR is accepted** (or brief is accepted for bugfix/refactor), write the impl. Break into phased checklists with concrete tasks. For refactor workflows, include a `## Boundary Map` section. For multi-phase impls of any type, consider adding a boundary map.
|
|
70
77
|
|
|
78
|
+
**Gate policy applies when writing impls.** The same `gate_policy` (strict/ask/auto) that governs work execution also governs how the impl is written:
|
|
79
|
+
|
|
80
|
+
- **`strict`**: Every phase MUST have all four sections (implementation, verification, context, document) with real items. No `(none needed)` or `skip-reason:`. If a section genuinely doesn't apply, you still must include it with a concrete item.
|
|
81
|
+
- **`ask`** (default): Every phase MUST have all required sections (per workflow type). If you think a section should be `(none needed)`, ask the user: "Phase 3 Document — I don't think this phase changes anything user-facing. Can I mark it (none needed)?" Only mark it after approval.
|
|
82
|
+
- **`auto`**: Include all sections, but you can use `(none needed)` or `skip-reason:` based on your judgment without asking.
|
|
83
|
+
|
|
84
|
+
Set the policy in the impl frontmatter:
|
|
85
|
+
```yaml
|
|
86
|
+
---
|
|
87
|
+
title: "My Plan"
|
|
88
|
+
gate_policy: ask
|
|
89
|
+
workflow: feature
|
|
90
|
+
---
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The `validate-impl-structure` hook enforces this at write time — it will block the impl if sections are missing for the workflow type.
|
|
94
|
+
|
|
71
95
|
7. **If impl is completed** (all items checked off by `/work`), invoke the retrospective skill (`/retrospective {plan-name}`). This handles the structured audit (docs, tests, quality, context), knowledge handoff to the docs site, and archival. Do not write a freeform retrospective — use the skill. (Bugfix and refactor workflows may skip retrospective for small changes — user's call.)
|
|
72
96
|
|
|
73
97
|
8. **Always present each document for review** before moving to the next stage. The user signs off on each step.
|
package/skills/work.md
CHANGED
|
@@ -61,6 +61,54 @@ Implementation plans live in `planning/{plan-name}/impl.md` as checklists. Your
|
|
|
61
61
|
|
|
62
62
|
A phase is not complete until all four are done. **Enforced by hooks:** if you try to check off a Phase N+1 implementation item while Phase N has unchecked gates, the edit will be blocked with a message listing what's missing. Complete the gates first.
|
|
63
63
|
|
|
64
|
+
## Gate Override Policy
|
|
65
|
+
|
|
66
|
+
Gates exist to prevent skipping important work. But sometimes a gate genuinely doesn't apply. The override policy controls what happens when the agent wants to skip a gate item.
|
|
67
|
+
|
|
68
|
+
Three modes, configured via `gate_policy` in the impl frontmatter or `.claude/settings.json`:
|
|
69
|
+
|
|
70
|
+
| Mode | Behavior |
|
|
71
|
+
|------|----------|
|
|
72
|
+
| **`strict`** | No overrides. Every gate item must be completed. `(none needed)` and `skip-reason:` are not accepted. Use for critical work where nothing should be skipped. |
|
|
73
|
+
| **`ask`** (default) | Agent must ask the user before skipping any gate item. The agent explains why it wants to skip and waits for approval. Only after the user says yes can it mark with `skip-reason:`. |
|
|
74
|
+
| **`auto`** | Agent can skip with `skip-reason:` without asking. Use when running autonomously or when you trust the agent's judgment. |
|
|
75
|
+
|
|
76
|
+
### How to set the mode
|
|
77
|
+
|
|
78
|
+
**Per-plan** (in impl frontmatter):
|
|
79
|
+
```yaml
|
|
80
|
+
---
|
|
81
|
+
title: "My Plan"
|
|
82
|
+
gate_policy: strict
|
|
83
|
+
---
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Per-project** (in `.claude/settings.json`):
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"indusk": {
|
|
90
|
+
"gate_policy": "ask"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Per-invocation**: `/work --strict`, `/work --ask`, `/work --auto`
|
|
96
|
+
|
|
97
|
+
Priority: per-invocation > per-plan > per-project > default (`ask`).
|
|
98
|
+
|
|
99
|
+
### What "ask" mode looks like
|
|
100
|
+
|
|
101
|
+
When the agent encounters a gate item it thinks should be skipped:
|
|
102
|
+
|
|
103
|
+
> "Phase 2 has a Document gate: 'Write reference page for the new API.' I don't think this phase needs a new docs page because we only changed internal implementation — the public API didn't change. Can I mark this as `skip-reason: internal change, no public API change`?"
|
|
104
|
+
|
|
105
|
+
The user can say:
|
|
106
|
+
- **"yes"** — agent marks it with skip-reason and continues
|
|
107
|
+
- **"no, do it"** — agent completes the gate item
|
|
108
|
+
- **"no, but mark it (none needed)"** — if the gate truly doesn't apply
|
|
109
|
+
|
|
110
|
+
**The agent must NEVER skip a gate without asking in `ask` mode.** This is the core enforcement. The hooks block unauthorized skips, and the skill enforces the conversation.
|
|
111
|
+
|
|
64
112
|
11. **Verification items.** The Verification section requires proof, not assumption. See the verify skill for full guidance.
|
|
65
113
|
- Run checks in order: type check → lint → affected tests → build. Skip checks that don't apply (see verify skill's skip logic table).
|
|
66
114
|
- Run commands and capture output — verification items must be specific runnable commands, not "verify it works"
|
|
@@ -91,6 +139,8 @@ When invoked as `/work teach` or `/work --teach {plan}`, slow down to a mentorin
|
|
|
91
139
|
|
|
92
140
|
### Before each edit:
|
|
93
141
|
|
|
142
|
+
**Where we are:** State the current position in the system — which plan, which phase, which gate (implementation/verification/context/document), and why this gate exists. Example: "We're in Phase 3 of the auth-system plan, working through implementation items. After these, we'll verify with type checks and tests, then update CLAUDE.md with what changed, then document it. That's the four-gate cycle that every phase goes through."
|
|
143
|
+
|
|
94
144
|
**Why this change:** Explain what you're about to modify and why. Reference the plan, the architecture, and the reasoning. Use plain language.
|
|
95
145
|
|
|
96
146
|
Then **stop and wait** for the user to say "continue" before making the edit.
|
|
@@ -103,15 +153,33 @@ Then **stop and wait** for the user to say "continue" before making the edit.
|
|
|
103
153
|
|
|
104
154
|
Then **stop and wait** for the user to say "continue" before moving to the next item.
|
|
105
155
|
|
|
156
|
+
### At gate transitions:
|
|
157
|
+
|
|
158
|
+
When moving from implementation to verification, or verification to context, or context to document — explain the transition and why this gate exists:
|
|
159
|
+
|
|
160
|
+
- **Implementation → Verification:** "The code is written. Now we prove it works. The verify skill says to run checks fastest-first: type check, lint, tests, build. This catches errors before they compound."
|
|
161
|
+
- **Verification → Context:** "Everything passes. Now we update CLAUDE.md so the next session knows what changed. Context is how the project remembers — without it, the next agent starts from scratch."
|
|
162
|
+
- **Context → Document:** "CLAUDE.md is updated. Now we write or update the project's documentation — the encyclopedia that any developer can read to understand what was built and why. In teach mode, we also write a learning entry: what surprised us, what we'd do differently, what conceptual connections to notice."
|
|
163
|
+
- **Phase complete → Next phase:** "All four gates passed for Phase N. The hook would have blocked us if we'd tried to skip any. Now Phase N+1 builds on what Phase N produced — here's what the boundary map says it needs..."
|
|
164
|
+
|
|
106
165
|
### Between checklist items:
|
|
107
166
|
|
|
108
|
-
Summarize what was accomplished and preview the next item. Explain how they connect.
|
|
167
|
+
Summarize what was accomplished and preview the next item. Explain how they connect — both in terms of the feature being built and the InDusk system driving the process.
|
|
168
|
+
|
|
169
|
+
### Document gate in teach mode:
|
|
170
|
+
|
|
171
|
+
In teach mode, every Document gate produces two things:
|
|
172
|
+
1. **Standard docs** — the same reference/guide updates you'd write in normal mode
|
|
173
|
+
2. **Learning entry** — what the developer should take away from this phase: what surprised us, what we chose and why, what conceptual connections to notice
|
|
174
|
+
|
|
175
|
+
See the document skill's "Two Documentation Layers" section for details. The learning journal is what makes teach mode a teaching tool, not just a slow mode.
|
|
109
176
|
|
|
110
177
|
### Important for teach mode:
|
|
111
178
|
|
|
112
179
|
- Never batch multiple edits between pauses
|
|
113
180
|
- Use clear headings to separate teaching from doing
|
|
114
181
|
- If the user asks a question, answer it fully before continuing
|
|
182
|
+
- Always give both layers: the **what** (the feature/code) and the **why** (the InDusk system's reasoning)
|
|
115
183
|
- Normal `/work` (without teach) remains unchanged — fast execution, no pauses
|
|
116
184
|
|
|
117
185
|
## Corrections and Context Learning
|