worclaude 1.9.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.
Files changed (76) hide show
  1. package/README.md +42 -3
  2. package/package.json +1 -1
  3. package/src/commands/backup.js +5 -3
  4. package/src/commands/delete.js +6 -9
  5. package/src/commands/diff.js +4 -5
  6. package/src/commands/doctor.js +265 -3
  7. package/src/commands/init.js +162 -106
  8. package/src/commands/status.js +4 -5
  9. package/src/commands/upgrade.js +52 -10
  10. package/src/core/config.js +11 -0
  11. package/src/core/detector.js +2 -1
  12. package/src/core/file-categorizer.js +4 -4
  13. package/src/core/merger.js +16 -14
  14. package/src/core/migration.js +144 -0
  15. package/src/core/remover.js +3 -1
  16. package/src/core/scaffolder.js +7 -1
  17. package/src/data/agents.js +2 -0
  18. package/src/utils/display.js +0 -9
  19. package/src/utils/file.js +21 -0
  20. package/templates/agents/optional/backend/api-designer.md +6 -0
  21. package/templates/agents/optional/backend/auth-auditor.md +2 -0
  22. package/templates/agents/optional/backend/database-analyst.md +7 -0
  23. package/templates/agents/optional/data/data-pipeline-reviewer.md +7 -0
  24. package/templates/agents/optional/data/ml-experiment-tracker.md +7 -0
  25. package/templates/agents/optional/data/prompt-engineer.md +2 -0
  26. package/templates/agents/optional/devops/ci-fixer.md +2 -0
  27. package/templates/agents/optional/devops/dependency-manager.md +7 -0
  28. package/templates/agents/optional/devops/deploy-validator.md +7 -0
  29. package/templates/agents/optional/devops/docker-helper.md +2 -0
  30. package/templates/agents/optional/docs/changelog-generator.md +7 -0
  31. package/templates/agents/optional/docs/doc-writer.md +3 -0
  32. package/templates/agents/optional/frontend/style-enforcer.md +2 -0
  33. package/templates/agents/optional/frontend/ui-reviewer.md +7 -0
  34. package/templates/agents/optional/quality/bug-fixer.md +2 -0
  35. package/templates/agents/optional/quality/build-fixer.md +2 -0
  36. package/templates/agents/optional/quality/e2e-runner.md +3 -0
  37. package/templates/agents/optional/quality/performance-auditor.md +8 -0
  38. package/templates/agents/optional/quality/refactorer.md +2 -0
  39. package/templates/agents/optional/quality/security-reviewer.md +12 -0
  40. package/templates/agents/universal/build-validator.md +3 -0
  41. package/templates/agents/universal/code-simplifier.md +2 -0
  42. package/templates/agents/universal/plan-reviewer.md +9 -0
  43. package/templates/agents/universal/test-writer.md +6 -1
  44. package/templates/agents/universal/verify-app.md +46 -0
  45. package/templates/commands/build-fix.md +4 -0
  46. package/templates/commands/commit-push-pr.md +11 -0
  47. package/templates/commands/compact-safe.md +4 -0
  48. package/templates/commands/conflict-resolver.md +4 -0
  49. package/templates/commands/end.md +13 -0
  50. package/templates/commands/refactor-clean.md +4 -0
  51. package/templates/commands/review-changes.md +4 -0
  52. package/templates/commands/review-plan.md +4 -0
  53. package/templates/commands/setup.md +7 -3
  54. package/templates/commands/start.md +5 -1
  55. package/templates/commands/status.md +4 -0
  56. package/templates/commands/sync.md +4 -0
  57. package/templates/commands/techdebt.md +4 -0
  58. package/templates/commands/test-coverage.md +4 -0
  59. package/templates/commands/update-claude-md.md +4 -0
  60. package/templates/commands/verify.md +4 -0
  61. package/templates/core/claude-md.md +13 -12
  62. package/templates/core/memory-md.md +61 -0
  63. package/templates/skills/templates/backend-conventions.md +6 -0
  64. package/templates/skills/templates/frontend-design-system.md +10 -0
  65. package/templates/skills/templates/project-patterns.md +4 -0
  66. package/templates/skills/universal/claude-md-maintenance.md +2 -0
  67. package/templates/skills/universal/context-management.md +2 -0
  68. package/templates/skills/universal/coordinator-mode.md +78 -0
  69. package/templates/skills/universal/git-conventions.md +2 -0
  70. package/templates/skills/universal/planning-with-files.md +2 -0
  71. package/templates/skills/universal/prompt-engineering.md +2 -0
  72. package/templates/skills/universal/review-and-handoff.md +2 -0
  73. package/templates/skills/universal/security-checklist.md +8 -0
  74. package/templates/skills/universal/subagent-usage.md +2 -0
  75. package/templates/skills/universal/testing.md +8 -0
  76. package/templates/skills/universal/verification.md +7 -0
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": "1.9.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 ora from 'ora';
3
3
  import { createBackup } from '../core/backup.js';
4
- import { fileExists, dirExists, listFiles } from '../utils/file.js';
4
+ import { fileExists, dirExists, listFiles, listSkillDirs } from '../utils/file.js';
5
5
  import * as display from '../utils/display.js';
6
6
 
7
7
  export async function backupCommand() {
@@ -33,11 +33,13 @@ export async function backupCommand() {
33
33
  if (await dirExists(claudeBackup)) {
34
34
  const agents = await listFiles(path.join(claudeBackup, 'agents'));
35
35
  const commands = await listFiles(path.join(claudeBackup, 'commands'));
36
- const skills = await listFiles(path.join(claudeBackup, 'skills'));
36
+ const skillFiles = await listFiles(path.join(claudeBackup, 'skills'));
37
+ const skillDirs = await listSkillDirs(path.join(claudeBackup, 'skills'));
38
+ const skillCount = skillDirs.length + skillFiles.length;
37
39
  const parts = [];
38
40
  if (agents.length > 0) parts.push(`${agents.length} agents`);
39
41
  if (commands.length > 0) parts.push(`${commands.length} commands`);
40
- if (skills.length > 0) parts.push(`${skills.length} skills`);
42
+ if (skillCount > 0) parts.push(`${skillCount} skills`);
41
43
  contents.push(`.claude/ (${parts.join(', ')})`);
42
44
  }
43
45
 
@@ -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
  }
@@ -1,3 +1,4 @@
1
+ import fs from 'fs-extra';
1
2
  import path from 'node:path';
2
3
  import { readWorkflowMeta, workflowMetaExists, getPackageVersion } from '../core/config.js';
3
4
  import { hashFile } from '../utils/hash.js';
@@ -72,6 +73,48 @@ async function checkClaudeMd(projectRoot) {
72
73
  }
73
74
  }
74
75
 
76
+ async function checkClaudeMdSize(projectRoot) {
77
+ const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
78
+ if (!(await fileExists(claudeMdPath))) {
79
+ return []; // Already covered by existing checkClaudeMd
80
+ }
81
+ try {
82
+ const content = await readFile(claudeMdPath);
83
+ const charCount = content.length;
84
+ const WARN_THRESHOLD = 30000;
85
+ const FAIL_THRESHOLD = 38000;
86
+ const HARD_LIMIT = 40000;
87
+
88
+ if (charCount > FAIL_THRESHOLD) {
89
+ return [
90
+ result(
91
+ FAIL,
92
+ `CLAUDE.md size: ${charCount.toLocaleString()} chars`,
93
+ `Exceeds recommended limit (${FAIL_THRESHOLD.toLocaleString()}/${HARD_LIMIT.toLocaleString()}). Claude Code caps at ${HARD_LIMIT.toLocaleString()} chars. Move domain-specific content to conditional skills with paths frontmatter.`
94
+ ),
95
+ ];
96
+ }
97
+ if (charCount > WARN_THRESHOLD) {
98
+ return [
99
+ result(
100
+ WARN,
101
+ `CLAUDE.md size: ${charCount.toLocaleString()} chars`,
102
+ `Approaching limit (${WARN_THRESHOLD.toLocaleString()}/${HARD_LIMIT.toLocaleString()}). Consider moving content to skills.`
103
+ ),
104
+ ];
105
+ }
106
+ return [
107
+ result(
108
+ PASS,
109
+ `CLAUDE.md size: ${charCount.toLocaleString()} chars (limit: ${HARD_LIMIT.toLocaleString()})`,
110
+ null
111
+ ),
112
+ ];
113
+ } catch {
114
+ return [];
115
+ }
116
+ }
117
+
75
118
  async function checkSettingsJson(projectRoot) {
76
119
  const settingsPath = path.join(projectRoot, '.claude', 'settings.json');
77
120
  if (!(await fileExists(settingsPath))) {
@@ -134,6 +177,60 @@ async function checkAgents(projectRoot, meta) {
134
177
  return results;
135
178
  }
136
179
 
180
+ async function readAgentFrontmatters(projectRoot) {
181
+ const agentsDir = path.join(projectRoot, '.claude', 'agents');
182
+ try {
183
+ const entries = await fs.readdir(agentsDir, { withFileTypes: true });
184
+ const mdFiles = entries.filter((e) => e.isFile() && e.name.endsWith('.md'));
185
+ const agents = [];
186
+ for (const file of mdFiles) {
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
+ }
196
+
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;
208
+ }
209
+
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) {
216
+ results.push(
217
+ result(
218
+ FAIL,
219
+ `agents/${name}`,
220
+ 'Missing required "description" field — agent is invisible to Claude Code\'s /agents and routing'
221
+ )
222
+ );
223
+ }
224
+ }
225
+
226
+ if (results.length === 0) {
227
+ results.push(
228
+ result(PASS, `agents/ frontmatter (${agents.length} agents have required fields)`, null)
229
+ );
230
+ }
231
+ return results;
232
+ }
233
+
137
234
  async function checkCommands(projectRoot) {
138
235
  const commandsDir = path.join(projectRoot, '.claude', 'commands');
139
236
  const missing = [];
@@ -157,7 +254,7 @@ async function checkSkills(projectRoot) {
157
254
  const allExpected = [...UNIVERSAL_SKILLS, ...TEMPLATE_SKILLS, 'agent-routing'];
158
255
 
159
256
  for (const skill of allExpected) {
160
- const skillPath = path.join(skillsDir, `${skill}.md`);
257
+ const skillPath = path.join(skillsDir, skill, 'SKILL.md');
161
258
  if (!(await fileExists(skillPath))) {
162
259
  missing.push(skill);
163
260
  }
@@ -166,7 +263,49 @@ async function checkSkills(projectRoot) {
166
263
  if (missing.length === 0) {
167
264
  return [result(PASS, `skills/ (${allExpected.length} expected, all present)`, null)];
168
265
  }
169
- return missing.map((s) => result(WARN, `skills/${s}.md`, 'Missing skill'));
266
+ return missing.map((s) => result(WARN, `skills/${s}/SKILL.md`, 'Missing skill'));
267
+ }
268
+
269
+ async function checkSkillFormat(projectRoot) {
270
+ const skillsDir = path.join(projectRoot, '.claude', 'skills');
271
+ const results = [];
272
+
273
+ try {
274
+ const entries = await fs.readdir(skillsDir, { withFileTypes: true });
275
+ const flatMdFiles = entries
276
+ .filter((e) => e.isFile() && e.name.endsWith('.md'))
277
+ .map((e) => e.name);
278
+
279
+ if (flatMdFiles.length > 0) {
280
+ results.push(
281
+ result(
282
+ FAIL,
283
+ `skills/ has ${flatMdFiles.length} flat .md file(s)`,
284
+ `Flat .md files in .claude/skills/ are invisible to Claude Code. Expected format: skill-name/SKILL.md. Run \`worclaude upgrade\` to migrate. Files: ${flatMdFiles.join(', ')}`
285
+ )
286
+ );
287
+ }
288
+
289
+ // Also check directory-format skills exist
290
+ const skillDirs = entries.filter((e) => e.isDirectory());
291
+ let validDirSkills = 0;
292
+ for (const dir of skillDirs) {
293
+ const skillMd = path.join(skillsDir, dir.name, 'SKILL.md');
294
+ if (await fileExists(skillMd)) {
295
+ validDirSkills++;
296
+ }
297
+ }
298
+
299
+ if (validDirSkills > 0 && flatMdFiles.length === 0) {
300
+ results.push(
301
+ result(PASS, `skills/ format (${validDirSkills} directory-format skills)`, null)
302
+ );
303
+ }
304
+ } catch {
305
+ // skills/ doesn't exist — covered by existing component checks
306
+ }
307
+
308
+ return results;
170
309
  }
171
310
 
172
311
  async function checkHashIntegrity(projectRoot, meta) {
@@ -244,6 +383,124 @@ async function checkDocSpecs(projectRoot) {
244
383
  return results;
245
384
  }
246
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
+
247
504
  async function checkPendingReviewFiles(projectRoot) {
248
505
  const pending = [];
249
506
  try {
@@ -287,6 +544,8 @@ export async function doctorCommand() {
287
544
  const meta = await readWorkflowMeta(projectRoot);
288
545
 
289
546
  printResult(await checkClaudeMd(projectRoot));
547
+ for (const r of await checkClaudeMdSize(projectRoot)) printResult(r);
548
+ for (const r of await checkClaudeMdSections(projectRoot)) printResult(r);
290
549
  printResult(await checkSettingsJson(projectRoot));
291
550
  printResult(await checkSessions(projectRoot));
292
551
  display.newline();
@@ -294,8 +553,11 @@ export async function doctorCommand() {
294
553
  // Components
295
554
  display.barLine(display.white('Components'));
296
555
  for (const r of await checkAgents(projectRoot, meta)) printResult(r);
556
+ for (const r of await checkAgentDescription(projectRoot)) printResult(r);
297
557
  for (const r of await checkCommands(projectRoot)) printResult(r);
298
558
  for (const r of await checkSkills(projectRoot)) printResult(r);
559
+ for (const r of await checkSkillFormat(projectRoot)) printResult(r);
560
+ for (const r of await checkAgentCompleteness(projectRoot)) printResult(r);
299
561
  display.newline();
300
562
 
301
563
  // Docs
@@ -311,7 +573,7 @@ export async function doctorCommand() {
311
573
 
312
574
  // Summary
313
575
  if (metaResult.status === FAIL) {
314
- 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.');
315
577
  } else {
316
578
  display.success('Doctor complete. Review any warnings above.');
317
579
  }