guild-agents 1.1.0 → 1.2.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 CHANGED
@@ -62,7 +62,7 @@ Six phases: **evaluate**, **specify**, **plan**, **implement**, **review**, **va
62
62
 
63
63
  ## Skills Reference
64
64
 
65
- All 11 skills, grouped by function:
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,61 @@ 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
+
171
228
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guild-agents",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Specification-driven development CLI for Claude Code — think before you build",
5
5
  "type": "module",
6
6
  "files": [
@@ -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,55 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
2
+ import { basename, join } from 'path';
3
+ import { findWorkspaceRoot, 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 async function getWorkspaceStatus() {
42
+ const root = findWorkspaceRoot();
43
+ if (!root) throw new Error('No workspace found. Run `guild workspace init` first.');
44
+
45
+ const filePath = join(root, WORKSPACE_FILE);
46
+ const config = JSON.parse(readFileSync(filePath, 'utf8'));
47
+
48
+ const members = config.members.map(m => {
49
+ const absPath = join(root, m.path);
50
+ const initialized = existsSync(join(absPath, '.claude'));
51
+ return { ...m, absolutePath: absPath, initialized };
52
+ });
53
+
54
+ return { name: config.name, root, members };
55
+ }
@@ -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).
@@ -0,0 +1,153 @@
1
+ ---
2
+ name: re-specialize
3
+ description: "Incremental re-specialization — re-scans the project and updates only auto-generated zones in CLAUDE.md and agents"
4
+ user-invocable: true
5
+ workflow:
6
+ version: 1
7
+ steps:
8
+ - id: read-current
9
+ role: system
10
+ intent: "Read current CLAUDE.md and agent files to identify existing zones."
11
+ commands: [cat CLAUDE.md]
12
+ produces: [current-claude-md, current-agents]
13
+ - id: explore-project
14
+ role: system
15
+ intent: "Scan project for current stack, dependencies, architecture, conventions."
16
+ commands: [ls -R src/, cat package.json]
17
+ produces: [detected-stack, detected-architecture, detected-conventions]
18
+ gate: true
19
+ - id: check-zones
20
+ role: system
21
+ intent: "Check if CLAUDE.md has guild zone markers. If not, offer to inject them."
22
+ requires: [current-claude-md]
23
+ produces: [zone-status]
24
+ gate: true
25
+ - id: regenerate-zones
26
+ role: tech-lead
27
+ intent: "Generate new content for each auto zone based on fresh project scan. Present diff to user."
28
+ requires: [current-claude-md, detected-stack, detected-architecture, detected-conventions, zone-status]
29
+ produces: [updated-claude-md, zone-diffs]
30
+ model-tier: reasoning
31
+ - id: update-agents
32
+ role: tech-lead
33
+ intent: "Update agent-context zones in agent files with fresh project context."
34
+ requires: [detected-stack, detected-architecture, detected-conventions]
35
+ produces: [updated-agents]
36
+ model-tier: execution
37
+ - id: confirm
38
+ role: system
39
+ intent: "Present summary of changes and get user confirmation."
40
+ requires: [zone-diffs, updated-agents]
41
+ produces: [confirmation]
42
+ gate: true
43
+ - id: commit
44
+ role: system
45
+ intent: "Commit re-specialized files."
46
+ commands: [git add CLAUDE.md .claude/agents/*.md, git commit -m "chore: re-specialize via guild-re-specialize"]
47
+ requires: [updated-claude-md, updated-agents, confirmation]
48
+ produces: [re-specialize-commit]
49
+ ---
50
+
51
+ # Re-Specialize
52
+
53
+ Incrementally updates auto-generated content in CLAUDE.md and agent files
54
+ without touching user customizations. Uses protected zone markers to identify
55
+ what can be safely regenerated.
56
+
57
+ ## When to use
58
+
59
+ - When project dependencies have changed (new framework, updated versions)
60
+ - When architecture has evolved (new patterns, restructured folders)
61
+ - When agents need refreshed context about the project
62
+ - Periodically to keep CLAUDE.md in sync with the actual codebase
63
+
64
+ ## Process
65
+
66
+ ### Step 1 -- Read current state
67
+
68
+ Read CLAUDE.md and all agent files in `.claude/agents/`:
69
+
70
+ - Identify existing zone markers (`<!-- guild:auto-start:ID -->` / `<!-- guild:auto-end:ID -->`)
71
+ - Note which zones exist and their current content
72
+ - Identify any user customizations outside of zones
73
+
74
+ ### Step 2 -- Explore the project
75
+
76
+ Same exploration as guild-specialize:
77
+
78
+ - Scan dependency files for current stack and versions
79
+ - Analyze project structure and architecture patterns
80
+ - Detect code conventions from linter/formatter configs
81
+ - Check environment variable examples
82
+
83
+ ### Step 3 -- Check zone markers
84
+
85
+ If CLAUDE.md has zone markers, proceed to regeneration.
86
+
87
+ If CLAUDE.md does NOT have zone markers (legacy project):
88
+
89
+ - Offer to inject markers around the auto-generated sections
90
+ - Show the user where markers would be placed
91
+ - Require explicit confirmation before modifying
92
+ - If user declines, abort gracefully
93
+
94
+ ### Step 4 -- Regenerate zone content
95
+
96
+ Invoke the Tech Lead agent using Task tool with `model: "opus"` (reasoning tier):
97
+
98
+ - Generate fresh content for each zone based on the project scan
99
+ - Compare new content with existing zone content
100
+ - Present a diff for each zone to the user
101
+ - Only replace zones where content has actually changed
102
+
103
+ Zones to regenerate:
104
+
105
+ | Zone ID | Content |
106
+ |----------------|--------------------------------------------|
107
+ | `structure` | Project folder structure with descriptions |
108
+ | `architecture` | Architecture patterns and design decisions |
109
+ | `conventions` | Code conventions from linter/formatter |
110
+ | `env-vars` | Environment variables from .env.example |
111
+
112
+ ### Step 5 -- Update agent context
113
+
114
+ Invoke the Tech Lead agent using Task tool with `model: "sonnet"` (execution tier):
115
+
116
+ - For each agent in `.claude/agents/*.md`, update the `agent-context` zone
117
+ - If no `agent-context` zone exists, append one at the bottom
118
+ - Preserve everything outside the zone (role definition, process, rules)
119
+
120
+ ### Step 6 -- Confirm changes
121
+
122
+ Present a summary:
123
+
124
+ ```text
125
+ Re-specialization complete for [project-name]
126
+
127
+ Zones updated:
128
+ - structure: [changed/unchanged]
129
+ - architecture: [changed/unchanged]
130
+ - conventions: [changed/unchanged]
131
+ - env-vars: [changed/unchanged]
132
+
133
+ Agents updated: [count] of [total]
134
+
135
+ Review the changes above. Confirm to commit.
136
+ ```
137
+
138
+ ### Step 7 -- Commit
139
+
140
+ Commit all changes as an atomic commit:
141
+
142
+ ```bash
143
+ git add CLAUDE.md .claude/agents/*.md
144
+ git commit -m "chore: re-specialize via guild-re-specialize"
145
+ ```
146
+
147
+ ## Important Notes
148
+
149
+ - NEVER modify content outside of zone markers
150
+ - NEVER read real `.env` files -- only `.env.example`
151
+ - If a zone's content hasn't changed, skip it (no-op)
152
+ - Present diffs before applying changes
153
+ - User confirmation is required before committing
@@ -0,0 +1,159 @@
1
+ ---
2
+ name: tdd
3
+ description: "Discipline skill — TDD red-green-refactor cycle. Use when implementing any feature or bugfix, before writing implementation code."
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Test-Driven Development (TDD)
8
+
9
+ Write the test first. Watch it fail. Write minimal code to pass.
10
+
11
+ **Core principle:** If you didn't watch the test fail, you don't know if it tests the right thing.
12
+
13
+ ## Usage
14
+
15
+ `/tdd`
16
+
17
+ Invoke this skill before implementing any feature or bugfix. It establishes the discipline for your implementation session.
18
+
19
+ ## When to use
20
+
21
+ - New features
22
+ - Bug fixes
23
+ - Refactoring
24
+ - Behavior changes
25
+
26
+ **Exceptions (ask the user):** throwaway prototypes, generated code, configuration files.
27
+
28
+ ## The Iron Law
29
+
30
+ ```text
31
+ NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
32
+ ```
33
+
34
+ Write code before the test? Delete it. Start over.
35
+
36
+ - Don't keep it as "reference"
37
+ - Don't "adapt" it while writing tests
38
+ - Don't look at it
39
+ - Delete means delete
40
+
41
+ ## Red-Green-Refactor
42
+
43
+ ### RED - Write Failing Test
44
+
45
+ Write one minimal test showing what should happen.
46
+
47
+ **Requirements:**
48
+
49
+ - One behavior per test
50
+ - Clear name that describes behavior
51
+ - Real code (no mocks unless unavoidable)
52
+
53
+ **Run the test. Confirm:**
54
+
55
+ - Test fails (not errors)
56
+ - Failure message is expected
57
+ - Fails because feature missing (not typos)
58
+
59
+ Test passes? You're testing existing behavior. Fix the test.
60
+
61
+ ### GREEN - Minimal Code
62
+
63
+ Write the simplest code to pass the test.
64
+
65
+ Don't add features, refactor other code, or "improve" beyond the test.
66
+
67
+ **Run the test. Confirm:**
68
+
69
+ - Test passes
70
+ - Other tests still pass
71
+ - Output pristine (no errors, warnings)
72
+
73
+ Test fails? Fix code, not test.
74
+
75
+ ### REFACTOR - Clean Up
76
+
77
+ After green only:
78
+
79
+ - Remove duplication
80
+ - Improve names
81
+ - Extract helpers
82
+
83
+ Keep tests green. Don't add behavior.
84
+
85
+ ### Repeat
86
+
87
+ Next failing test for next behavior.
88
+
89
+ ## Good Tests
90
+
91
+ | Quality | Good | Bad |
92
+ | ---------------- | ----------------------------------- | --------------------------------------------------- |
93
+ | **Minimal** | One thing. "and" in name? Split it. | `test('validates email and domain and whitespace')` |
94
+ | **Clear** | Name describes behavior | `test('test1')` |
95
+ | **Shows intent** | Demonstrates desired API | Obscures what code should do |
96
+
97
+ ## Common Rationalizations
98
+
99
+ | Excuse | Reality |
100
+ | -------------------------------- | ----------------------------------------------------------------------- |
101
+ | "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
102
+ | "I'll test after" | Tests passing immediately prove nothing. |
103
+ | "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
104
+ | "Already manually tested" | Ad-hoc is not systematic. No record, can't re-run. |
105
+ | "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. |
106
+ | "Need to explore first" | Fine. Throw away exploration, start with TDD. |
107
+ | "Test hard = design unclear" | Listen to the test. Hard to test = hard to use. |
108
+ | "TDD will slow me down" | TDD is faster than debugging. |
109
+
110
+ ## Red Flags - STOP and Start Over
111
+
112
+ - Code before test
113
+ - Test after implementation
114
+ - Test passes immediately
115
+ - Can't explain why test failed
116
+ - Rationalizing "just this once"
117
+ - "I already manually tested it"
118
+ - "Keep as reference"
119
+
120
+ **All of these mean: Delete code. Start over with TDD.**
121
+
122
+ ## Bug Fix Flow
123
+
124
+ 1. Write failing test reproducing the bug
125
+ 2. Verify RED (test fails as expected)
126
+ 3. Implement minimal fix
127
+ 4. Verify GREEN (test passes, all tests pass)
128
+ 5. Refactor if needed
129
+
130
+ Never fix bugs without a test.
131
+
132
+ ## When Stuck
133
+
134
+ | Problem | Solution |
135
+ | ------------------------ | ----------------------------------------------------- |
136
+ | Don't know how to test | Write wished-for API. Write assertion first. |
137
+ | Test too complicated | Design too complicated. Simplify interface. |
138
+ | Must mock everything | Code too coupled. Use dependency injection. |
139
+ | Test setup huge | Extract helpers. Still complex? Simplify design. |
140
+
141
+ ## Verification Checklist
142
+
143
+ Before marking work complete:
144
+
145
+ - [ ] Every new function/method has a test
146
+ - [ ] Watched each test fail before implementing
147
+ - [ ] Each test failed for expected reason
148
+ - [ ] Wrote minimal code to pass each test
149
+ - [ ] All tests pass
150
+ - [ ] Output pristine (no errors, warnings)
151
+ - [ ] Tests use real code (mocks only if unavoidable)
152
+ - [ ] Edge cases and errors covered
153
+
154
+ Can't check all boxes? You skipped TDD. Start over.
155
+
156
+ ## Related Skills
157
+
158
+ - `/debug` — systematic debugging when tests reveal unexpected failures
159
+ - `/verify` — verification before claiming work is complete
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: verify
3
+ description: "Discipline skill — verification before completion. Use when about to claim work is complete, fixed, or passing, before committing or creating PRs."
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Verification Before Completion
8
+
9
+ Claiming work is complete without verification is dishonesty, not efficiency.
10
+
11
+ **Core principle:** Evidence before claims, always.
12
+
13
+ ## Usage
14
+
15
+ `/verify`
16
+
17
+ Invoke this skill before claiming any work is done, before committing, and before creating PRs.
18
+
19
+ ## When to use
20
+
21
+ **ALWAYS before:**
22
+
23
+ - Any success or completion claim
24
+ - Committing, pushing, or creating PRs
25
+ - Moving to the next task
26
+ - Expressing satisfaction about work state
27
+
28
+ ## The Iron Law
29
+
30
+ ```text
31
+ NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE
32
+ ```
33
+
34
+ If you haven't run the verification command in this step, you cannot claim it passes.
35
+
36
+ ## The Gate Function
37
+
38
+ ```text
39
+ BEFORE claiming any status:
40
+
41
+ 1. IDENTIFY: What command proves this claim?
42
+ 2. RUN: Execute the FULL command (fresh, complete)
43
+ 3. READ: Full output, check exit code, count failures
44
+ 4. VERIFY: Does output confirm the claim?
45
+ - If NO: State actual status with evidence
46
+ - If YES: State claim WITH evidence
47
+ 5. ONLY THEN: Make the claim
48
+
49
+ Skip any step = lying, not verifying
50
+ ```
51
+
52
+ ## What Each Claim Requires
53
+
54
+ | Claim | Requires | Not Sufficient |
55
+ | ---------------- | ------------------------------- | ------------------------------ |
56
+ | Tests pass | Test command output: 0 failures | Previous run, "should pass" |
57
+ | Linter clean | Linter output: 0 errors | Partial check, extrapolation |
58
+ | Build succeeds | Build command: exit 0 | Linter passing, logs look good |
59
+ | Bug fixed | Test original symptom: passes | Code changed, assumed fixed |
60
+ | Regression test | Red-green cycle verified | Test passes once |
61
+ | Requirements met | Line-by-line checklist | Tests passing |
62
+
63
+ ## Red Flags - STOP
64
+
65
+ - Using "should", "probably", "seems to"
66
+ - Expressing satisfaction before verification ("Great!", "Perfect!", "Done!")
67
+ - About to commit/push/PR without verification
68
+ - Relying on partial verification
69
+ - Thinking "just this once"
70
+ - ANY wording implying success without having run verification
71
+
72
+ ## Common Rationalizations
73
+
74
+ | Excuse | Reality |
75
+ | ---------------------------- | ------------------------------ |
76
+ | "Should work now" | RUN the verification |
77
+ | "I'm confident" | Confidence is not evidence |
78
+ | "Just this once" | No exceptions |
79
+ | "Linter passed" | Linter is not compiler |
80
+ | "Partial check is enough" | Partial proves nothing |
81
+
82
+ ## Verification Patterns
83
+
84
+ **Tests:**
85
+
86
+ ```text
87
+ OK: [Run test command] [See: 34/34 pass] "All tests pass"
88
+ BAD: "Should pass now" / "Looks correct"
89
+ ```
90
+
91
+ **Build:**
92
+
93
+ ```text
94
+ OK: [Run build] [See: exit 0] "Build passes"
95
+ BAD: "Linter passed" (linter doesn't check compilation)
96
+ ```
97
+
98
+ **Requirements:**
99
+
100
+ ```text
101
+ OK: Re-read plan -> Create checklist -> Verify each -> Report gaps or completion
102
+ BAD: "Tests pass, phase complete"
103
+ ```
104
+
105
+ ## The Bottom Line
106
+
107
+ Run the command. Read the output. THEN claim the result.
108
+
109
+ No shortcuts. Non-negotiable.
110
+
111
+ ## Related Skills
112
+
113
+ - `/tdd` — TDD ensures tests exist before claiming code works
114
+ - `/debug` — systematic debugging when verification reveals failures
@@ -3,6 +3,8 @@
3
3
  */
4
4
 
5
5
  import { writeFileSync } from 'fs';
6
+ import { wrapZone } from './zones.js';
7
+ import { generateWorkspaceContext } from './workspace.js';
6
8
 
7
9
  /**
8
10
  * Generates PROJECT.md with the onboarding data.
@@ -95,7 +97,10 @@ export function inferEnvVars(type, stack) {
95
97
  /**
96
98
  * Generates CLAUDE.md — central document with placeholders for guild-specialize.
97
99
  */
98
- export async function generateClaudeMd(data) {
100
+ export async function generateClaudeMd(data, workspace = null, currentMemberName = null) {
101
+ const wsContext = generateWorkspaceContext(workspace, currentMemberName);
102
+ const workspaceSection = wsContext ? `\n${wsContext}\n` : '';
103
+
99
104
  const content = `# ${data.name}
100
105
 
101
106
  ## Framework
@@ -105,20 +110,17 @@ This project uses Guild. Read SESSION.md at the start of each session.
105
110
  ${data.stack}
106
111
 
107
112
  ## Project structure
108
- [PENDING: guild-specialize]
109
-
110
- docs/
111
- specs/ # Design documents (SDD specs)
113
+ ${wrapZone('structure', '[PENDING: guild-specialize]\n\ndocs/\n specs/ # Design documents (SDD specs)')}
112
114
 
113
115
  ## Code conventions
114
- ${inferCodeConventions(data.type, data.stack)}
116
+ ${wrapZone('conventions', inferCodeConventions(data.type, data.stack))}
115
117
 
116
118
  ## Architecture patterns
117
- [PENDING: guild-specialize]
119
+ ${wrapZone('architecture', '[PENDING: guild-specialize]')}
118
120
 
119
121
  ## Environment variables
120
- ${inferEnvVars(data.type, data.stack)}
121
-
122
+ ${wrapZone('env-vars', inferEnvVars(data.type, data.stack))}
123
+ ${workspaceSection}
122
124
  ## Global rules
123
125
  - Do not implement without an approved plan
124
126
  - Update SESSION.md at the end of each session
@@ -0,0 +1,82 @@
1
+ import { existsSync, readFileSync, readdirSync } from 'fs';
2
+ import { join, dirname, resolve } from 'path';
3
+
4
+ export const WORKSPACE_FILE = 'guild-workspace.json';
5
+
6
+ export function findWorkspaceRoot(startDir = process.cwd()) {
7
+ let dir = resolve(startDir);
8
+ while (true) {
9
+ if (existsSync(join(dir, WORKSPACE_FILE))) {
10
+ return dir;
11
+ }
12
+ const parent = dirname(dir);
13
+ if (parent === dir) return null;
14
+ dir = parent;
15
+ }
16
+ }
17
+
18
+ export function loadWorkspace(startDir = process.cwd()) {
19
+ const root = findWorkspaceRoot(startDir);
20
+ if (!root) return null;
21
+
22
+ const filePath = join(root, WORKSPACE_FILE);
23
+ const raw = JSON.parse(readFileSync(filePath, 'utf8'));
24
+
25
+ return {
26
+ ...raw,
27
+ root,
28
+ members: (raw.members || []).map(m => ({
29
+ ...m,
30
+ absolutePath: resolve(root, m.path),
31
+ })),
32
+ };
33
+ }
34
+
35
+ export function resolveWorkspaceAgents(workspace, localAgentsDir) {
36
+ const agents = new Map();
37
+
38
+ if (workspace?.shared?.agents) {
39
+ const sharedDir = resolve(workspace.root, workspace.shared.agents);
40
+ if (existsSync(sharedDir)) {
41
+ for (const file of readdirSync(sharedDir).filter(f => f.endsWith('.md'))) {
42
+ const name = file.replace('.md', '');
43
+ agents.set(name, { name, path: join(sharedDir, file), source: 'workspace' });
44
+ }
45
+ }
46
+ }
47
+
48
+ if (existsSync(localAgentsDir)) {
49
+ for (const file of readdirSync(localAgentsDir).filter(f => f.endsWith('.md'))) {
50
+ const name = file.replace('.md', '');
51
+ agents.set(name, { name, path: join(localAgentsDir, file), source: 'local' });
52
+ }
53
+ }
54
+
55
+ return [...agents.values()].sort((a, b) => a.name.localeCompare(b.name));
56
+ }
57
+
58
+ export function generateWorkspaceContext(workspace, currentMemberName) {
59
+ if (!workspace) return '';
60
+
61
+ const otherMembers = workspace.members.filter(m => m.name !== currentMemberName);
62
+ if (otherMembers.length === 0) return '';
63
+
64
+ const lines = [
65
+ '## Workspace context',
66
+ `- **Workspace:** ${workspace.name}`,
67
+ `- **Members:** ${workspace.members.map(m => m.name === currentMemberName ? `${m.name} (this)` : m.name).join(', ')}`,
68
+ ];
69
+
70
+ for (const member of otherMembers) {
71
+ const projectMdPath = join(member.absolutePath, 'PROJECT.md');
72
+ if (existsSync(projectMdPath)) {
73
+ const content = readFileSync(projectMdPath, 'utf8');
74
+ const stackMatch = content.match(/\*\*Stack:\*\*\s*(.+)/);
75
+ if (stackMatch) {
76
+ lines.push(`- **${member.name} stack:** ${stackMatch[1].trim()}`);
77
+ }
78
+ }
79
+ }
80
+
81
+ return lines.join('\n');
82
+ }
@@ -0,0 +1,39 @@
1
+ const MARKER_START = 'guild:auto-start';
2
+ const MARKER_END = 'guild:auto-end';
3
+
4
+ export function wrapZone(zoneId, content) {
5
+ const trimmed = content.endsWith('\n') ? content.slice(0, -1) : content;
6
+ return `<!-- ${MARKER_START}:${zoneId} -->\n${trimmed}\n<!-- ${MARKER_END}:${zoneId} -->`;
7
+ }
8
+
9
+ export function extractZones(content) {
10
+ const zones = new Map();
11
+ const startPattern = /^<!-- guild:auto-start:(\S+) -->$/gm;
12
+ let match;
13
+
14
+ while ((match = startPattern.exec(content)) !== null) {
15
+ const zoneId = match[1];
16
+ const contentStart = match.index + match[0].length + 1; // +1 for newline
17
+ const endMarker = `<!-- ${MARKER_END}:${zoneId} -->`;
18
+ const endIndex = content.indexOf(endMarker, contentStart);
19
+ if (endIndex === -1) continue;
20
+
21
+ zones.set(zoneId, {
22
+ start: match.index,
23
+ end: endIndex + endMarker.length,
24
+ content: content.slice(contentStart, endIndex - 1), // -1 to trim newline before end marker
25
+ });
26
+ }
27
+
28
+ return zones;
29
+ }
30
+
31
+ export function replaceZone(content, zoneId, newContent) {
32
+ const zones = extractZones(content);
33
+ if (!zones.has(zoneId)) return content;
34
+
35
+ const zone = zones.get(zoneId);
36
+ const before = content.slice(0, zone.start);
37
+ const after = content.slice(zone.end);
38
+ return before + wrapZone(zoneId, newContent) + after;
39
+ }