worclaude 2.7.1 → 2.9.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 (83) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +72 -56
  3. package/package.json +1 -1
  4. package/src/commands/doc-lint.js +37 -0
  5. package/src/commands/doctor.js +145 -0
  6. package/src/commands/init.js +144 -44
  7. package/src/commands/observability.js +24 -0
  8. package/src/commands/regenerate-routing.js +70 -0
  9. package/src/commands/status.js +14 -0
  10. package/src/commands/upgrade.js +87 -1
  11. package/src/commands/worktrees.js +90 -0
  12. package/src/core/config.js +10 -1
  13. package/src/core/file-categorizer.js +16 -0
  14. package/src/core/merger.js +42 -20
  15. package/src/core/scaffolder.js +26 -0
  16. package/src/data/agents.js +14 -28
  17. package/src/data/optional-features.js +46 -0
  18. package/src/generators/agent-routing.js +189 -34
  19. package/src/index.js +37 -0
  20. package/src/prompts/agent-selection.js +11 -3
  21. package/src/utils/agent-frontmatter.js +109 -0
  22. package/src/utils/doc-lint.js +196 -0
  23. package/src/utils/observability.js +300 -0
  24. package/templates/agents/optional/backend/api-designer.md +7 -1
  25. package/templates/agents/optional/backend/auth-auditor.md +7 -1
  26. package/templates/agents/optional/backend/database-analyst.md +7 -1
  27. package/templates/agents/optional/data/data-pipeline-reviewer.md +7 -1
  28. package/templates/agents/optional/data/ml-experiment-tracker.md +7 -1
  29. package/templates/agents/optional/data/prompt-engineer.md +7 -1
  30. package/templates/agents/optional/devops/ci-fixer.md +7 -1
  31. package/templates/agents/optional/devops/dependency-manager.md +7 -1
  32. package/templates/agents/optional/devops/deploy-validator.md +7 -1
  33. package/templates/agents/optional/devops/docker-helper.md +7 -1
  34. package/templates/agents/optional/docs/changelog-generator.md +9 -1
  35. package/templates/agents/optional/docs/doc-writer.md +7 -1
  36. package/templates/agents/optional/frontend/style-enforcer.md +7 -1
  37. package/templates/agents/optional/frontend/ui-reviewer.md +7 -1
  38. package/templates/agents/optional/quality/bug-fixer.md +19 -1
  39. package/templates/agents/optional/quality/build-fixer.md +7 -1
  40. package/templates/agents/optional/quality/performance-auditor.md +8 -1
  41. package/templates/agents/optional/quality/refactorer.md +7 -1
  42. package/templates/agents/optional/quality/security-reviewer.md +7 -1
  43. package/templates/agents/universal/build-validator.md +7 -1
  44. package/templates/agents/universal/code-simplifier.md +8 -1
  45. package/templates/agents/universal/plan-reviewer.md +8 -1
  46. package/templates/agents/universal/test-writer.md +19 -1
  47. package/templates/agents/universal/upstream-watcher.md +8 -1
  48. package/templates/agents/universal/verify-app.md +45 -3
  49. package/templates/commands/build-fix.md +30 -11
  50. package/templates/commands/commit-push-pr.md +47 -24
  51. package/templates/commands/compact-safe.md +79 -7
  52. package/templates/commands/conflict-resolver.md +7 -3
  53. package/templates/commands/end.md +63 -17
  54. package/templates/commands/learn.md +72 -8
  55. package/templates/commands/observability.md +59 -0
  56. package/templates/commands/refactor-clean.md +44 -2
  57. package/templates/commands/review-changes.md +40 -11
  58. package/templates/commands/review-plan.md +83 -10
  59. package/templates/commands/start.md +61 -30
  60. package/templates/commands/sync.md +86 -6
  61. package/templates/commands/test-coverage.md +78 -12
  62. package/templates/commands/update-claude-md.md +96 -7
  63. package/templates/commands/verify.md +32 -8
  64. package/templates/core/claude-md.md +9 -0
  65. package/templates/hooks/correction-detect.cjs +1 -1
  66. package/templates/hooks/learn-capture.cjs +0 -2
  67. package/templates/hooks/obs-agent-events.cjs +55 -0
  68. package/templates/hooks/obs-command-invocations.cjs +53 -0
  69. package/templates/hooks/obs-skill-loads.cjs +54 -0
  70. package/templates/hooks/skill-hint.cjs +22 -2
  71. package/templates/scripts/start-drift.sh +29 -0
  72. package/templates/scripts/sync-release-scope.sh +17 -0
  73. package/templates/scripts/test-coverage-changed-files.sh +14 -0
  74. package/templates/settings/base.json +73 -0
  75. package/templates/skills/universal/claude-md-maintenance.md +50 -14
  76. package/templates/skills/universal/git-conventions.md +11 -1
  77. package/templates/skills/universal/memory-architecture.md +115 -0
  78. package/templates/skills/universal/subagent-usage.md +15 -2
  79. package/src/data/agent-registry.js +0 -365
  80. package/templates/agents/optional/quality/e2e-runner.md +0 -98
  81. package/templates/commands/status.md +0 -15
  82. package/templates/commands/techdebt.md +0 -18
  83. package/templates/commands/upstream-check.md +0 -85
@@ -10,6 +10,12 @@
10
10
  {tech_stack_filled_during_init}
11
11
 
12
12
  ## Commands
13
+
14
+ <!-- references package.json (or equivalent for non-Node stacks) -->
15
+ The verification commands below are filled during init from the project's
16
+ package manager scripts. Reference them by script name; do not restate the
17
+ underlying tool invocations.
18
+
13
19
  {commands_filled_during_init}
14
20
 
15
21
  ## Skills (read on demand, not upfront)
@@ -35,6 +41,7 @@ See `.claude/skills/` — load only what's relevant:
35
41
  **Feature branch:** /start → work → /verify → /commit-push-pr
36
42
  **After merging PRs:** git checkout develop → git pull → /conflict-resolver (if needed) → /sync
37
43
  **Mid-task stop:** /end (writes handoff file)
44
+ **Trigger discipline:** /commit-push-pr and /sync execute only when the human types them. They do not run autonomously after work "feels done."
38
45
 
39
46
  ## Critical Rules
40
47
  1. SPEC.md is source of truth. Do not invent features.
@@ -49,6 +56,7 @@ See `.claude/skills/` — load only what's relevant:
49
56
  10. Surgical changes only — every changed line must trace to the request. Don't "improve" adjacent code, comments, or formatting.
50
57
  11. Push back when simpler approaches exist. Present alternatives, don't pick silently.
51
58
  12. Transform tasks to success criteria. "Fix the bug" → "Write a failing test, then make it pass."
59
+ 13. Commit, push, and PR only when the human explicitly invokes /commit-push-pr or /sync. Never run git commit, git push, or gh pr create on your own initiative, never invoke those slash commands without an explicit human trigger, and never auto-answer the Version bump: question — refuse to proceed without a human-selected option.
52
60
 
53
61
  ## Memory Architecture
54
62
 
@@ -58,6 +66,7 @@ See `.claude/skills/` — load only what's relevant:
58
66
  - Path-scoped rules: `.claude/rules/` with YAML frontmatter.
59
67
  - Session state: `.claude/sessions/` (gitignored).{memory_architecture_extras}
60
68
  - Do NOT write session learnings or auto-captured patterns here.
69
+ - If your repository has the Claude Code GitHub Action installed (run `/install-github-action`), `@claude` mentions in PR comments will automatically propose CLAUDE.md updates.
61
70
 
62
71
  ## Learnings
63
72
 
@@ -37,7 +37,7 @@ try {
37
37
  );
38
38
  } else if (correctionPatterns.some((p) => p.test(prompt))) {
39
39
  process.stdout.write(
40
- '[Correction detected] Consider proposing a [LEARN] block if this is a generalizable rule.\n'
40
+ '[Correction detected — semi-auto] Draft a one-line generalizable rule, then prompt via AskUserQuestion: "Capture as team learning? yes / yes, let me edit / no". On yes or yes-edit, emit a [LEARN] block; the Stop hook will persist it.\n'
41
41
  );
42
42
  }
43
43
  }
@@ -139,7 +139,6 @@ try {
139
139
  `created: ${today}`,
140
140
  `category: ${learning.category}`,
141
141
  `project: ${projectName}`,
142
- 'times_applied: 0',
143
142
  '---',
144
143
  '',
145
144
  `**Rule:** ${learning.rule}`,
@@ -163,7 +162,6 @@ try {
163
162
  file: filename,
164
163
  category: learning.category,
165
164
  created: today,
166
- times_applied: 0,
167
165
  });
168
166
  }
169
167
  }
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // SubagentStart and SubagentStop hook: records each agent event to
5
+ // .claude/observability/agent-events.jsonl. The aggregator
6
+ // (worclaude observability) pairs start+stop on session+agent to
7
+ // compute durations — keeping the hook stateless.
8
+ //
9
+ // Single hook serves both events; the input.event field tells which
10
+ // fired. Always exits 0.
11
+
12
+ const { readFileSync, appendFileSync, mkdirSync, existsSync } = require('fs');
13
+ const { join } = require('path');
14
+
15
+ function main() {
16
+ let input;
17
+ try {
18
+ input = JSON.parse(readFileSync(0, 'utf8'));
19
+ } catch {
20
+ return;
21
+ }
22
+
23
+ const cwd = process.env.CLAUDE_PROJECT_DIR || input.cwd || process.cwd();
24
+ const obsDir = join(cwd, '.claude', 'observability');
25
+ if (!existsSync(obsDir)) {
26
+ try {
27
+ mkdirSync(obsDir, { recursive: true });
28
+ } catch {
29
+ return;
30
+ }
31
+ }
32
+
33
+ const event = input.event || input.hook_event_name || 'unknown';
34
+ const phase = /stop$/i.test(event) ? 'stop' : 'start';
35
+
36
+ const entry = {
37
+ ts: new Date().toISOString(),
38
+ event: phase,
39
+ agent: input.agent_name || input.subagent_type || input.agent || 'unknown',
40
+ };
41
+ if (input.session_id) entry.session = input.session_id;
42
+ if (phase === 'stop' && input.exit_status) entry.exit = input.exit_status;
43
+
44
+ try {
45
+ appendFileSync(join(obsDir, 'agent-events.jsonl'), JSON.stringify(entry) + '\n');
46
+ } catch {
47
+ // Non-critical
48
+ }
49
+ }
50
+
51
+ try {
52
+ main();
53
+ } catch {
54
+ // Never block session
55
+ }
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // UserPromptSubmit hook: records slash-command invocations to
5
+ // .claude/observability/command-invocations.jsonl. Reads JSON from stdin
6
+ // per Claude Code hook contract. Skips non-slash prompts (filter is
7
+ // `/^/`). Always exits 0.
8
+
9
+ const { readFileSync, appendFileSync, mkdirSync, existsSync } = require('fs');
10
+ const { join } = require('path');
11
+
12
+ const SLASH_RE = /^\s*\/([\w-]+)/;
13
+
14
+ function main() {
15
+ let input;
16
+ try {
17
+ input = JSON.parse(readFileSync(0, 'utf8'));
18
+ } catch {
19
+ return;
20
+ }
21
+
22
+ const prompt = input.prompt || input.user_prompt || input.text || '';
23
+ const match = SLASH_RE.exec(prompt);
24
+ if (!match) return;
25
+
26
+ const cwd = process.env.CLAUDE_PROJECT_DIR || input.cwd || process.cwd();
27
+ const obsDir = join(cwd, '.claude', 'observability');
28
+ if (!existsSync(obsDir)) {
29
+ try {
30
+ mkdirSync(obsDir, { recursive: true });
31
+ } catch {
32
+ return;
33
+ }
34
+ }
35
+
36
+ const entry = {
37
+ ts: new Date().toISOString(),
38
+ command: '/' + match[1],
39
+ };
40
+ if (input.session_id) entry.session = input.session_id;
41
+
42
+ try {
43
+ appendFileSync(join(obsDir, 'command-invocations.jsonl'), JSON.stringify(entry) + '\n');
44
+ } catch {
45
+ // Non-critical
46
+ }
47
+ }
48
+
49
+ try {
50
+ main();
51
+ } catch {
52
+ // Never block session
53
+ }
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // InstructionsLoaded hook: records each skill load to
5
+ // .claude/observability/skill-loads.jsonl. Reads JSON from stdin per Claude
6
+ // Code hook contract. Always exits 0 — never blocks the session.
7
+
8
+ const { readFileSync, appendFileSync, mkdirSync, existsSync } = require('fs');
9
+ const { join } = require('path');
10
+
11
+ function main() {
12
+ let input;
13
+ try {
14
+ input = JSON.parse(readFileSync(0, 'utf8'));
15
+ } catch {
16
+ return;
17
+ }
18
+
19
+ const cwd = process.env.CLAUDE_PROJECT_DIR || input.cwd || process.cwd();
20
+ const obsDir = join(cwd, '.claude', 'observability');
21
+ if (!existsSync(obsDir)) {
22
+ try {
23
+ mkdirSync(obsDir, { recursive: true });
24
+ } catch {
25
+ return;
26
+ }
27
+ }
28
+
29
+ const skill =
30
+ input.skill_name ||
31
+ input.skill ||
32
+ input.instructions_name ||
33
+ (input.path && String(input.path).split('/').filter(Boolean).slice(-2, -1)[0]) ||
34
+ 'unknown';
35
+ const trigger = input.trigger || input.reason || 'unknown';
36
+
37
+ const entry = {
38
+ ts: new Date().toISOString(),
39
+ skill,
40
+ trigger,
41
+ };
42
+
43
+ try {
44
+ appendFileSync(join(obsDir, 'skill-loads.jsonl'), JSON.stringify(entry) + '\n');
45
+ } catch {
46
+ // Non-critical
47
+ }
48
+ }
49
+
50
+ try {
51
+ main();
52
+ } catch {
53
+ // Never block session
54
+ }
@@ -2,7 +2,11 @@
2
2
  'use strict';
3
3
 
4
4
  // UserPromptSubmit hook: hints at relevant skills based on user prompt keywords.
5
- // Reads .claude/skills/ directory, matches skill-name tokens against prompt tokens.
5
+ // Reads .claude/skills/ directory and matches prompt tokens against skill
6
+ // directory names AND each skill's `description:` frontmatter line. The
7
+ // description fallback lets renames stay in sync with intent (e.g. a skill
8
+ // named "compact-safe" still matches the prompt "session context budget"
9
+ // because its description mentions "context" and "session").
6
10
  // Outputs at most one hint to stdout if a match is found; empty output otherwise.
7
11
  // Always exits 0.
8
12
 
@@ -24,6 +28,18 @@ function tokenize(text) {
24
28
  .filter((w) => w.length >= 4 && !STOPWORDS.has(w));
25
29
  }
26
30
 
31
+ function readSkillDescription(skillsDir, slug) {
32
+ try {
33
+ const content = readFileSync(path.join(skillsDir, slug, 'SKILL.md'), 'utf8');
34
+ const fm = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
35
+ if (!fm) return '';
36
+ const desc = fm[1].match(/^description:\s*["']?(.+?)["']?\s*$/m);
37
+ return desc ? desc[1] : '';
38
+ } catch {
39
+ return '';
40
+ }
41
+ }
42
+
27
43
  try {
28
44
  const data = JSON.parse(readFileSync(0, 'utf8'));
29
45
  const prompt = data.input?.prompt || '';
@@ -50,7 +66,11 @@ try {
50
66
 
51
67
  for (const slug of skills) {
52
68
  const slugTokens = tokenize(slug);
53
- const hit = slugTokens.some((t) => promptTokens.has(t));
69
+ let hit = slugTokens.some((t) => promptTokens.has(t));
70
+ if (!hit) {
71
+ const descTokens = tokenize(readSkillDescription(skillsDir, slug));
72
+ hit = descTokens.some((t) => promptTokens.has(t));
73
+ }
54
74
  if (hit) {
55
75
  process.stdout.write(
56
76
  `[Skill hint] Consider loading skill: ${slug}/SKILL.md\n`
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+ # Drift detection for /start. Invoke as a single command:
3
+ # bash .claude/scripts/start-drift.sh
4
+ # Bundling this in a script avoids per-line permission prompts that fire on
5
+ # multi-line bash with X=$(...) patterns (env-var-prefixed substitution
6
+ # is not covered by Bash(cmd:*) allow rules).
7
+ set -eu
8
+
9
+ LAST_SESSION=$(ls -t .claude/sessions/*.md 2>/dev/null | head -1 || true)
10
+ LAST_SHA=""
11
+ if [ -n "$LAST_SESSION" ]; then
12
+ LAST_SHA=$(awk '/^sha:/ {print $2; exit}' "$LAST_SESSION" 2>/dev/null || true)
13
+ fi
14
+
15
+ if [ -n "$LAST_SHA" ] && git rev-parse --verify --quiet "$LAST_SHA" >/dev/null 2>&1; then
16
+ echo "Commits since last session SHA ($LAST_SHA):"
17
+ git log --oneline "$LAST_SHA"..HEAD 2>/dev/null | head -15
18
+ elif [ -n "$LAST_SESSION" ]; then
19
+ SESSION_DATE=$(echo "$LAST_SESSION" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -1)
20
+ echo "Commits since last session ($SESSION_DATE):"
21
+ git log --oneline --since="$SESSION_DATE" 2>/dev/null | head -15
22
+ else
23
+ echo "No previous session found. Recent commits:"
24
+ git log --oneline -10 2>/dev/null
25
+ fi
26
+
27
+ echo ""
28
+ echo "Current branch:"
29
+ git branch --show-current 2>/dev/null
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env bash
2
+ # Resolve the last release tag and its commit date (YYYY-MM-DD) for /sync.
3
+ # Invoke as a single command:
4
+ # bash .claude/scripts/sync-release-scope.sh
5
+ # Output: two key=value lines suitable for downstream parsing.
6
+ # last_tag=v1.2.3
7
+ # since=2026-04-01
8
+ # When no tag exists, both values are empty and /sync should bootstrap one.
9
+ set -eu
10
+
11
+ LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
12
+ SINCE=""
13
+ if [ -n "$LAST_TAG" ]; then
14
+ SINCE=$(git log -1 --format=%as "$LAST_TAG" 2>/dev/null || echo "")
15
+ fi
16
+
17
+ printf 'last_tag=%s\nsince=%s\n' "$LAST_TAG" "$SINCE"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ # List files changed since the last release tag (or last 10 commits if no tag).
3
+ # Invoke as a single command:
4
+ # bash .claude/scripts/test-coverage-changed-files.sh
5
+ # Output is one filename per line, sorted and de-duplicated.
6
+ set -eu
7
+
8
+ LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
9
+
10
+ if [ -n "$LAST_TAG" ]; then
11
+ git log "$LAST_TAG"..HEAD --name-only --pretty=format: 2>/dev/null | sort -u | grep -v '^$' || true
12
+ else
13
+ git diff --name-only HEAD~10 2>/dev/null || true
14
+ fi
@@ -19,6 +19,22 @@
19
19
  "Bash(worclaude scan:*)",
20
20
  "Bash(worclaude setup-state:*)",
21
21
 
22
+ "// -- Shell builtins for slash-command flow --",
23
+ "Bash(test:*)",
24
+ "Bash([:*)",
25
+ "Bash(bash:*)",
26
+
27
+ "// -- WebFetch (research targets) + built-in WebSearch --",
28
+ "WebFetch(domain:docs.anthropic.com)",
29
+ "WebFetch(domain:docs.claude.com)",
30
+ "WebFetch(domain:github.com)",
31
+ "WebFetch(domain:api.github.com)",
32
+ "WebSearch",
33
+
34
+ "// -- Built-in skills used by the workflow --",
35
+ "Skill(update-config)",
36
+ "Skill(fewer-permission-prompts)",
37
+
22
38
  "// -- Common Dev Tools --",
23
39
  "Bash(echo:*)", "Bash(mkdir:*)", "Bash(touch:*)",
24
40
  "Bash(cp:*)", "Bash(mv:*)",
@@ -40,6 +56,29 @@
40
56
  "Edit(README*)", "Edit(*.md)",
41
57
  "Edit(package.json)", "Edit(pyproject.toml)",
42
58
  "Edit(.github/**)"
59
+ ],
60
+ "deny": [
61
+ "// -- Secret files (Read/Edit — Claude's own tools) --",
62
+ "Read(./.env)", "Read(./.env.*)",
63
+ "Read(./secrets/**)",
64
+ "Edit(./.env)", "Edit(./.env.*)", "Edit(./secrets/**)",
65
+ "Read(./*.pem)", "Read(./*.key)",
66
+ "Read(./id_rsa)", "Read(./id_ed25519)",
67
+
68
+ "// -- SSH and cloud creds (home-relative) --",
69
+ "Read(~/.ssh/**)",
70
+ "Read(~/.aws/credentials)",
71
+ "Read(~/.config/gh/hosts.yml)",
72
+
73
+ "// -- Bash file-view commands targeting .env --",
74
+ "Bash(cat *.env*)", "Bash(head *.env*)", "Bash(tail *.env*)",
75
+ "Bash(less *.env*)", "Bash(more *.env*)", "Bash(grep *.env*)",
76
+
77
+ "// -- Catastrophic rm patterns (literal-match defense-in-depth) --",
78
+ "Bash(rm -rf /)", "Bash(rm -rf /*)",
79
+ "Bash(rm -fr /)", "Bash(rm -fr /*)",
80
+ "Bash(rm -rf ~)", "Bash(rm -rf ~/*)",
81
+ "Bash(rm -rf $HOME)", "Bash(rm -rf $HOME/*)"
43
82
  ]
44
83
  },
45
84
  "hooks": {
@@ -120,6 +159,40 @@
120
159
  "type": "command",
121
160
  "command": "p=${WORCLAUDE_HOOK_PROFILE:-standard}; case \"$p\" in minimal) exit 0;; esac; test -f .claude/hooks/skill-hint.cjs && node .claude/hooks/skill-hint.cjs || true"
122
161
  }]
162
+ },
163
+ {
164
+ "matcher": "",
165
+ "hooks": [{
166
+ "type": "command",
167
+ "command": "p=${WORCLAUDE_HOOK_PROFILE:-standard}; case \"$p\" in minimal) exit 0;; esac; test -f .claude/hooks/obs-command-invocations.cjs && node .claude/hooks/obs-command-invocations.cjs || true"
168
+ }]
169
+ }
170
+ ],
171
+ "InstructionsLoaded": [
172
+ {
173
+ "matcher": "",
174
+ "hooks": [{
175
+ "type": "command",
176
+ "command": "p=${WORCLAUDE_HOOK_PROFILE:-standard}; case \"$p\" in minimal) exit 0;; esac; test -f .claude/hooks/obs-skill-loads.cjs && node .claude/hooks/obs-skill-loads.cjs || true"
177
+ }]
178
+ }
179
+ ],
180
+ "SubagentStart": [
181
+ {
182
+ "matcher": "",
183
+ "hooks": [{
184
+ "type": "command",
185
+ "command": "p=${WORCLAUDE_HOOK_PROFILE:-standard}; case \"$p\" in minimal) exit 0;; esac; test -f .claude/hooks/obs-agent-events.cjs && node .claude/hooks/obs-agent-events.cjs || true"
186
+ }]
187
+ }
188
+ ],
189
+ "SubagentStop": [
190
+ {
191
+ "matcher": "",
192
+ "hooks": [{
193
+ "type": "command",
194
+ "command": "p=${WORCLAUDE_HOOK_PROFILE:-standard}; case \"$p\" in minimal) exit 0;; esac; test -f .claude/hooks/obs-agent-events.cjs && node .claude/hooks/obs-agent-events.cjs || true"
195
+ }]
123
196
  }
124
197
  ],
125
198
  "Notification": [
@@ -21,11 +21,12 @@ The cycle:
21
21
  This is why the Gotchas section exists. It grows organically from real problems
22
22
  encountered during development.
23
23
 
24
- ## The 50-Line Target
24
+ ## The 200-Line Target
25
25
 
26
- CLAUDE.md should stay under 50 lines of actual content (excluding blank lines and
27
- section headers). This is a target, not a hard limit, but exceeding it significantly
28
- means CLAUDE.md is trying to do too much.
26
+ CLAUDE.md should stay under 200 lines of actual content. This is the official
27
+ Claude Code guidance and matches `worclaude doctor`'s WARN threshold (150 lines /
28
+ 30,000 chars) and ERROR threshold (200 lines). It is a target, not a hard limit,
29
+ but exceeding it significantly means CLAUDE.md is trying to do too much.
29
30
 
30
31
  Claude reads CLAUDE.md at the start of every session and after every /compact.
31
32
  Long CLAUDE.md files waste context on every single interaction.
@@ -78,7 +79,7 @@ Each gotcha should be:
78
79
  ## When to Prune
79
80
 
80
81
  Review CLAUDE.md when:
81
- - It exceeds 50 lines
82
+ - It exceeds the 200-line target
82
83
  - You notice rules that no longer apply
83
84
  - A rule has been absorbed into a skill
84
85
  - Two rules say the same thing differently
@@ -102,25 +103,60 @@ Only add rules for recurring problems.
102
103
 
103
104
  ## The @include Directive
104
105
 
105
- When CLAUDE.md grows beyond the 50-line target, use `@include` to split content
106
- into separate files while keeping it loadable:
106
+ When CLAUDE.md outgrows what one file can hold cleanly, use `@path/to/import`
107
+ to split content into separate files that still load with CLAUDE.md:
107
108
 
108
109
  ```markdown
109
110
  # CLAUDE.md
110
111
  ## Key Files
111
- @./docs/conventions.md
112
- @./docs/api-standards.md
112
+ @README
113
+ @docs/git-instructions.md
114
+ @~/.claude/my-project-instructions.md
113
115
  ```
114
116
 
115
- - `@./relative` relative to the file containing the directive
116
- - `@~/path` — relative to home directory
117
- - `@/absolute` — absolute path
117
+ Syntax (per official Claude Code docs):
118
+
119
+ - `@path/to/import` — relative to the file containing the directive
120
+ (e.g., `@README`, `@docs/git-instructions.md`)
121
+ - `@~/path` — home-directory relative
122
+ (e.g., `@~/.claude/my-project-instructions.md`)
118
123
  - Works in CLAUDE.md, .claude/CLAUDE.md, .claude/rules/*.md, and CLAUDE.local.md
119
124
  - Does NOT work inside code blocks (only in leaf text nodes)
120
125
  - Non-existent files are silently ignored; circular references are prevented
121
126
 
122
- This is the recommended alternative to cramming everything into CLAUDE.md.
123
- Each included file still consumes context budget, so use judiciously.
127
+ Behavior:
128
+
129
+ - **Imports load at launch and consume context.** They help organization, not
130
+ context budget. Splitting CLAUDE.md into 5 files of 50 lines each produces
131
+ the same context cost as one 250-line file.
132
+ - **Recursion is capped at 5 hops.** A imports B imports C... — Claude stops
133
+ resolving after 5 levels.
134
+ - **External imports trigger an approval dialog on first use.** Importing a
135
+ path outside the project root (e.g., a system-wide config) prompts the user
136
+ to confirm before the import resolves. This is a one-time approval.
137
+
138
+ ### The `@~/.claude/...` worktree-share pattern
139
+
140
+ Worktree agents (`isolation: worktree`) operate in a freshly-checked-out copy
141
+ of the repo. Anything in `.claude/CLAUDE.local.md` or other gitignored files
142
+ is not present in the worktree, so the agent loses your local rules.
143
+
144
+ Workaround: store shared local rules in a home-directory file and import it
145
+ from the project's CLAUDE.md:
146
+
147
+ ```markdown
148
+ # CLAUDE.md
149
+ @~/.claude/my-team-rules.md
150
+ ```
151
+
152
+ The worktree agent re-reads `~/.claude/my-team-rules.md` at launch (it lives
153
+ outside the repo, so no checkout is needed) and gets the same rules as your
154
+ main session. The first run triggers an external-import approval; after that
155
+ it loads silently.
156
+
157
+ Reserve this pattern for rules that belong to *you* across all projects
158
+ (coding style preferences, personal shortcuts). Team-shared rules should
159
+ still live inside the repo.
124
160
 
125
161
  ## Gotchas
126
162
 
@@ -6,6 +6,16 @@ version: "1.0.0"
6
6
 
7
7
  # Git Conventions
8
8
 
9
+ ## Invocation Boundary
10
+
11
+ `git commit`, `git push`, and `gh pr create` are invoked only when the human
12
+ explicitly types `/commit-push-pr` or `/sync` (or one of their listed Trigger
13
+ Phrases). The slash commands themselves are not invoked autonomously — wait for
14
+ the human trigger. The `Version bump:` AskUserQuestion in `/commit-push-pr` is
15
+ non-skippable; refuse to proceed without an explicit human selection.
16
+
17
+ See CLAUDE.md Critical Rule 13.
18
+
9
19
  ## Branch Naming
10
20
 
11
21
  Pattern: `{type}/{short-description}`
@@ -98,7 +108,7 @@ When using `git worktree` for parallel work:
98
108
  - Always clean up worktrees when done: `git worktree remove {path}`
99
109
  - Don't leave stale worktrees — they hold refs and can cause confusion
100
110
 
101
- Agents that use worktree isolation (code-simplifier, test-writer, ci-fixer, etc.)
111
+ Agents that use worktree isolation (code-simplifier, test-writer, bug-fixer, etc.)
102
112
  create and clean up their own worktrees automatically.
103
113
 
104
114
  ## Shared-State Files
@@ -0,0 +1,115 @@
1
+ ---
2
+ description: 'Five-layer memory architecture: where each fact lives, how layers interact, when to promote learnings'
3
+ when_to_use: 'When deciding where a new fact, rule, or preference belongs. When triaging a [LEARN] capture. When promoting from learnings to CLAUDE.md.'
4
+ version: '1.0.0'
5
+ ---
6
+
7
+ # Memory Architecture
8
+
9
+ Worclaude projects use **five distinct memory layers**. Each has a different
10
+ scope, owner, and lifecycle. Routing a fact to the correct layer is a
11
+ load-bearing decision — the wrong layer means the fact is invisible when
12
+ needed, or noisy when not.
13
+
14
+ ## The Five Layers
15
+
16
+ | Layer | Scope | Owner | Lifecycle |
17
+ | ------------------------- | -------- | ----------------------- | -------------------------------- |
18
+ | `CLAUDE.md` | Team | Manual (humans + Claude via `/update-claude-md`) | Stable, lean (target ~200 lines) |
19
+ | `.claude/rules/` | Team | Manual, topic-organized | Stable; optionally path-scoped (deferred — see BACKLOG) |
20
+ | `.claude/learnings/` | Team | Hook-captured (`learn-capture.cjs`) | Append-only; transient inputs to promotion |
21
+ | `CLAUDE.local.md` | Personal | Manual; gitignored | Per-machine sandbox; never shared |
22
+ | Claude Code auto memory | Personal | Autonomous (Claude) | Active, self-pruning |
23
+
24
+ The line between team and personal is the most important boundary. Team
25
+ layers are committed and shared with collaborators; personal layers stay
26
+ on the local machine.
27
+
28
+ ## Routing Contract
29
+
30
+ When a fact, rule, or pattern surfaces during a session, route it like this:
31
+
32
+ | Source | Destination |
33
+ | --------------------------------------------------- | --------------------------------- |
34
+ | A team-relevant rule the user wants enforced — typed `[LEARN]` block or `/learn` invocation | `.claude/learnings/<category>.md` (via hook) |
35
+ | A personal preference (workflow, tone, naming whim) | Claude Code auto memory (Claude does this autonomously when noticed) |
36
+ | A machine-local sandbox value (paths, secrets, dev URLs) | `CLAUDE.local.md` (manual; gitignored) |
37
+ | A topic that has accreted multiple learnings AND is stable | Promote to `CLAUDE.md` via `/update-claude-md` |
38
+
39
+ **Default rule:** if you cannot point to a specific reason a fact belongs in
40
+ a different layer, it does not belong in `CLAUDE.md`. `CLAUDE.md` is the
41
+ last layer to grow, not the first.
42
+
43
+ ## Layer Interactions
44
+
45
+ - **`CLAUDE.md` is the read-on-every-session layer.** It is loaded into
46
+ context at session start and after every `/compact`. Long files waste
47
+ context on every interaction. Stay under ~200 lines of actual content.
48
+ - **`.claude/learnings/` is the staging area.** Hooks write here on every
49
+ `[LEARN]` block. Same category = same file = appended block, so a file
50
+ that grows multiple `**Rule:**` entries signals recurrence. The
51
+ `index.json` `created` field is updated to the latest capture date —
52
+ use it as a "last touched" timestamp, not a fixed creation date.
53
+ - **Auto memory runs in parallel.** Claude Code maintains
54
+ `~/.claude/projects/<project-slug>/memory/` autonomously. It is
55
+ per-machine and personal. Worclaude does not write to it and does not
56
+ read from it during `/update-claude-md` promotion (deliberate scope
57
+ boundary — see BACKLOG for the discussion).
58
+ - **`CLAUDE.local.md` overrides `CLAUDE.md`** for the local machine. Use
59
+ it for facts that are genuinely user-specific within an otherwise shared
60
+ project. Do not commit it.
61
+ - **`.claude/rules/` is reserved.** Claude Code's official docs recommend
62
+ it for topic-organized, optionally path-scoped team rules. Worclaude
63
+ defers scaffolding it until a usage signal exists; users can still
64
+ create the folder manually. Do not duplicate `CLAUDE.md` content into
65
+ `.claude/rules/` ad-hoc.
66
+
67
+ ## Promotion Path: Learnings → CLAUDE.md
68
+
69
+ Promotion is the bridge from `.claude/learnings/` to `CLAUDE.md`. It is
70
+ deliberately gated by `/update-claude-md` rather than automatic — promotion
71
+ is a content decision, not a mechanical one.
72
+
73
+ A learning is a **promotion candidate** when at least one of these holds:
74
+
75
+ 1. **Recurrence:** the learning's file in `.claude/learnings/` has 3 or
76
+ more `**Rule:**` blocks (i.e., the same category was captured at least
77
+ three times). Counted by scanning the file, not the index.
78
+ 2. **Recency cluster:** the index entry's `created` date is within the
79
+ last 14 days AND the same theme has shown up in another recent
80
+ learning. Recent + repeated > recent alone.
81
+ 3. **Drift:** the learning's content is structurally relevant to an
82
+ existing `CLAUDE.md` section (e.g., a new "always do X" pattern that
83
+ would naturally live in `## Critical Rules` or `## Gotchas`) but the
84
+ pattern is missing from the file.
85
+
86
+ Even when a candidate qualifies, `/update-claude-md` confirms each
87
+ proposed addition with the user via `AskUserQuestion`. No silent writes.
88
+
89
+ ## Don't / Do
90
+
91
+ - **Don't** edit `.claude/learnings/` files by hand to "fix" them. They
92
+ are the raw capture surface. If a learning is wrong, fix the rule in
93
+ `CLAUDE.md` or remove the learning file.
94
+ - **Don't** scaffold `.claude/rules/` content from old `CLAUDE.md`
95
+ sections "to make `CLAUDE.md` smaller." Splitting into sub-files just
96
+ fragments the single source of truth without saving context.
97
+ - **Don't** mix personal preferences into team layers. If something
98
+ applies only to your local workflow, it belongs in `CLAUDE.local.md`
99
+ or Claude Code's auto memory — not in `CLAUDE.md`.
100
+ - **Do** delete stale learnings. If a category was captured once eight
101
+ months ago and never recurred, it is noise.
102
+ - **Do** prune `CLAUDE.md` when it crosses 200 lines. `worclaude doctor`
103
+ warns at 150 and errors at 200. Pruning is part of maintenance.
104
+ - **Do** read the file before recommending an update. Memory across
105
+ sessions is not authoritative — current file content is.
106
+
107
+ ## Cross-References
108
+
109
+ - `/learn` — captures a `[LEARN]` block to `.claude/learnings/`.
110
+ - `/update-claude-md` — proposes promotions from learnings to
111
+ `CLAUDE.md`, with size + dedup gates.
112
+ - `claude-md-maintenance` skill — what belongs in `CLAUDE.md`, format
113
+ discipline, the 200-line target.
114
+ - `worclaude doctor` — surfaces drift between `CLAUDE.md` claims and
115
+ `package.json` reality (see Phase 3 T3.8).