guild-agents 1.1.0 → 1.3.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.
- package/README.md +8 -1
- package/bin/guild.js +84 -0
- package/package.json +5 -2
- package/src/commands/init.js +8 -1
- package/src/commands/workspace.js +92 -0
- package/src/templates/skills/build-feature/evals/evals.json +53 -0
- package/src/templates/skills/council/SKILL.md +27 -6
- package/src/templates/skills/council/evals/evals.json +41 -0
- package/src/templates/skills/debug/SKILL.md +145 -0
- package/src/templates/skills/guild-specialize/SKILL.md +20 -0
- package/src/templates/skills/re-specialize/SKILL.md +153 -0
- package/src/templates/skills/tdd/SKILL.md +159 -0
- package/src/templates/skills/verify/SKILL.md +114 -0
- package/src/utils/eval-runner.js +139 -0
- package/src/utils/generators.js +11 -9
- package/src/utils/workspace.js +171 -0
- package/src/utils/zones.js +39 -0
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ Six phases: **evaluate**, **specify**, **plan**, **implement**, **review**, **va
|
|
|
62
62
|
|
|
63
63
|
## Skills Reference
|
|
64
64
|
|
|
65
|
-
All
|
|
65
|
+
All 15 skills, grouped by function:
|
|
66
66
|
|
|
67
67
|
| Skill | Group | Description |
|
|
68
68
|
| --- | --- | --- |
|
|
@@ -72,7 +72,11 @@ All 11 skills, grouped by function:
|
|
|
72
72
|
| `/council` | Decision | Multi-perspective deliberation on a decision or feature |
|
|
73
73
|
| `/review` | Quality | Code review on the current diff |
|
|
74
74
|
| `/qa-cycle` | Quality | QA and bugfix loop until clean |
|
|
75
|
+
| `/tdd` | Discipline | TDD red-green-refactor cycle |
|
|
76
|
+
| `/debug` | Discipline | Systematic 4-phase debugging |
|
|
77
|
+
| `/verify` | Discipline | Evidence-before-claims verification |
|
|
75
78
|
| `/guild-specialize` | Context | Explore codebase, enrich CLAUDE.md with real conventions |
|
|
79
|
+
| `/re-specialize` | Context | Incremental update of auto-generated CLAUDE.md zones |
|
|
76
80
|
| `/session-start` | Context | Load context and resume work |
|
|
77
81
|
| `/session-end` | Context | Save state to SESSION.md |
|
|
78
82
|
| `/status` | Context | Project and session state overview |
|
|
@@ -89,6 +93,9 @@ guild list # List agents and skills
|
|
|
89
93
|
guild run <skill> # Preview a skill's execution plan (dry-run)
|
|
90
94
|
guild logs # View execution traces
|
|
91
95
|
guild logs clean # Remove old traces (--days N, --all)
|
|
96
|
+
guild workspace init <name> <members...> # Create a workspace
|
|
97
|
+
guild workspace add <path> # Add a member repo
|
|
98
|
+
guild workspace status # Show workspace state
|
|
92
99
|
```
|
|
93
100
|
|
|
94
101
|
## Under the Hood
|
package/bin/guild.js
CHANGED
|
@@ -168,4 +168,88 @@ logsCmd
|
|
|
168
168
|
}
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
+
// guild workspace
|
|
172
|
+
const workspaceCmd = program
|
|
173
|
+
.command('workspace')
|
|
174
|
+
.description('Manage multi-repo workspaces');
|
|
175
|
+
|
|
176
|
+
// guild workspace init
|
|
177
|
+
workspaceCmd
|
|
178
|
+
.command('init')
|
|
179
|
+
.description('Initialize a workspace in the current directory')
|
|
180
|
+
.argument('<name>', 'Workspace name')
|
|
181
|
+
.argument('<members...>', 'Paths to member repos (e.g., ./backend ./frontend)')
|
|
182
|
+
.action(async (name, members) => {
|
|
183
|
+
try {
|
|
184
|
+
const { createWorkspaceFile } = await import('../src/commands/workspace.js');
|
|
185
|
+
await createWorkspaceFile(name, members);
|
|
186
|
+
console.log(`Workspace "${name}" created with ${members.length} member(s).`);
|
|
187
|
+
} catch (err) {
|
|
188
|
+
console.error(err.message);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// guild workspace add
|
|
194
|
+
workspaceCmd
|
|
195
|
+
.command('add')
|
|
196
|
+
.description('Add a member repo to the workspace')
|
|
197
|
+
.argument('<path>', 'Path to the member repo')
|
|
198
|
+
.action(async (memberPath) => {
|
|
199
|
+
try {
|
|
200
|
+
const { addWorkspaceMember } = await import('../src/commands/workspace.js');
|
|
201
|
+
await addWorkspaceMember(memberPath);
|
|
202
|
+
console.log(`Added "${memberPath}" to workspace.`);
|
|
203
|
+
} catch (err) {
|
|
204
|
+
console.error(err.message);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// guild workspace status
|
|
210
|
+
workspaceCmd
|
|
211
|
+
.command('status')
|
|
212
|
+
.description('Show workspace members and their state')
|
|
213
|
+
.action(async () => {
|
|
214
|
+
try {
|
|
215
|
+
const { getWorkspaceStatus } = await import('../src/commands/workspace.js');
|
|
216
|
+
const status = await getWorkspaceStatus();
|
|
217
|
+
console.log(`Workspace: ${status.name}`);
|
|
218
|
+
for (const m of status.members) {
|
|
219
|
+
const state = m.initialized ? 'initialized' : 'not initialized';
|
|
220
|
+
console.log(` ${m.name} (${m.path}) — ${state}`);
|
|
221
|
+
}
|
|
222
|
+
} catch (err) {
|
|
223
|
+
console.error(err.message);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// guild workspace run
|
|
229
|
+
workspaceCmd
|
|
230
|
+
.command('run')
|
|
231
|
+
.description('Run a command in a workspace member repo')
|
|
232
|
+
.argument('[member]', 'Member name (or omit with --all)')
|
|
233
|
+
.argument('[preset]', 'Preset command: test, lint, build')
|
|
234
|
+
.option('--cmd <command>', 'Custom command to run')
|
|
235
|
+
.option('--all', 'Run in all workspace members')
|
|
236
|
+
.action(async (member, preset, options) => {
|
|
237
|
+
try {
|
|
238
|
+
const { runWorkspaceCommand } = await import('../src/commands/workspace.js');
|
|
239
|
+
const results = runWorkspaceCommand(member, preset, options);
|
|
240
|
+
for (const r of results) {
|
|
241
|
+
const icon = r.status === 'passed' ? '\u2705' : '\u274C';
|
|
242
|
+
console.log(`${icon} ${r.member}: ${r.status} (${r.duration}ms)`);
|
|
243
|
+
if (r.status === 'failed' && r.output) {
|
|
244
|
+
console.log(r.output);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const failed = results.filter(r => r.status === 'failed');
|
|
248
|
+
if (failed.length > 0) process.exit(1);
|
|
249
|
+
} catch (err) {
|
|
250
|
+
console.error(err.message);
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
171
255
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guild-agents",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Specification-driven development CLI for Claude Code — think before you build",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
"publish:snapshot": "npm run version:snapshot && npm publish --tag snapshot",
|
|
29
29
|
"publish:beta": "npm run version:beta && npm publish --tag beta",
|
|
30
30
|
"publish:stable": "npm run version:stable && npm publish --tag latest",
|
|
31
|
-
"publish:promote-beta": "npm dist-tag add guild-agents@$(node --input-type=commonjs -p \"require('./package.json').version\") beta"
|
|
31
|
+
"publish:promote-beta": "npm dist-tag add guild-agents@$(node --input-type=commonjs -p \"require('./package.json').version\") beta",
|
|
32
|
+
"eval": "node scripts/run-evals.js",
|
|
33
|
+
"eval:build-feature": "node scripts/run-evals.js build-feature",
|
|
34
|
+
"eval:council": "node scripts/run-evals.js council"
|
|
32
35
|
},
|
|
33
36
|
"keywords": [
|
|
34
37
|
"claude",
|
package/src/commands/init.js
CHANGED
|
@@ -14,11 +14,18 @@ import chalk from 'chalk';
|
|
|
14
14
|
import { existsSync } from 'fs';
|
|
15
15
|
import { generateProjectMd, generateSessionMd, generateClaudeMd } from '../utils/generators.js';
|
|
16
16
|
import { copyTemplates, getAgentNames, getSkillNames } from '../utils/files.js';
|
|
17
|
+
import { loadWorkspace } from '../utils/workspace.js';
|
|
17
18
|
|
|
18
19
|
export async function runInit() {
|
|
19
20
|
console.log('');
|
|
20
21
|
p.intro(chalk.bold.cyan('Guild v1 — New project'));
|
|
21
22
|
|
|
23
|
+
// Detect workspace membership
|
|
24
|
+
const workspace = loadWorkspace();
|
|
25
|
+
if (workspace) {
|
|
26
|
+
p.log.info(chalk.gray(`Workspace detected: ${workspace.name} (${workspace.root})`));
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
// Check for existing installation
|
|
23
30
|
if (existsSync('.claude/agents')) {
|
|
24
31
|
const overwrite = await p.confirm({
|
|
@@ -107,7 +114,7 @@ export async function runInit() {
|
|
|
107
114
|
try {
|
|
108
115
|
await copyTemplates();
|
|
109
116
|
spinner.message('Generating CLAUDE.md...');
|
|
110
|
-
await generateClaudeMd(projectData);
|
|
117
|
+
await generateClaudeMd(projectData, workspace, name);
|
|
111
118
|
|
|
112
119
|
spinner.message('Generating PROJECT.md...');
|
|
113
120
|
await generateProjectMd(projectData);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { basename, join } from 'path';
|
|
3
|
+
import { findWorkspaceRoot, loadWorkspace, runInMember, PRESET_COMMANDS, WORKSPACE_FILE } from '../utils/workspace.js';
|
|
4
|
+
|
|
5
|
+
export async function createWorkspaceFile(name, memberPaths) {
|
|
6
|
+
const members = memberPaths.map(p => ({
|
|
7
|
+
name: basename(p),
|
|
8
|
+
path: p,
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const config = {
|
|
12
|
+
name,
|
|
13
|
+
members,
|
|
14
|
+
shared: {
|
|
15
|
+
agents: '.guild/agents',
|
|
16
|
+
skills: '.guild/skills',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
writeFileSync(WORKSPACE_FILE, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
21
|
+
mkdirSync(join('.guild', 'agents'), { recursive: true });
|
|
22
|
+
mkdirSync(join('.guild', 'skills'), { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function addWorkspaceMember(memberPath) {
|
|
26
|
+
const root = findWorkspaceRoot();
|
|
27
|
+
if (!root) throw new Error('No workspace found. Run `guild workspace init` first.');
|
|
28
|
+
|
|
29
|
+
const filePath = join(root, WORKSPACE_FILE);
|
|
30
|
+
const config = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
31
|
+
const name = basename(memberPath);
|
|
32
|
+
|
|
33
|
+
if (config.members.some(m => m.path === memberPath || m.name === name)) {
|
|
34
|
+
throw new Error(`"${name}" is already a member of this workspace.`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
config.members.push({ name, path: memberPath });
|
|
38
|
+
writeFileSync(filePath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function runWorkspaceCommand(memberName, preset, options) {
|
|
42
|
+
const workspace = loadWorkspace();
|
|
43
|
+
if (!workspace) throw new Error('No workspace found. Run `guild workspace init` first.');
|
|
44
|
+
|
|
45
|
+
// Resolve command
|
|
46
|
+
let cmd, args;
|
|
47
|
+
if (options.cmd) {
|
|
48
|
+
const parts = options.cmd.split(/\s+/);
|
|
49
|
+
cmd = parts[0];
|
|
50
|
+
args = parts.slice(1);
|
|
51
|
+
} else if (preset && PRESET_COMMANDS[preset]) {
|
|
52
|
+
({ cmd, args } = PRESET_COMMANDS[preset]);
|
|
53
|
+
} else {
|
|
54
|
+
throw new Error(`Unknown command: "${preset}". Use test, lint, build, or --cmd "...".`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Resolve members
|
|
58
|
+
let targets;
|
|
59
|
+
if (options.all) {
|
|
60
|
+
targets = workspace.members;
|
|
61
|
+
} else {
|
|
62
|
+
const member = workspace.members.find(m => m.name === memberName);
|
|
63
|
+
if (!member) {
|
|
64
|
+
const available = workspace.members.map(m => m.name).join(', ');
|
|
65
|
+
throw new Error(`Member "${memberName}" not found. Available: ${available}`);
|
|
66
|
+
}
|
|
67
|
+
targets = [member];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Execute sequentially, collect all
|
|
71
|
+
const results = [];
|
|
72
|
+
for (const target of targets) {
|
|
73
|
+
results.push(runInMember(target, cmd, args));
|
|
74
|
+
}
|
|
75
|
+
return results;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function getWorkspaceStatus() {
|
|
79
|
+
const root = findWorkspaceRoot();
|
|
80
|
+
if (!root) throw new Error('No workspace found. Run `guild workspace init` first.');
|
|
81
|
+
|
|
82
|
+
const filePath = join(root, WORKSPACE_FILE);
|
|
83
|
+
const config = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
84
|
+
|
|
85
|
+
const members = config.members.map(m => {
|
|
86
|
+
const absPath = join(root, m.path);
|
|
87
|
+
const initialized = existsSync(join(absPath, '.claude'));
|
|
88
|
+
return { ...m, absolutePath: absPath, initialized };
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return { name: config.name, root, members };
|
|
92
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "build-feature",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": "bf-has-core-phases",
|
|
6
|
+
"description": "Plan contains evaluate, specify, design, implement phases",
|
|
7
|
+
"expectations": [
|
|
8
|
+
{ "text": "Has evaluate step", "assertion": "step-exists:evaluate" },
|
|
9
|
+
{ "text": "Has specify step", "assertion": "step-exists:specify" },
|
|
10
|
+
{ "text": "Has design step", "assertion": "step-exists:design" },
|
|
11
|
+
{ "text": "Has implement step", "assertion": "step-exists:implement" }
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "bf-has-quality-phases",
|
|
16
|
+
"description": "Plan contains review, QA, and completion phases",
|
|
17
|
+
"expectations": [
|
|
18
|
+
{ "text": "Has review step", "assertion": "step-exists:review" },
|
|
19
|
+
{ "text": "Has QA phase", "assertion": "step-exists:qa-phase" },
|
|
20
|
+
{ "text": "Has completion step", "assertion": "step-exists:completion" }
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "bf-advisor-uses-reasoning",
|
|
25
|
+
"description": "Advisor (evaluate) uses reasoning tier",
|
|
26
|
+
"expectations": [
|
|
27
|
+
{ "text": "Evaluate uses reasoning tier", "assertion": "step-model-tier:evaluate:reasoning" }
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "bf-developer-uses-execution",
|
|
32
|
+
"description": "Developer (implement) uses execution tier",
|
|
33
|
+
"expectations": [
|
|
34
|
+
{ "text": "Implement uses execution tier", "assertion": "step-model-tier:implement:execution" }
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "bf-gates-exist",
|
|
39
|
+
"description": "Quality gates exist at pre-review and final",
|
|
40
|
+
"expectations": [
|
|
41
|
+
{ "text": "Pre-review gate exists", "assertion": "gate-exists:gate-pre-review" },
|
|
42
|
+
{ "text": "Final gate exists", "assertion": "gate-exists:gate-final" }
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "bf-minimum-steps",
|
|
47
|
+
"description": "Plan has at least 10 steps",
|
|
48
|
+
"expectations": [
|
|
49
|
+
{ "text": "At least 10 steps", "assertion": "step-count:10" }
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -11,24 +11,30 @@ workflow:
|
|
|
11
11
|
requires: [user-question]
|
|
12
12
|
produces: [council-type, participant-roles]
|
|
13
13
|
gate: true
|
|
14
|
+
- id: workspace-context
|
|
15
|
+
role: system
|
|
16
|
+
intent: "Detect workspace membership. If in a workspace, collect context from sibling repos (CLAUDE.md, PROJECT.md, SESSION.md) and build workspace context block."
|
|
17
|
+
requires: [council-type]
|
|
18
|
+
produces: [workspace-context]
|
|
19
|
+
condition: in-workspace
|
|
14
20
|
- id: agent-1
|
|
15
21
|
role: dynamic
|
|
16
22
|
intent: "Analyze the question from specialized perspective. State position with concrete arguments."
|
|
17
|
-
requires: [user-question, council-type]
|
|
23
|
+
requires: [user-question, council-type, workspace-context]
|
|
18
24
|
produces: [perspective-1]
|
|
19
25
|
model-tier: reasoning
|
|
20
26
|
parallel: [agent-2, agent-3]
|
|
21
27
|
- id: agent-2
|
|
22
28
|
role: dynamic
|
|
23
29
|
intent: "Analyze the question from specialized perspective. State position with concrete arguments."
|
|
24
|
-
requires: [user-question, council-type]
|
|
30
|
+
requires: [user-question, council-type, workspace-context]
|
|
25
31
|
produces: [perspective-2]
|
|
26
32
|
model-tier: reasoning
|
|
27
33
|
parallel: [agent-1, agent-3]
|
|
28
34
|
- id: agent-3
|
|
29
35
|
role: dynamic
|
|
30
36
|
intent: "Analyze the question from specialized perspective. State position with concrete arguments."
|
|
31
|
-
requires: [user-question, council-type]
|
|
37
|
+
requires: [user-question, council-type, workspace-context]
|
|
32
38
|
produces: [perspective-3]
|
|
33
39
|
model-tier: reasoning
|
|
34
40
|
parallel: [agent-1, agent-2]
|
|
@@ -114,12 +120,23 @@ Analyze the user's question and determine which council type applies:
|
|
|
114
120
|
|
|
115
121
|
### Step 2 — Convene agents
|
|
116
122
|
|
|
123
|
+
**Workspace detection:** Before invoking agents, check if the project is inside a workspace:
|
|
124
|
+
|
|
125
|
+
1. Look for a `guild-workspace.json` file by searching upward from the project root
|
|
126
|
+
2. If found, load the workspace config and identify which member this project is
|
|
127
|
+
3. Read CLAUDE.md, PROJECT.md, and SESSION.md from each sibling member repo
|
|
128
|
+
4. Build a workspace context block with:
|
|
129
|
+
- Workspace name
|
|
130
|
+
- Each sibling's stack, structure summary, and current task
|
|
131
|
+
- Absolute paths so the agent can read any sibling file for deeper analysis
|
|
132
|
+
|
|
117
133
|
Invoke the 3 corresponding agents IN PARALLEL using Task tool with `model: "opus"` (all council agents use reasoning tier). Each agent:
|
|
118
134
|
|
|
119
135
|
1. Reads their `.claude/agents/[name].md` file to assume their role
|
|
120
136
|
2. Reads `CLAUDE.md` and `SESSION.md` for project context
|
|
121
|
-
3.
|
|
122
|
-
4.
|
|
137
|
+
3. **If in a workspace:** receives the workspace context block and considers cross-repo impact as part of their analysis. They may read files from sibling repos using the provided paths.
|
|
138
|
+
4. Analyzes the question from their specialized perspective
|
|
139
|
+
5. States their position with concrete arguments
|
|
123
140
|
|
|
124
141
|
### Step 3 — Present debate
|
|
125
142
|
|
|
@@ -191,7 +208,11 @@ Example:
|
|
|
191
208
|
Task tool with:
|
|
192
209
|
subagent_type: "general-purpose"
|
|
193
210
|
model: "opus"
|
|
194
|
-
prompt: "Read .claude/agents/tech-lead.md and assume that role. Then: [debate question]
|
|
211
|
+
prompt: "Read .claude/agents/tech-lead.md and assume that role. Then: [debate question]
|
|
212
|
+
|
|
213
|
+
[If in workspace, append:]
|
|
214
|
+
## Workspace context
|
|
215
|
+
[workspace context block from Step 2]"
|
|
195
216
|
```
|
|
196
217
|
|
|
197
218
|
The `model` parameter is resolved from the step's `model-tier`: all council agents use reasoning→`"opus"`.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "council",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": "council-three-parallel-agents",
|
|
6
|
+
"description": "Council has 3 agent steps in parallel",
|
|
7
|
+
"expectations": [
|
|
8
|
+
{ "text": "Agent-1 exists", "assertion": "step-exists:agent-1" },
|
|
9
|
+
{ "text": "Agent-2 exists", "assertion": "step-exists:agent-2" },
|
|
10
|
+
{ "text": "Agent-3 exists", "assertion": "step-exists:agent-3" },
|
|
11
|
+
{ "text": "Agent-1 is parallel", "assertion": "step-parallel:agent-1" },
|
|
12
|
+
{ "text": "Agent-2 is parallel", "assertion": "step-parallel:agent-2" },
|
|
13
|
+
{ "text": "Agent-3 is parallel", "assertion": "step-parallel:agent-3" }
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": "council-agents-use-reasoning",
|
|
18
|
+
"description": "All council agents use reasoning tier",
|
|
19
|
+
"expectations": [
|
|
20
|
+
{ "text": "Agent-1 uses reasoning", "assertion": "step-model-tier:agent-1:reasoning" },
|
|
21
|
+
{ "text": "Agent-2 uses reasoning", "assertion": "step-model-tier:agent-2:reasoning" },
|
|
22
|
+
{ "text": "Agent-3 uses reasoning", "assertion": "step-model-tier:agent-3:reasoning" }
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "council-synthesize-gate",
|
|
27
|
+
"description": "Synthesize step exists with gate",
|
|
28
|
+
"expectations": [
|
|
29
|
+
{ "text": "Synthesize step exists", "assertion": "step-exists:synthesize" },
|
|
30
|
+
{ "text": "Synthesize has gate", "assertion": "gate-exists:synthesize" }
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "council-workspace-context",
|
|
35
|
+
"description": "Workspace context step exists with condition",
|
|
36
|
+
"expectations": [
|
|
37
|
+
{ "text": "Workspace-context step exists", "assertion": "step-exists:workspace-context" }
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debug
|
|
3
|
+
description: "Discipline skill — systematic debugging process. Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes."
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Systematic Debugging
|
|
8
|
+
|
|
9
|
+
Random fixes waste time and create new bugs. Quick patches mask underlying issues.
|
|
10
|
+
|
|
11
|
+
**Core principle:** ALWAYS find root cause before attempting fixes.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
`/debug`
|
|
16
|
+
|
|
17
|
+
Invoke this skill when encountering any bug, test failure, or unexpected behavior. Follow the four phases in order.
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
- Test failures
|
|
22
|
+
- Bugs in production
|
|
23
|
+
- Unexpected behavior
|
|
24
|
+
- Performance problems
|
|
25
|
+
- Build failures
|
|
26
|
+
- Integration issues
|
|
27
|
+
|
|
28
|
+
**Use this ESPECIALLY when:**
|
|
29
|
+
|
|
30
|
+
- Under time pressure (emergencies make guessing tempting)
|
|
31
|
+
- "Just one quick fix" seems obvious
|
|
32
|
+
- You've already tried multiple fixes
|
|
33
|
+
- Previous fix didn't work
|
|
34
|
+
|
|
35
|
+
## The Iron Law
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If you haven't completed Phase 1, you cannot propose fixes.
|
|
42
|
+
|
|
43
|
+
## The Four Phases
|
|
44
|
+
|
|
45
|
+
Complete each phase before proceeding to the next.
|
|
46
|
+
|
|
47
|
+
### Phase 1: Root Cause Investigation
|
|
48
|
+
|
|
49
|
+
**BEFORE attempting ANY fix:**
|
|
50
|
+
|
|
51
|
+
1. **Read Error Messages Carefully**
|
|
52
|
+
- Don't skip past errors or warnings
|
|
53
|
+
- Read stack traces completely
|
|
54
|
+
- Note line numbers, file paths, error codes
|
|
55
|
+
|
|
56
|
+
2. **Reproduce Consistently**
|
|
57
|
+
- Can you trigger it reliably?
|
|
58
|
+
- What are the exact steps?
|
|
59
|
+
- If not reproducible, gather more data — don't guess
|
|
60
|
+
|
|
61
|
+
3. **Check Recent Changes**
|
|
62
|
+
- What changed that could cause this?
|
|
63
|
+
- Git diff, recent commits
|
|
64
|
+
- New dependencies, config changes
|
|
65
|
+
|
|
66
|
+
4. **Gather Evidence in Multi-Component Systems**
|
|
67
|
+
- Log what data enters each component boundary
|
|
68
|
+
- Log what data exits each component boundary
|
|
69
|
+
- Verify environment/config propagation
|
|
70
|
+
- Run once to gather evidence showing WHERE it breaks
|
|
71
|
+
- THEN investigate that specific component
|
|
72
|
+
|
|
73
|
+
5. **Trace Data Flow**
|
|
74
|
+
- Where does the bad value originate?
|
|
75
|
+
- What called this with the bad value?
|
|
76
|
+
- Keep tracing up until you find the source
|
|
77
|
+
- Fix at source, not at symptom
|
|
78
|
+
|
|
79
|
+
### Phase 2: Pattern Analysis
|
|
80
|
+
|
|
81
|
+
1. **Find Working Examples** — locate similar working code in the same codebase
|
|
82
|
+
2. **Compare Against References** — read reference implementations COMPLETELY, don't skim
|
|
83
|
+
3. **Identify Differences** — list every difference between working and broken, however small
|
|
84
|
+
4. **Understand Dependencies** — what components, settings, environment does it need?
|
|
85
|
+
|
|
86
|
+
### Phase 3: Hypothesis and Testing
|
|
87
|
+
|
|
88
|
+
1. **Form Single Hypothesis** — "I think X is the root cause because Y"
|
|
89
|
+
2. **Test Minimally** — smallest possible change, one variable at a time
|
|
90
|
+
3. **Verify** — did it work? Yes = Phase 4. No = new hypothesis. DON'T stack fixes.
|
|
91
|
+
|
|
92
|
+
### Phase 4: Implementation
|
|
93
|
+
|
|
94
|
+
1. **Create Failing Test Case** — simplest possible reproduction, automated if possible. Use `/tdd` for proper failing tests.
|
|
95
|
+
2. **Implement Single Fix** — address the root cause, ONE change at a time, no "while I'm here" improvements.
|
|
96
|
+
3. **Verify Fix** — test passes? No other tests broken? Issue actually resolved? Use `/verify` before claiming done.
|
|
97
|
+
|
|
98
|
+
**If fix doesn't work:**
|
|
99
|
+
|
|
100
|
+
- If < 3 attempts: return to Phase 1, re-analyze with new information
|
|
101
|
+
- **If >= 3 attempts: STOP and question the architecture**
|
|
102
|
+
|
|
103
|
+
**3+ failed fixes indicate an architectural problem:**
|
|
104
|
+
|
|
105
|
+
- Each fix reveals new coupling in different places
|
|
106
|
+
- Fixes require massive refactoring
|
|
107
|
+
- Each fix creates new symptoms elsewhere
|
|
108
|
+
- Discuss with the user before attempting more fixes
|
|
109
|
+
|
|
110
|
+
## Red Flags - STOP and Follow Process
|
|
111
|
+
|
|
112
|
+
- "Quick fix for now, investigate later"
|
|
113
|
+
- "Just try changing X and see if it works"
|
|
114
|
+
- "Add multiple changes, run tests"
|
|
115
|
+
- "It's probably X, let me fix that"
|
|
116
|
+
- "I don't fully understand but this might work"
|
|
117
|
+
- Proposing solutions before tracing data flow
|
|
118
|
+
- "One more fix attempt" (when already tried 2+)
|
|
119
|
+
|
|
120
|
+
**ALL of these mean: STOP. Return to Phase 1.**
|
|
121
|
+
|
|
122
|
+
## Common Rationalizations
|
|
123
|
+
|
|
124
|
+
| Excuse | Reality |
|
|
125
|
+
| ----------------------------------------- | ------------------------------------------------------------------------ |
|
|
126
|
+
| "Issue is simple, don't need process" | Simple issues have root causes too. Process is fast for simple bugs. |
|
|
127
|
+
| "Emergency, no time for process" | Systematic debugging is FASTER than guess-and-check thrashing. |
|
|
128
|
+
| "Just try this first, then investigate" | First fix sets the pattern. Do it right from the start. |
|
|
129
|
+
| "I'll write test after confirming fix" | Untested fixes don't stick. Test first proves it. |
|
|
130
|
+
| "Multiple fixes at once saves time" | Can't isolate what worked. Causes new bugs. |
|
|
131
|
+
| "I see the problem, let me fix it" | Seeing symptoms is not understanding root cause. |
|
|
132
|
+
|
|
133
|
+
## Quick Reference
|
|
134
|
+
|
|
135
|
+
| Phase | Key Activities | Success Criteria |
|
|
136
|
+
| ---------------------- | ------------------------------------------------------ | --------------------------- |
|
|
137
|
+
| **1. Root Cause** | Read errors, reproduce, check changes, gather evidence | Understand WHAT and WHY |
|
|
138
|
+
| **2. Pattern** | Find working examples, compare | Identify differences |
|
|
139
|
+
| **3. Hypothesis** | Form theory, test minimally | Confirmed or new hypothesis |
|
|
140
|
+
| **4. Implementation** | Create test, fix, verify | Bug resolved, tests pass |
|
|
141
|
+
|
|
142
|
+
## Related Skills
|
|
143
|
+
|
|
144
|
+
- `/tdd` — TDD cycle for creating failing test cases in Phase 4
|
|
145
|
+
- `/verify` — verification before claiming the fix is complete
|
|
@@ -113,6 +113,13 @@ Invoke the Tech Lead agent using Task tool with `model: "opus"` (reasoning tier)
|
|
|
113
113
|
- **Visible limitations and technical debt**: outdated dependencies, TODOs found
|
|
114
114
|
- **Useful project commands**: detected npm/make/cargo scripts
|
|
115
115
|
|
|
116
|
+
CLAUDE.md now uses zone markers (`<!-- guild:auto-start:ID -->` / `<!-- guild:auto-end:ID -->`) to delimit auto-generated sections. When enriching:
|
|
117
|
+
|
|
118
|
+
- Replace content BETWEEN the markers, preserving the markers themselves
|
|
119
|
+
- The following zones exist: `structure`, `architecture`, `conventions`, `env-vars`
|
|
120
|
+
- Do NOT modify content outside of zone markers (user-owned sections)
|
|
121
|
+
- If markers are missing (legacy project), replace `[PENDING: guild-specialize]` placeholders directly
|
|
122
|
+
|
|
116
123
|
### Step 4 — Specialize agents
|
|
117
124
|
|
|
118
125
|
Invoke the Tech Lead agent using Task tool with `model: "sonnet"` (execution tier) to add project-specific context for each agent in `.claude/agents/*.md`:
|
|
@@ -127,6 +134,19 @@ Invoke the Tech Lead agent using Task tool with `model: "sonnet"` (execution tie
|
|
|
127
134
|
- **db-migration.md**: ORM, migration tool, current schema (if applicable)
|
|
128
135
|
- **platform-expert.md**: Claude Code version, known permission bugs, hook configuration
|
|
129
136
|
|
|
137
|
+
When specializing agents, append a zone at the bottom of each agent file:
|
|
138
|
+
|
|
139
|
+
```markdown
|
|
140
|
+
<!-- guild:auto-start:agent-context -->
|
|
141
|
+
## Project-Specific Context
|
|
142
|
+
- Stack: [detected stack]
|
|
143
|
+
- Architecture: [detected patterns]
|
|
144
|
+
- Conventions: [detected conventions]
|
|
145
|
+
<!-- guild:auto-end:agent-context -->
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
This zone allows `guild-re-specialize` to update agent context later without touching the agent's core role definition.
|
|
149
|
+
|
|
130
150
|
Use the `Task` tool with `model: "sonnet"` to invoke each agent by reading their `.claude/agents/[name].md` if you need a specialized perspective to enrich their configuration.
|
|
131
151
|
|
|
132
152
|
The `model` parameter is resolved from the step's `model-tier`: reasoning→`"opus"`, execution→`"sonnet"`. System/gate steps run inline (no Task tool).
|