worclaude 2.0.0 → 2.1.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.1.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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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/**"