worclaude 2.0.0 → 2.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
@@ -10,7 +10,7 @@
10
10
 
11
11
  [Full Documentation](https://sefaertunc.github.io/Worclaude/) · [Interactive Demo](https://sefaertunc.github.io/Worclaude/demo/) · [npm](https://www.npmjs.com/package/worclaude)
12
12
 
13
- Worclaude scaffolds a complete Claude Code workflow into any project in seconds. It implements all [tips by Boris Cherny](https://www.howborisusesclaudecode.com/) — the creator of Claude Code at Anthropic — as a reusable, upgradable scaffold. One `init` command gives you 25 agents, 16 slash commands, 14 skills, hooks, permissions, and a CLAUDE.md template tuned for your tech stack. Whether you're starting fresh or adding structure to an existing project, Worclaude handles the setup so you can focus on building.
13
+ Worclaude scaffolds a complete Claude Code workflow into any project in seconds. It implements all [tips by Boris Cherny](https://www.howborisusesclaudecode.com/) — the creator of Claude Code at Anthropic — as a reusable, upgradable scaffold. One `init` command gives you 25 agents, 16 slash commands, 15 skills, hooks, permissions, and a CLAUDE.md template tuned for your tech stack. Whether you're starting fresh or adding structure to an existing project, Worclaude handles the setup so you can focus on building.
14
14
 
15
15
  ---
16
16
 
@@ -26,9 +26,9 @@ Worclaude scaffolds a complete Claude Code workflow into any project in seconds.
26
26
  **Slash Commands (16)**
27
27
  `/start` `/end` `/commit-push-pr` `/review-plan` `/techdebt` `/verify` `/compact-safe` `/status` `/update-claude-md` `/setup` `/sync` `/conflict-resolver` `/review-changes` `/build-fix` `/refactor-clean` `/test-coverage`
28
28
 
29
- **Skills (14)**
29
+ **Skills (15)**
30
30
 
31
- - 10 universal knowledge files (testing, git conventions, context management, security, and more)
31
+ - 11 universal knowledge files (testing, git conventions, context management, security, coordinator mode, and more)
32
32
  - 3 project-specific templates filled in by `/setup`
33
33
  - 1 generated agent routing guide (dynamically built from your agent selection)
34
34
 
@@ -48,6 +48,45 @@ Worclaude scaffolds a complete Claude Code workflow into any project in seconds.
48
48
 
49
49
  ---
50
50
 
51
+ ## What's New in v2.0.0
52
+
53
+ v2.0.0 is a major integration release. Skills and agents now register with Claude Code's runtime systems — they show up in `/skills` and `/agents`, not just as files on disk.
54
+
55
+ **Claude Code Runtime Integration**
56
+
57
+ - Skills use directory format (`skill-name/SKILL.md`) and register with `/skills`
58
+ - Agents include `description` frontmatter and register with `/agents`
59
+ - Run `worclaude doctor` to verify everything is wired up correctly
60
+
61
+ **Conditional Skills**
62
+
63
+ - 6 skills activate only when relevant files are touched (testing, security, frontend, backend, verification, project-patterns)
64
+ - 8 skills stay always-loaded for cross-cutting guidance
65
+ - Saves context window budget by keeping domain-specific guidance out of unrelated work
66
+
67
+ **Agent Enhancements**
68
+
69
+ - Read-only agents blocked from file modifications via `disallowedTools`
70
+ - Background execution for long-running agents (verify-app, build-validator, e2e-runner)
71
+ - Turn limits (`maxTurns`) prevent runaway token consumption
72
+ - Persistent memory for agents that learn across sessions (test-writer, security-reviewer, doc-writer)
73
+
74
+ **New Content**
75
+
76
+ - Coordinator-mode skill for multi-agent orchestration patterns
77
+ - Optional MEMORY.md template for Claude Code's memory system
78
+ - Enhanced verify-app agent with structured verdicts and adversarial probe requirements
79
+ - Per-tech-stack permission presets (16 languages)
80
+
81
+ **Upgrade Migration**
82
+
83
+ - `worclaude upgrade` auto-migrates v1.x projects: flat skills → directory format, agents get required frontmatter
84
+ - `worclaude doctor` detects old formats and missing fields
85
+
86
+ See the [Claude Code Integration guide](https://sefaertunc.github.io/Worclaude/guide/claude-code-integration) for technical details.
87
+
88
+ ---
89
+
51
90
  ## Quick Start
52
91
 
53
92
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worclaude",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "CLI tool that scaffolds a comprehensive Claude Code workflow into any project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import inquirer from 'inquirer';
3
3
  import ora from 'ora';
4
- import { workflowMetaExists, readWorkflowMeta } from '../core/config.js';
4
+ import { requireWorkflowMeta } from '../core/config.js';
5
5
  import { createBackup } from '../core/backup.js';
6
6
  import {
7
7
  classifyClaudeFiles,
@@ -16,16 +16,13 @@ export async function deleteCommand() {
16
16
  const projectRoot = process.cwd();
17
17
 
18
18
  // Pre-flight: ensure worclaude is installed
19
- if (!(await workflowMetaExists(projectRoot))) {
20
- display.error('No worclaude workflow found in this project.');
21
- display.info('Run `worclaude init` to set up a workflow first.');
19
+ const { meta, error } = await requireWorkflowMeta(projectRoot);
20
+ if (error === 'not-installed') {
21
+ display.info('Workflow is not installed. Run `worclaude init` to set up.');
22
22
  return;
23
23
  }
24
-
25
- const meta = await readWorkflowMeta(projectRoot);
26
- if (!meta) {
27
- display.error('workflow-meta.json is corrupted or unreadable.');
28
- display.info('You may need to manually remove the .claude/ directory.');
24
+ if (error === 'corrupted') {
25
+ display.error('workflow-meta.json is corrupted. Run `worclaude init` to reinstall.');
29
26
  return;
30
27
  }
31
28
 
@@ -1,17 +1,16 @@
1
- import { readWorkflowMeta, workflowMetaExists, getPackageVersion } from '../core/config.js';
1
+ import { requireWorkflowMeta, getPackageVersion } from '../core/config.js';
2
2
  import { categorizeFiles } from '../core/file-categorizer.js';
3
3
  import * as display from '../utils/display.js';
4
4
 
5
5
  export async function diffCommand() {
6
6
  const projectRoot = process.cwd();
7
7
 
8
- if (!(await workflowMetaExists(projectRoot))) {
8
+ const { meta, error } = await requireWorkflowMeta(projectRoot);
9
+ if (error === 'not-installed') {
9
10
  display.info('Workflow is not installed. Run `worclaude init` to set up.');
10
11
  return;
11
12
  }
12
-
13
- const meta = await readWorkflowMeta(projectRoot);
14
- if (!meta) {
13
+ if (error === 'corrupted') {
15
14
  display.error('workflow-meta.json is corrupted. Run `worclaude init` to reinstall.');
16
15
  return;
17
16
  }
@@ -177,59 +177,57 @@ async function checkAgents(projectRoot, meta) {
177
177
  return results;
178
178
  }
179
179
 
180
- async function checkAgentDescription(projectRoot) {
180
+ async function readAgentFrontmatters(projectRoot) {
181
181
  const agentsDir = path.join(projectRoot, '.claude', 'agents');
182
- const results = [];
183
-
184
182
  try {
185
183
  const entries = await fs.readdir(agentsDir, { withFileTypes: true });
186
184
  const mdFiles = entries.filter((e) => e.isFile() && e.name.endsWith('.md'));
187
-
185
+ const agents = [];
188
186
  for (const file of mdFiles) {
189
- const filePath = path.join(agentsDir, file.name);
190
- const content = await readFile(filePath);
191
-
192
- // Parse YAML frontmatter
193
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
194
- if (!frontmatterMatch) {
195
- results.push(
196
- result(
197
- FAIL,
198
- `agents/${file.name}`,
199
- 'No YAML frontmatter — agent is invisible to Claude Code'
200
- )
201
- );
202
- continue;
203
- }
187
+ const content = await readFile(path.join(agentsDir, file.name));
188
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
189
+ agents.push({ name: file.name, frontmatter: match ? match[1] : null });
190
+ }
191
+ return agents;
192
+ } catch {
193
+ return [];
194
+ }
195
+ }
204
196
 
205
- const frontmatter = frontmatterMatch[1];
206
- const hasName = /^name:\s*.+/m.test(frontmatter);
207
- const hasDescription = /^description:\s*.+/m.test(frontmatter);
208
-
209
- if (!hasName) {
210
- results.push(
211
- result(FAIL, `agents/${file.name}`, 'Missing required "name" field in frontmatter')
212
- );
213
- } else if (!hasDescription) {
214
- results.push(
215
- result(
216
- FAIL,
217
- `agents/${file.name}`,
218
- 'Missing required "description" field — agent is invisible to Claude Code\'s /agents and routing'
219
- )
220
- );
221
- }
197
+ async function checkAgentDescription(projectRoot) {
198
+ const agents = await readAgentFrontmatters(projectRoot);
199
+ if (agents.length === 0) return [];
200
+
201
+ const results = [];
202
+ for (const { name, frontmatter } of agents) {
203
+ if (!frontmatter) {
204
+ results.push(
205
+ result(FAIL, `agents/${name}`, 'No YAML frontmatter — agent is invisible to Claude Code')
206
+ );
207
+ continue;
222
208
  }
223
209
 
224
- if (results.length === 0 && mdFiles.length > 0) {
210
+ const hasName = /^name:\s*.+/m.test(frontmatter);
211
+ const hasDescription = /^description:\s*.+/m.test(frontmatter);
212
+
213
+ if (!hasName) {
214
+ results.push(result(FAIL, `agents/${name}`, 'Missing required "name" field in frontmatter'));
215
+ } else if (!hasDescription) {
225
216
  results.push(
226
- result(PASS, `agents/ frontmatter (${mdFiles.length} agents have required fields)`, null)
217
+ result(
218
+ FAIL,
219
+ `agents/${name}`,
220
+ 'Missing required "description" field — agent is invisible to Claude Code\'s /agents and routing'
221
+ )
227
222
  );
228
223
  }
229
- } catch {
230
- // agents/ doesn't exist — covered by existing component checks
231
224
  }
232
225
 
226
+ if (results.length === 0) {
227
+ results.push(
228
+ result(PASS, `agents/ frontmatter (${agents.length} agents have required fields)`, null)
229
+ );
230
+ }
233
231
  return results;
234
232
  }
235
233
 
@@ -385,6 +383,124 @@ async function checkDocSpecs(projectRoot) {
385
383
  return results;
386
384
  }
387
385
 
386
+ const AGENT_OPTIONAL_FIELDS = [
387
+ 'model',
388
+ 'isolation',
389
+ 'maxTurns',
390
+ 'disallowedTools',
391
+ 'background',
392
+ 'memory',
393
+ 'skills',
394
+ 'initialPrompt',
395
+ 'criticalSystemReminder',
396
+ 'omitClaudeMd',
397
+ ];
398
+
399
+ async function checkAgentCompleteness(projectRoot) {
400
+ const agents = await readAgentFrontmatters(projectRoot);
401
+ const withFrontmatter = agents.filter((a) => a.frontmatter);
402
+ if (withFrontmatter.length === 0) return [];
403
+
404
+ let totalFields = 0;
405
+ const suggestions = [];
406
+
407
+ for (const { name, frontmatter } of withFrontmatter) {
408
+ let fieldCount = 0;
409
+ for (const field of AGENT_OPTIONAL_FIELDS) {
410
+ if (new RegExp(`^${field}:`, 'm').test(frontmatter)) fieldCount++;
411
+ }
412
+ totalFields += fieldCount;
413
+
414
+ const hasDisallowed = /^disallowedTools:/m.test(frontmatter);
415
+ const hasReminder = /^criticalSystemReminder:/m.test(frontmatter);
416
+ if (hasDisallowed && !hasReminder) {
417
+ suggestions.push(`${name}: read-only agent could benefit from criticalSystemReminder`);
418
+ }
419
+ }
420
+
421
+ const totalPossible = withFrontmatter.length * AGENT_OPTIONAL_FIELDS.length;
422
+ const pct = Math.round((totalFields / totalPossible) * 100);
423
+ const results = [];
424
+
425
+ if (pct >= 50) {
426
+ results.push(
427
+ result(
428
+ PASS,
429
+ `Agent enrichment: ${pct}% optional fields used across ${withFrontmatter.length} agents`,
430
+ null
431
+ )
432
+ );
433
+ } else {
434
+ results.push(
435
+ result(
436
+ WARN,
437
+ `Agent enrichment: ${pct}% optional fields used across ${withFrontmatter.length} agents`,
438
+ 'Run `worclaude upgrade` to add model, maxTurns, skills, and other metadata'
439
+ )
440
+ );
441
+ }
442
+
443
+ for (const s of suggestions) {
444
+ results.push(result(WARN, s, null));
445
+ }
446
+
447
+ return results;
448
+ }
449
+
450
+ async function checkClaudeMdSections(projectRoot) {
451
+ const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
452
+ const SECTION_THRESHOLD = 20000; // Only analyze sections if file > 20KB
453
+ const results = [];
454
+
455
+ try {
456
+ const content = await readFile(claudeMdPath);
457
+ if (content.length < SECTION_THRESHOLD) return results;
458
+
459
+ // Split into ## sections
460
+ const sections = [];
461
+ const lines = content.split('\n');
462
+ let currentHeading = '(top-level)';
463
+ let currentLines = [];
464
+
465
+ for (const line of lines) {
466
+ const headingMatch = line.match(/^##\s+(.+)/);
467
+ if (headingMatch) {
468
+ if (currentLines.length > 0) {
469
+ sections.push({ heading: currentHeading, size: currentLines.join('\n').length });
470
+ }
471
+ currentHeading = headingMatch[1];
472
+ currentLines = [];
473
+ } else {
474
+ currentLines.push(line);
475
+ }
476
+ }
477
+ if (currentLines.length > 0) {
478
+ sections.push({ heading: currentHeading, size: currentLines.join('\n').length });
479
+ }
480
+
481
+ // Sort by size, suggest extracting the top 3 sections > 2KB
482
+ const large = sections.filter((s) => s.size > 2000).sort((a, b) => b.size - a.size);
483
+
484
+ if (large.length > 0) {
485
+ const top = large.slice(0, 3);
486
+ const sectionList = top
487
+ .map((s) => `"${s.heading}" (${(s.size / 1024).toFixed(1)}KB)`)
488
+ .join(', ');
489
+ results.push(
490
+ result(
491
+ WARN,
492
+ `CLAUDE.md has large sections: ${sectionList}`,
493
+ 'Consider extracting to conditional skills with paths frontmatter to save context budget'
494
+ )
495
+ );
496
+ }
497
+ } catch {
498
+ // Already covered by checkClaudeMd
499
+ }
500
+
501
+ return results;
502
+ }
503
+
388
504
  async function checkPendingReviewFiles(projectRoot) {
389
505
  const pending = [];
390
506
  try {
@@ -429,6 +545,7 @@ export async function doctorCommand() {
429
545
 
430
546
  printResult(await checkClaudeMd(projectRoot));
431
547
  for (const r of await checkClaudeMdSize(projectRoot)) printResult(r);
548
+ for (const r of await checkClaudeMdSections(projectRoot)) printResult(r);
432
549
  printResult(await checkSettingsJson(projectRoot));
433
550
  printResult(await checkSessions(projectRoot));
434
551
  display.newline();
@@ -440,6 +557,7 @@ export async function doctorCommand() {
440
557
  for (const r of await checkCommands(projectRoot)) printResult(r);
441
558
  for (const r of await checkSkills(projectRoot)) printResult(r);
442
559
  for (const r of await checkSkillFormat(projectRoot)) printResult(r);
560
+ for (const r of await checkAgentCompleteness(projectRoot)) printResult(r);
443
561
  display.newline();
444
562
 
445
563
  // Docs
@@ -455,7 +573,7 @@ export async function doctorCommand() {
455
573
 
456
574
  // Summary
457
575
  if (metaResult.status === FAIL) {
458
- display.error('Workflow is not installed. Run `worclaude init` to set up.');
576
+ display.info('Workflow is not installed. Run `worclaude init` to set up.');
459
577
  } else {
460
578
  display.success('Doctor complete. Review any warnings above.');
461
579
  }
@@ -31,111 +31,137 @@ import { buildAgentRoutingSkill } from '../generators/agent-routing.js';
31
31
 
32
32
  // --- Helper functions ---
33
33
 
34
+ const LANGUAGE_COMMANDS = {
35
+ python: {
36
+ heading: 'Python',
37
+ commands: [
38
+ 'python -m pytest # Run tests',
39
+ 'ruff check . # Lint',
40
+ 'ruff format . # Format',
41
+ ],
42
+ },
43
+ node: {
44
+ heading: 'Node.js / TypeScript',
45
+ commands: [
46
+ 'npm test # Run tests',
47
+ 'npx eslint . # Lint',
48
+ 'npx prettier --write . # Format',
49
+ ],
50
+ },
51
+ java: {
52
+ heading: 'Java',
53
+ commands: [
54
+ 'mvn test # Run tests',
55
+ 'mvn checkstyle:check # Lint',
56
+ 'mvn spotless:apply # Format',
57
+ ],
58
+ },
59
+ csharp: {
60
+ heading: 'C# / .NET',
61
+ commands: [
62
+ 'dotnet test # Run tests',
63
+ 'dotnet format --verify-no-changes # Lint',
64
+ 'dotnet format # Format',
65
+ ],
66
+ },
67
+ cpp: {
68
+ heading: 'C / C++',
69
+ commands: [
70
+ 'cmake --build build && ctest # Build & test',
71
+ 'clang-tidy src/*.cpp # Lint',
72
+ 'clang-format -i src/*.[ch]pp # Format',
73
+ ],
74
+ },
75
+ go: {
76
+ heading: 'Go',
77
+ commands: [
78
+ 'go test ./... # Run tests',
79
+ 'golangci-lint run # Lint',
80
+ 'gofmt -w . # Format',
81
+ ],
82
+ },
83
+ php: {
84
+ heading: 'PHP',
85
+ commands: [
86
+ 'vendor/bin/phpunit # Run tests',
87
+ 'vendor/bin/phpstan analyse # Lint',
88
+ 'vendor/bin/php-cs-fixer fix . # Format',
89
+ ],
90
+ },
91
+ ruby: {
92
+ heading: 'Ruby',
93
+ commands: [
94
+ 'bundle exec rspec # Run tests',
95
+ 'rubocop # Lint',
96
+ 'rubocop -A # Format',
97
+ ],
98
+ },
99
+ kotlin: {
100
+ heading: 'Kotlin',
101
+ commands: [
102
+ 'gradle test # Run tests',
103
+ 'detekt # Lint',
104
+ 'ktlint -F # Format',
105
+ ],
106
+ },
107
+ swift: {
108
+ heading: 'Swift',
109
+ commands: [
110
+ 'swift test # Run tests',
111
+ 'swiftlint # Lint',
112
+ 'swift-format format -r . -i # Format',
113
+ ],
114
+ },
115
+ rust: {
116
+ heading: 'Rust',
117
+ commands: [
118
+ 'cargo test # Run tests',
119
+ 'cargo clippy # Lint',
120
+ 'cargo fmt # Format',
121
+ ],
122
+ },
123
+ dart: {
124
+ heading: 'Dart / Flutter',
125
+ commands: [
126
+ 'dart test # Run tests',
127
+ 'dart analyze # Lint',
128
+ 'dart format . # Format',
129
+ ],
130
+ },
131
+ scala: {
132
+ heading: 'Scala',
133
+ commands: [
134
+ 'sbt test # Run tests',
135
+ 'sbt scalafix # Lint',
136
+ 'scalafmt # Format',
137
+ ],
138
+ },
139
+ elixir: {
140
+ heading: 'Elixir',
141
+ commands: [
142
+ 'mix test # Run tests',
143
+ 'mix credo # Lint',
144
+ 'mix format # Format',
145
+ ],
146
+ },
147
+ zig: {
148
+ heading: 'Zig',
149
+ commands: [
150
+ 'zig build test # Run tests',
151
+ 'zig build # Build (lint via compiler)',
152
+ 'zig fmt . # Format',
153
+ ],
154
+ },
155
+ };
156
+
34
157
  function buildCommandsBlock(languages, useDocker) {
35
158
  const lines = ['```bash'];
36
- if (languages.includes('python')) {
37
- lines.push('# Python');
38
- lines.push('python -m pytest # Run tests');
39
- lines.push('ruff check . # Lint');
40
- lines.push('ruff format . # Format');
41
- }
42
- if (languages.includes('node')) {
43
- if (lines.length > 1) lines.push('');
44
- lines.push('# Node.js / TypeScript');
45
- lines.push('npm test # Run tests');
46
- lines.push('npx eslint . # Lint');
47
- lines.push('npx prettier --write . # Format');
48
- }
49
- if (languages.includes('java')) {
50
- if (lines.length > 1) lines.push('');
51
- lines.push('# Java');
52
- lines.push('mvn test # Run tests');
53
- lines.push('mvn checkstyle:check # Lint');
54
- lines.push('mvn spotless:apply # Format');
55
- }
56
- if (languages.includes('csharp')) {
57
- if (lines.length > 1) lines.push('');
58
- lines.push('# C# / .NET');
59
- lines.push('dotnet test # Run tests');
60
- lines.push('dotnet format --verify-no-changes # Lint');
61
- lines.push('dotnet format # Format');
62
- }
63
- if (languages.includes('cpp')) {
64
- if (lines.length > 1) lines.push('');
65
- lines.push('# C / C++');
66
- lines.push('cmake --build build && ctest # Build & test');
67
- lines.push('clang-tidy src/*.cpp # Lint');
68
- lines.push('clang-format -i src/*.[ch]pp # Format');
69
- }
70
- if (languages.includes('go')) {
71
- if (lines.length > 1) lines.push('');
72
- lines.push('# Go');
73
- lines.push('go test ./... # Run tests');
74
- lines.push('golangci-lint run # Lint');
75
- lines.push('gofmt -w . # Format');
76
- }
77
- if (languages.includes('php')) {
78
- if (lines.length > 1) lines.push('');
79
- lines.push('# PHP');
80
- lines.push('vendor/bin/phpunit # Run tests');
81
- lines.push('vendor/bin/phpstan analyse # Lint');
82
- lines.push('vendor/bin/php-cs-fixer fix . # Format');
83
- }
84
- if (languages.includes('ruby')) {
85
- if (lines.length > 1) lines.push('');
86
- lines.push('# Ruby');
87
- lines.push('bundle exec rspec # Run tests');
88
- lines.push('rubocop # Lint');
89
- lines.push('rubocop -A # Format');
90
- }
91
- if (languages.includes('kotlin')) {
92
- if (lines.length > 1) lines.push('');
93
- lines.push('# Kotlin');
94
- lines.push('gradle test # Run tests');
95
- lines.push('detekt # Lint');
96
- lines.push('ktlint -F # Format');
97
- }
98
- if (languages.includes('swift')) {
99
- if (lines.length > 1) lines.push('');
100
- lines.push('# Swift');
101
- lines.push('swift test # Run tests');
102
- lines.push('swiftlint # Lint');
103
- lines.push('swift-format format -r . -i # Format');
104
- }
105
- if (languages.includes('rust')) {
106
- if (lines.length > 1) lines.push('');
107
- lines.push('# Rust');
108
- lines.push('cargo test # Run tests');
109
- lines.push('cargo clippy # Lint');
110
- lines.push('cargo fmt # Format');
111
- }
112
- if (languages.includes('dart')) {
113
- if (lines.length > 1) lines.push('');
114
- lines.push('# Dart / Flutter');
115
- lines.push('dart test # Run tests');
116
- lines.push('dart analyze # Lint');
117
- lines.push('dart format . # Format');
118
- }
119
- if (languages.includes('scala')) {
120
- if (lines.length > 1) lines.push('');
121
- lines.push('# Scala');
122
- lines.push('sbt test # Run tests');
123
- lines.push('sbt scalafix # Lint');
124
- lines.push('scalafmt # Format');
125
- }
126
- if (languages.includes('elixir')) {
127
- if (lines.length > 1) lines.push('');
128
- lines.push('# Elixir');
129
- lines.push('mix test # Run tests');
130
- lines.push('mix credo # Lint');
131
- lines.push('mix format # Format');
132
- }
133
- if (languages.includes('zig')) {
159
+ for (const lang of languages) {
160
+ const entry = LANGUAGE_COMMANDS[lang];
161
+ if (!entry) continue;
134
162
  if (lines.length > 1) lines.push('');
135
- lines.push('# Zig');
136
- lines.push('zig build test # Run tests');
137
- lines.push('zig build # Build (lint via compiler)');
138
- lines.push('zig fmt . # Format');
163
+ lines.push(`# ${entry.heading}`);
164
+ lines.push(...entry.commands);
139
165
  }
140
166
  if (useDocker) {
141
167
  if (lines.length > 1) lines.push('');
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- import { readWorkflowMeta, workflowMetaExists, getPackageVersion } from '../core/config.js';
2
+ import { requireWorkflowMeta, getPackageVersion } from '../core/config.js';
3
3
  import { hashFile } from '../utils/hash.js';
4
4
  import { fileExists, readFile, listFilesRecursive } from '../utils/file.js';
5
5
  import { getLatestNpmVersion } from '../utils/npm.js';
@@ -15,13 +15,12 @@ function countByPrefix(fileHashes, prefix) {
15
15
  export async function statusCommand() {
16
16
  const projectRoot = process.cwd();
17
17
 
18
- if (!(await workflowMetaExists(projectRoot))) {
18
+ const { meta, error } = await requireWorkflowMeta(projectRoot);
19
+ if (error === 'not-installed') {
19
20
  display.info('Workflow is not installed. Run `worclaude init` to set up.');
20
21
  return;
21
22
  }
22
-
23
- const meta = await readWorkflowMeta(projectRoot);
24
- if (!meta) {
23
+ if (error === 'corrupted') {
25
24
  display.error('workflow-meta.json is corrupted. Run `worclaude init` to reinstall.');
26
25
  return;
27
26
  }
@@ -4,8 +4,7 @@ import inquirer from 'inquirer';
4
4
  import ora from 'ora';
5
5
  import {
6
6
  computeFileHashes,
7
- readWorkflowMeta,
8
- workflowMetaExists,
7
+ requireWorkflowMeta,
9
8
  writeWorkflowMeta,
10
9
  getPackageVersion,
11
10
  } from '../core/config.js';
@@ -70,16 +69,13 @@ export async function upgradeCommand() {
70
69
  }
71
70
 
72
71
  // 2. Check prerequisite
73
- if (!(await workflowMetaExists(projectRoot))) {
74
- display.error('No workflow installation found.');
75
- display.info('Run `worclaude init` to set up the workflow first.');
72
+ const { meta, error } = await requireWorkflowMeta(projectRoot);
73
+ if (error === 'not-installed') {
74
+ display.info('Workflow is not installed. Run `worclaude init` to set up.');
76
75
  return;
77
76
  }
78
-
79
- const meta = await readWorkflowMeta(projectRoot);
80
- if (!meta) {
81
- display.error('workflow-meta.json is corrupted or invalid.');
82
- display.info('Run `worclaude init` to reinstall (a backup will be created first).');
77
+ if (error === 'corrupted') {
78
+ display.error('workflow-meta.json is corrupted. Run `worclaude init` to reinstall.');
83
79
  return;
84
80
  }
85
81
 
@@ -59,6 +59,17 @@ export async function writeWorkflowMeta(projectRoot, meta) {
59
59
  await writeFile(metaPath, JSON.stringify(meta, null, 2));
60
60
  }
61
61
 
62
+ export async function requireWorkflowMeta(projectRoot) {
63
+ if (!(await workflowMetaExists(projectRoot))) {
64
+ return { meta: null, error: 'not-installed' };
65
+ }
66
+ const meta = await readWorkflowMeta(projectRoot);
67
+ if (!meta) {
68
+ return { meta: null, error: 'corrupted' };
69
+ }
70
+ return { meta, error: null };
71
+ }
72
+
62
73
  export async function computeFileHashes(projectRoot) {
63
74
  const claudeDir = path.join(projectRoot, '.claude');
64
75
  const allFiles = await listFilesRecursive(claudeDir);
@@ -64,15 +64,6 @@ export const MODEL_BADGES = {
64
64
  haiku: badges.haiku,
65
65
  };
66
66
 
67
- export const CATEGORY_BADGES = {
68
- Backend: badges.backend,
69
- Frontend: badges.frontend,
70
- DevOps: badges.devops,
71
- Quality: badges.quality,
72
- Documentation: badges.docs,
73
- 'Data / AI': badges.dataai,
74
- };
75
-
76
67
  export const STACK_BADGES = {
77
68
  Python: badges.python,
78
69
  'Node.js / TypeScript': badges.node,
@@ -11,6 +11,9 @@ disallowedTools:
11
11
  maxTurns: 40
12
12
  omitClaudeMd: true
13
13
  memory: project
14
+ skills:
15
+ - security-checklist
16
+ criticalSystemReminder: "CRITICAL: You CANNOT edit files. Report vulnerabilities with remediation guidance only."
14
17
  ---
15
18
 
16
19
  You are a senior application security engineer performing a code
@@ -10,6 +10,7 @@ disallowedTools:
10
10
  - Agent
11
11
  maxTurns: 30
12
12
  omitClaudeMd: true
13
+ criticalSystemReminder: "CRITICAL: You CANNOT edit files. Review and report findings only."
13
14
  ---
14
15
 
15
16
  You are a senior staff engineer reviewing an implementation plan.
@@ -5,6 +5,8 @@ model: sonnet
5
5
  isolation: worktree
6
6
  maxTurns: 50
7
7
  memory: project
8
+ skills:
9
+ - testing
8
10
  ---
9
11
 
10
12
  You are a test specialist. You write comprehensive, meaningful tests
@@ -5,6 +5,8 @@ model: sonnet
5
5
  isolation: worktree
6
6
  background: true
7
7
  maxTurns: 50
8
+ initialPrompt: "/start"
9
+ criticalSystemReminder: "CRITICAL: You are verification-only. Do NOT edit or fix code. Report findings with exact reproduction steps."
8
10
  ---
9
11
 
10
12
  You are a verification specialist. You test the actual running
@@ -110,6 +112,9 @@ You will feel the urge to skip checks. These are the excuses — recognize them:
110
112
  - **Config/Infrastructure**: validate syntax → dry-run where possible → check env vars
111
113
  - **Bug fixes**: reproduce original bug → verify fix → run regression tests
112
114
  - **Refactoring**: existing test suite must pass unchanged → diff public API surface
115
+ - **Mobile (iOS/Android)**: clean build → install on simulator/emulator → dump accessibility/UI tree, tap by coords, re-dump to verify → check crash logs (logcat / device console)
116
+ - **Database migrations**: run migration up → verify schema matches intent → run migration down (reversibility) → test against existing data, not just empty DB
117
+ - **Data/ML pipeline**: run with sample input → verify output shape/schema/types → test empty input and NaN/null handling → check row counts in vs out for silent data loss
113
118
 
114
119
  ## Before Issuing PASS
115
120
 
@@ -7,23 +7,51 @@
7
7
  ## User
8
8
 
9
9
  <!-- Role, preferences, expertise — helps Claude tailor responses -->
10
+ <!-- Example: - [Backend lead](user_role.md) — 8 years Python, new to this frontend -->
10
11
 
11
12
  ## Feedback
12
13
 
13
14
  <!-- What to do and what to avoid — both corrections AND confirmed approaches -->
14
15
  <!-- Format: rule, then **Why:** and **How to apply:** -->
16
+ <!-- Example: - [No mocks in integration tests](feedback_testing.md) — burned by mock/prod divergence -->
15
17
 
16
18
  ## Project
17
19
 
18
20
  <!-- Ongoing work, goals, deadlines — convert relative dates to absolute -->
19
21
  <!-- Format: fact/decision, then **Why:** and **How to apply:** -->
22
+ <!-- Example: - [Merge freeze 2026-03-05](project_release.md) — mobile team cutting release branch -->
20
23
 
21
24
  ## Reference
22
25
 
23
26
  <!-- Pointers to external systems — Linear boards, Slack channels, dashboards -->
27
+ <!-- Example: - [Pipeline bugs](reference_linear.md) — tracked in Linear project "INGEST" -->
24
28
 
25
29
  ---
26
30
 
31
+ ## Memory File Format
32
+
33
+ Each memory file in `.claude/memory/` uses this frontmatter:
34
+
35
+ ```markdown
36
+ ---
37
+ name: descriptive-name
38
+ description: one-line summary used to decide relevance in future sessions
39
+ type: user | feedback | project | reference
40
+ ---
41
+
42
+ Content here. For feedback/project types, structure as:
43
+ Rule or fact.
44
+ **Why:** the reason or context.
45
+ **How to apply:** when and where this guidance applies.
46
+ ```
47
+
48
+ ## Drift and Verification
49
+
50
+ - Memory records become stale over time. Before acting on a memory, verify it against the current state of the codebase.
51
+ - If a memory names a file path, check the file still exists. If it names a function or flag, grep for it.
52
+ - If a recalled memory conflicts with current information, trust what you observe now — update or remove the stale memory.
53
+ - "The memory says X exists" is not the same as "X exists now."
54
+
27
55
  ## What NOT to save here
28
56
 
29
57
  - Code patterns, architecture, file paths — derivable from current project state
@@ -31,3 +59,12 @@
31
59
  - Debugging solutions — the fix is in the code, the context is in the commit message
32
60
  - Anything already in CLAUDE.md
33
61
  - Ephemeral task details — current conversation context, in-progress work
62
+
63
+ These exclusions apply even when explicitly asked to save. If asked to save a PR list or activity summary, ask what was *surprising* or *non-obvious* about it — that is the part worth keeping.
64
+
65
+ ## Memory vs Plans vs Tasks
66
+
67
+ Memory is for information useful across conversations. Don't use it for:
68
+ - **Plans** — use a plan file or plan mode for implementation strategies within a session
69
+ - **Tasks** — use the task system for tracking work steps within a session
70
+ - **Session state** — current conversation context belongs in the conversation, not memory
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "How Claude writes rules for itself, when to update CLAUDE.md, keeping it lean and effective"
3
3
  when_to_use: "When considering updates to CLAUDE.md, when the same mistake has happened twice, when CLAUDE.md is getting too long"
4
+ version: "1.0.0"
4
5
  ---
5
6
 
6
7
  # CLAUDE.md Maintenance
@@ -99,6 +100,28 @@ The /update-claude-md command helps at session end:
99
100
  Always review proposed changes before applying. Not every mistake needs a rule.
100
101
  Only add rules for recurring problems.
101
102
 
103
+ ## The @include Directive
104
+
105
+ When CLAUDE.md grows beyond the 50-line target, use `@include` to split content
106
+ into separate files while keeping it loadable:
107
+
108
+ ```markdown
109
+ # CLAUDE.md
110
+ ## Key Files
111
+ @./docs/conventions.md
112
+ @./docs/api-standards.md
113
+ ```
114
+
115
+ - `@./relative` — relative to the file containing the directive
116
+ - `@~/path` — relative to home directory
117
+ - `@/absolute` — absolute path
118
+ - Works in CLAUDE.md, .claude/CLAUDE.md, .claude/rules/*.md, and CLAUDE.local.md
119
+ - Does NOT work inside code blocks (only in leaf text nodes)
120
+ - Non-existent files are silently ignored; circular references are prevented
121
+
122
+ This is the recommended alternative to cramming everything into CLAUDE.md.
123
+ Each included file still consumes context budget, so use judiciously.
124
+
102
125
  ## Gotchas
103
126
 
104
127
  - CLAUDE.md is read as system context, not as a document. Write it as instructions,
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "Context budget awareness, when to compact, when to clear, subagent offloading"
3
3
  when_to_use: "When context is running low, before compaction decisions, when deciding whether to use subagents for context hygiene"
4
+ version: "1.0.0"
4
5
  ---
5
6
 
6
7
  # Context Management
@@ -117,6 +118,29 @@ WORCLAUDE_HOOK_PROFILE=strict claude
117
118
  The default is `standard` if the variable is not set. You don't need to do
118
119
  anything for normal development — the default just works.
119
120
 
121
+ ## Token Budgets (Reference)
122
+
123
+ Approximate values from Claude Code v2.1.88 source (March 2026). These may change between releases.
124
+
125
+ | Resource | Budget |
126
+ |---|---|
127
+ | Context window (default) | 200,000 tokens |
128
+ | Context window (Opus 4.6 / Sonnet 4.6 with 1M) | 1,000,000 tokens |
129
+ | Max output tokens (Sonnet 4.6) | 32,000 default, 128,000 upper limit |
130
+ | Max output tokens (Opus 4.6) | 64,000 default, 128,000 upper limit |
131
+ | Tool presence overhead | ~500 tokens (added when any tools are enabled) |
132
+ | Post-compact file restore | 5 files max, 50,000 token budget, 5,000 per file |
133
+ | Post-compact skills restore | 25,000 token budget, 5,000 per skill |
134
+ | Compact summary output | 20,000 tokens max |
135
+ | CLAUDE.md total budget | ~40,000 characters across all loaded instruction files |
136
+ | MEMORY.md | 200 lines / 25,000 bytes |
137
+
138
+ Practical takeaways:
139
+ - After compaction, only 5 files are restored at 5k tokens each. Structure your work
140
+ so the most important files are recently read.
141
+ - Skills over 5k tokens get truncated after compaction. Keep skills focused.
142
+ - The 70% rule still applies — these numbers help you estimate when you'll hit it.
143
+
120
144
  ## Gotchas
121
145
 
122
146
  - Compacting doesn't free as much context as you think. If you've read 20 large files,
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: 'Multi-agent orchestration patterns: when to use coordinator mode, worker prompts, parallel execution'
3
3
  when_to_use: 'When working with multiple agents or terminals in parallel, or when deciding how to break a large task into coordinated sub-tasks'
4
+ version: "1.0.0"
4
5
  ---
5
6
 
6
7
  # Coordinator Mode
@@ -20,6 +21,25 @@ Don't use coordinator patterns when:
20
21
  - Steps are strictly sequential with no parallelism
21
22
  - The overhead of coordination exceeds the work itself
22
23
 
24
+ ## Phase-Based Workflow
25
+
26
+ Most coordinated tasks follow four phases:
27
+
28
+ | Phase | Who | Purpose |
29
+ |-------|-----|---------|
30
+ | Research | Workers (parallel) | Investigate codebase, find files, understand problem |
31
+ | Synthesis | **You** (coordinator) | Read findings, understand the problem, craft implementation specs |
32
+ | Implementation | Workers | Make targeted changes per spec, commit |
33
+ | Verification | Workers | Test changes work, try to break them |
34
+
35
+ The synthesis phase is the coordinator's most important job. When workers report
36
+ research findings, **you must understand them before directing follow-up work**.
37
+ Read the findings. Identify the approach. Then write a prompt that proves you
38
+ understood by including specific file paths, line numbers, and exactly what to change.
39
+
40
+ Never write "based on your findings" or "based on the research." These phrases
41
+ delegate understanding to the worker instead of doing it yourself.
42
+
23
43
  ## Worker Prompt Best Practices
24
44
 
25
45
  Workers cannot see your conversation. Every prompt must be self-contained:
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "Branch naming, commit message format, PR workflow, worktree conventions, versioning policy"
3
3
  when_to_use: "When creating branches, writing commit messages, creating PRs, or making versioning decisions"
4
+ version: "1.0.0"
4
5
  ---
5
6
 
6
7
  # Git Conventions
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "How to structure implementation plans as files, progressive implementation, plan review process"
3
3
  when_to_use: "When starting a multi-step task that needs a written plan, or when reviewing an existing implementation plan"
4
+ version: "1.0.0"
4
5
  ---
5
6
 
6
7
  # Planning with Files
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "Effective prompting patterns for working with Claude, demanding quality, writing specs"
3
3
  when_to_use: "When writing or editing prompts, skills, agent definitions, or CLAUDE.md instructions"
4
+ version: "1.0.0"
4
5
  ---
5
6
 
6
7
  # Prompt Engineering
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "Session ending protocol, HANDOFF document format, seamless continuation between sessions"
3
3
  when_to_use: "When ending a session, writing handoff documents, or updating PROGRESS.md"
4
+ version: "1.0.0"
4
5
  ---
5
6
 
6
7
  # Review and Handoff
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "OWASP-based security checklist any agent can reference when reviewing or writing code"
3
3
  when_to_use: "When writing code that handles user input, authentication, authorization, file uploads, or external data"
4
+ version: "1.0.0"
4
5
  paths:
5
6
  - "**/auth/**"
6
7
  - "**/security/**"
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "When to use subagents, how many, context hygiene, worktree isolation patterns"
3
3
  when_to_use: "When deciding whether to spawn a subagent, choosing between parallel and sequential execution, or giving subagent instructions"
4
+ version: "1.0.0"
4
5
  ---
5
6
 
6
7
  # Subagent Usage
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "Test philosophy, coverage strategy, test-first patterns, what to test and what not to"
3
3
  when_to_use: "When writing, modifying, or reviewing tests, or when making decisions about test strategy and coverage"
4
+ version: "1.0.0"
4
5
  paths:
5
6
  - "test/**"
6
7
  - "tests/**"
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: "Domain-specific verification beyond tests, closing the feedback loop for web, API, CLI, data"
3
3
  when_to_use: "When verifying that implemented changes work correctly, after running automated tests, before committing"
4
+ version: "1.0.0"
4
5
  paths:
5
6
  - "test/**"
6
7
  - "tests/**"