create-merlin-brain 5.3.5 → 5.3.8

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/bin/install.cjs CHANGED
@@ -1320,10 +1320,17 @@ async function install() {
1320
1320
  hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/user-prompt-router.sh' }]
1321
1321
  });
1322
1322
 
1323
- // PostToolUse: file size enforcement (implementation agents only)
1324
- addHookIfMissing(settings.hooks.PostToolUse, {
1325
- matcher: 'Edit|Write',
1326
- hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/check-file-size.sh' }]
1323
+ // PreToolUse: file size enforcement (400-LOC rule, blocks oversized writes)
1324
+ // NOTE: Moved from PostToolUse to PreToolUse in v5.3.8 to BLOCK before write, not warn after.
1325
+ addHookIfMissing(settings.hooks.PreToolUse, {
1326
+ matcher: 'Edit|Write|MultiEdit',
1327
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/check-file-size.sh', timeout: 10 }]
1328
+ });
1329
+
1330
+ // Remove legacy PostToolUse check-file-size.sh (pre-5.3.8)
1331
+ settings.hooks.PostToolUse = settings.hooks.PostToolUse.filter(entry => {
1332
+ const cmd = entry.hooks?.[0]?.command || '';
1333
+ return !cmd.includes('check-file-size.sh');
1327
1334
  });
1328
1335
 
1329
1336
  // PreToolUse: security scanner (prompt injection, secrets, data exfiltration)
@@ -1750,12 +1757,21 @@ ${colors.cyan}Universal Task Optimization (NEW in 5.3.0):${colors.reset}
1750
1757
  • ${colors.bright}/merlin:polish${colors.reset} - Animation polish via animation-expert
1751
1758
  • ${colors.bright}/merlin:redesign${colors.reset} - Full redesign via ui-builder
1752
1759
 
1753
- ${colors.cyan}Tier-2 cleanup (NEW in 5.3.5):${colors.reset}
1754
- 4 new agents wired (android-expert, apple-swift-expert, desktop-app-expert, marketing-automation)
1755
- Counter-reset bug diagnosed in duo-codex-call.sh (fix pending v5.3.6)
1756
- MCP routing reads live agent list from disk (no drift)
1757
- • Concurrent codex calls protected by flock
1758
- Malformed config files now backed up before overwrite
1760
+ ${colors.cyan}Attribution hardening (NEW in 5.3.6):${colors.reset}
1761
+ All shipped agents now carry provenance frontmatter (source + license + import date)
1762
+ check-provenance.js now requires every agent to declare provenance
1763
+ Unknown-origin agents documented in NOTICE.md (attribution pending see issue tracker)
1764
+
1765
+ ${colors.cyan}Discovery-first (NEW in 5.3.7):${colors.reset}
1766
+ • Brain now proactively searches 1000+ community agents before routing
1767
+ • ${colors.bright}/merlin:install <slug>${colors.reset} - One-keystroke install of any catalog agent
1768
+ • smart_route + discover_agents wired into the orchestrator protocol
1769
+
1770
+ ${colors.cyan}File-size enforcement (NEW in 5.3.8):${colors.reset}
1771
+ • 400-LOC rule now enforced by PreToolUse hook (blocks oversized writes)
1772
+ • ${colors.bright}/merlin:check-size${colors.reset} - Scan repo for violations
1773
+ • Justify exceptions with: ${colors.yellow}// merlin:allow-large-file: <reason>${colors.reset}
1774
+ • Override: MERLIN_SKIP_FILE_SIZE_CHECK=1 or MERLIN_FILE_SIZE_LIMIT=N
1759
1775
 
1760
1776
  ${colors.cyan}Merlin works with or without Sights:${colors.reset}
1761
1777
  • ${colors.green}With Sights${colors.reset}: Instant context, cross-session memory
package/files/CLAUDE.md CHANGED
@@ -53,11 +53,23 @@ Do NOT spawn Explore agents or run Glob/Grep for codebase questions. Use Sights
53
53
 
54
54
  Never just dump an agent result and go silent. Always follow through.
55
55
 
56
+ ## Discovery-First Routing (1000+ community agents)
57
+
58
+ Before routing any non-trivial task to a built-in specialist, proactively check the community catalog:
59
+
60
+ 1. Call `merlin_smart_route(task="<full user text>")` to score both built-in and catalog agents.
61
+ 2. If a catalog match (Grade A+ or A) scores higher than built-in options, surface it to the user.
62
+ 3. Example: "⟡🔮 MERLIN › Found a community agent: **Payment Integration** (Grade A). Install with `/merlin:install payment-integration`, or use built-in implementation-dev?"
63
+ 4. Wait for user choice — never auto-install without confirmation.
64
+ 5. Use `/merlin:install <slug>` to install, or the user can describe what they want and Merlin will auto-route.
65
+
66
+ Skip discovery for: trivial edits (single file, comment, rename), debug runs, doc updates, or when user explicitly names an agent.
67
+
56
68
  ## Execution
57
69
 
58
70
  Run independent agents in PARALLEL. Never sequential when parallel is possible.
59
71
  NEVER run `claude --agent` via Bash. Always use `Skill("merlin:route")` or `merlin_route()`.
60
- For ANY routing, call `merlin_smart_route(task="...")` FIRST to check 500+ community agents.
72
+ For ANY routing, call `merlin_smart_route(task="...")` FIRST to check community agents + built-ins.
61
73
 
62
74
  ## Learning
63
75
 
@@ -71,6 +83,7 @@ When user corrects you → `merlin_save_behavior`. When user says "always/never/
71
83
  - Never kill user processes (Xcode, VS Code, browsers) without explicit confirmation.
72
84
  - Never claim "done" without actually building/compiling/testing.
73
85
  - Badge on EVERY action — call `~/.claude/scripts/duo-badge.sh` to get the right badge. If the user can't see the badge, you're not doing your job.
86
+ - No file may exceed 400 LOC. Enforced by ~/.claude/hooks/check-file-size.sh (PreToolUse hook). Override per-file with `// merlin:allow-large-file: <reason>` comment. Override per-session with MERLIN_SKIP_FILE_SIZE_CHECK=1.
74
87
 
75
88
  ## Codex Execution Mode
76
89
 
@@ -3,6 +3,15 @@ name: android-expert
3
3
  description: Full-lifecycle Android agent — implements, refactors, architects, tests, and hardens Kotlin, Jetpack Compose, Material Design 3, and Android apps.
4
4
  model: sonnet
5
5
  color: green
6
+ provenance:
7
+ upstream: unknown-origin/vendored-agents-feb2026
8
+ source: unknown
9
+ imported_date: "2026-02-04"
10
+ style_signature: "Full-lifecycle X agent — builds, refactors, architects, tests, and hardens"
11
+ license: unknown
12
+ license_verification: unconfirmed
13
+ adapted: "Vendored as-is from local cache on 2026-02-04. No modifications beyond Merlin integration."
14
+ note: "Imported in batch on 2026-02-04 from an unidentified source. Style is consistent with a single author/tool but no public catalog match was found (checked wshobson/agents, VoltAgent/awesome-claude-code-subagents). Curated, integrated, and shipped via create-merlin-brain. If you recognize this as your work, please open an issue at https://github.com/sandman66666/merlin and we'll update attribution."
6
15
  ---
7
16
 
8
17
  <role>
@@ -3,6 +3,15 @@ name: animation-expert
3
3
  description: Full-lifecycle animation agent — builds, refactors, architects, tests, and hardens animations with Motion, GSAP, CSS, and 60fps performance.
4
4
  model: sonnet
5
5
  color: violet
6
+ provenance:
7
+ upstream: unknown-origin/vendored-agents-feb2026
8
+ source: unknown
9
+ imported_date: "2026-02-04"
10
+ style_signature: "Full-lifecycle X agent — builds, refactors, architects, tests, and hardens"
11
+ license: unknown
12
+ license_verification: unconfirmed
13
+ adapted: "Vendored as-is from local cache on 2026-02-04. No modifications beyond Merlin integration."
14
+ note: "Imported in batch on 2026-02-04 from an unidentified source. Style is consistent with a single author/tool but no public catalog match was found (checked wshobson/agents, VoltAgent/awesome-claude-code-subagents). Curated, integrated, and shipped via create-merlin-brain. If you recognize this as your work, please open an issue at https://github.com/sandman66666/merlin and we'll update attribution."
6
15
  ---
7
16
 
8
17
  <role>
@@ -3,6 +3,15 @@ name: apple-swift-expert
3
3
  description: Full-lifecycle Apple platform agent — implements, refactors, architects, tests, and hardens Swift 6, SwiftUI, AppKit, iOS and macOS code.
4
4
  model: sonnet
5
5
  color: blue
6
+ provenance:
7
+ upstream: unknown-origin/vendored-agents-feb2026
8
+ source: unknown
9
+ imported_date: "2026-02-04"
10
+ style_signature: "Full-lifecycle X agent — builds, refactors, architects, tests, and hardens"
11
+ license: unknown
12
+ license_verification: unconfirmed
13
+ adapted: "Vendored as-is from local cache on 2026-02-04. No modifications beyond Merlin integration."
14
+ note: "Imported in batch on 2026-02-04 from an unidentified source. Style is consistent with a single author/tool but no public catalog match was found (checked wshobson/agents, VoltAgent/awesome-claude-code-subagents). Curated, integrated, and shipped via create-merlin-brain. If you recognize this as your work, please open an issue at https://github.com/sandman66666/merlin and we'll update attribution."
6
15
  ---
7
16
 
8
17
  <role>
@@ -3,6 +3,15 @@ name: desktop-app-expert
3
3
  description: Full-lifecycle desktop app agent — implements, refactors, architects, tests, and hardens Electron and Tauri apps with IPC security and cross-platform distribution.
4
4
  model: sonnet
5
5
  color: cyan
6
+ provenance:
7
+ upstream: unknown-origin/vendored-agents-feb2026
8
+ source: unknown
9
+ imported_date: "2026-02-04"
10
+ style_signature: "Full-lifecycle X agent — builds, refactors, architects, tests, and hardens"
11
+ license: unknown
12
+ license_verification: unconfirmed
13
+ adapted: "Vendored as-is from local cache on 2026-02-04. No modifications beyond Merlin integration."
14
+ note: "Imported in batch on 2026-02-04 from an unidentified source. Style is consistent with a single author/tool but no public catalog match was found (checked wshobson/agents, VoltAgent/awesome-claude-code-subagents). Curated, integrated, and shipped via create-merlin-brain. If you recognize this as your work, please open an issue at https://github.com/sandman66666/merlin and we'll update attribution."
6
15
  ---
7
16
 
8
17
  <role>
@@ -3,6 +3,15 @@ name: marketing-automation
3
3
  description: Full-lifecycle marketing engineering agent — builds, refactors, architects, tests, and hardens email campaigns, drip sequences, A/B tests, and analytics.
4
4
  model: sonnet
5
5
  color: red
6
+ provenance:
7
+ upstream: unknown-origin/vendored-agents-feb2026
8
+ source: unknown
9
+ imported_date: "2026-02-04"
10
+ style_signature: "Full-lifecycle X agent — builds, refactors, architects, tests, and hardens"
11
+ license: unknown
12
+ license_verification: unconfirmed
13
+ adapted: "Vendored as-is from local cache on 2026-02-04. No modifications beyond Merlin integration."
14
+ note: "Imported in batch on 2026-02-04 from an unidentified source. Style is consistent with a single author/tool but no public catalog match was found (checked wshobson/agents, VoltAgent/awesome-claude-code-subagents). Curated, integrated, and shipped via create-merlin-brain. If you recognize this as your work, please open an issue at https://github.com/sandman66666/merlin and we'll update attribution."
6
15
  ---
7
16
 
8
17
  <role>
@@ -3,6 +3,14 @@ name: orchestrator
3
3
  description: Master router for a vibe coder building serious, production-leaning systems. Always choose and coordinate the right specialist agent instead of doing work yourself.
4
4
  model: opus
5
5
  color: red
6
+ provenance:
7
+ upstream: unknown-origin/vendored-agents-feb2026
8
+ source: unknown
9
+ imported_date: "2026-01-22"
10
+ license: unknown
11
+ license_verification: unconfirmed
12
+ adapted: "Vendored as-is from local cache on 2026-01-22. No modifications beyond Merlin integration."
13
+ note: "Imported on 2026-01-22 from an unidentified source (different style than the Feb 4 batch). Curated, integrated, and shipped via create-merlin-brain. If you recognize this as your work, please open an issue at https://github.com/sandman66666/merlin and we'll update attribution."
6
14
  ---
7
15
 
8
16
  You are the orchestrator for a very strong product thinker and vibe coder who uses Claude Code as their main dev environment.
@@ -3,6 +3,15 @@ name: ui-builder
3
3
  description: Full-lifecycle UI engineering agent — builds, refactors, architects, tests, and hardens React components with Tailwind, shadcn/ui, and Radix.
4
4
  model: sonnet
5
5
  color: orange
6
+ provenance:
7
+ upstream: unknown-origin/vendored-agents-feb2026
8
+ source: unknown
9
+ imported_date: "2026-02-04"
10
+ style_signature: "Full-lifecycle X agent — builds, refactors, architects, tests, and hardens"
11
+ license: unknown
12
+ license_verification: unconfirmed
13
+ adapted: "Vendored as-is from local cache on 2026-02-04. No modifications beyond Merlin integration."
14
+ note: "Imported in batch on 2026-02-04 from an unidentified source. Style is consistent with a single author/tool but no public catalog match was found (checked wshobson/agents, VoltAgent/awesome-claude-code-subagents). Curated, integrated, and shipped via create-merlin-brain. If you recognize this as your work, please open an issue at https://github.com/sandman66666/merlin and we'll update attribution."
6
15
  ---
7
16
 
8
17
  <role>
@@ -3,6 +3,15 @@ name: ui-designer
3
3
  description: Full-lifecycle design agent — creates, refactors, architects, audits, and hardens design systems, accessibility, tokens, and component specs.
4
4
  model: sonnet
5
5
  color: pink
6
+ provenance:
7
+ upstream: unknown-origin/vendored-agents-feb2026
8
+ source: unknown
9
+ imported_date: "2026-02-04"
10
+ style_signature: "Full-lifecycle X agent — builds, refactors, architects, tests, and hardens"
11
+ license: unknown
12
+ license_verification: unconfirmed
13
+ adapted: "Vendored as-is from local cache on 2026-02-04. No modifications beyond Merlin integration."
14
+ note: "Imported in batch on 2026-02-04 from an unidentified source. Style is consistent with a single author/tool but no public catalog match was found (checked wshobson/agents, VoltAgent/awesome-claude-code-subagents). Curated, integrated, and shipped via create-merlin-brain. If you recognize this as your work, please open an issue at https://github.com/sandman66666/merlin and we'll update attribution."
6
15
  ---
7
16
 
8
17
  <role>
@@ -0,0 +1,152 @@
1
+ ---
2
+ name: merlin:check-size
3
+ description: Scan the repo for files exceeding the 400-LOC convention and surface violations
4
+ argument-hint: "[path]"
5
+ allowed-tools:
6
+ - Read
7
+ - Glob
8
+ - Grep
9
+ - Bash
10
+ - AskUserQuestion
11
+ - mcp__merlin__merlin_route
12
+ ---
13
+
14
+ <objective>
15
+ Scan the current repository for files that exceed the 400-LOC project convention.
16
+ Surface violations grouped by severity, identify opt-out markers, and offer to route to
17
+ `code-organization-supervisor` for refactor proposals on the worst offenders.
18
+ </objective>
19
+
20
+ <context>
21
+ Optional path argument: $ARGUMENTS
22
+ If provided, scan only that directory. Otherwise scan from repo root (cwd).
23
+ </context>
24
+
25
+ <process>
26
+
27
+ ## Step 1: Discover Code Files
28
+
29
+ Run a find command to locate all code files, excluding common generated/vendor directories:
30
+
31
+ ```bash
32
+ find "${1:-.}" -type f \( \
33
+ -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \
34
+ -o -name "*.py" -o -name "*.rs" -o -name "*.go" -o -name "*.sh" \
35
+ -o -name "*.cjs" -o -name "*.mjs" -o -name "*.swift" -o -name "*.kt" \
36
+ -o -name "*.java" -o -name "*.rb" -o -name "*.php" -o -name "*.c" \
37
+ -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" \
38
+ \) \
39
+ -not -path "*/node_modules/*" \
40
+ -not -path "*/dist/*" \
41
+ -not -path "*/build/*" \
42
+ -not -path "*/.next/*" \
43
+ -not -path "*/.git/*" \
44
+ -not -path "*/coverage/*" \
45
+ -not -path "*/.vite/*" \
46
+ -not -path "*/vendor/*" \
47
+ -not -path "*/__pycache__/*" \
48
+ 2>/dev/null | xargs wc -l 2>/dev/null | awk '$1 > 400 && !/total$/' | sort -rn
49
+ ```
50
+
51
+ Capture the output as VIOLATIONS.
52
+
53
+ ## Step 2: Group by Severity
54
+
55
+ Parse VIOLATIONS and categorize:
56
+
57
+ | Tier | LOC Range | Label |
58
+ |------|-----------|-------|
59
+ | Critical | 1000+ | files that urgently need splitting |
60
+ | High | 600-999 | should be refactored soon |
61
+ | Warn | 401-599 | approaching limit, watch closely |
62
+
63
+ ## Step 3: Check for Opt-Out Markers
64
+
65
+ For each violation, check if the file contains the opt-out marker:
66
+
67
+ ```bash
68
+ grep -l "merlin:allow-large-file:" <file>
69
+ ```
70
+
71
+ Tag files that have the marker with "(justified)" in the output.
72
+
73
+ ## Step 4: Present Report
74
+
75
+ Output a structured report:
76
+
77
+ ```
78
+ ============================================
79
+ FILE SIZE AUDIT — 400-LOC Convention
80
+ ============================================
81
+
82
+ CRITICAL (1000+ LOC):
83
+ * path/to/file.ts — 1523 lines
84
+ * path/to/other.js — 1201 lines
85
+
86
+ HIGH (600-999 LOC):
87
+ * path/to/module.py — 812 lines (justified: "generated parser tables")
88
+
89
+ WARN (401-599 LOC):
90
+ * path/to/component.tsx — 456 lines
91
+
92
+ --------------------------------------------
93
+ Total violations: X files
94
+ - X critical, X high, X warn
95
+ - X have justification markers
96
+ --------------------------------------------
97
+ ```
98
+
99
+ If no violations found:
100
+ ```
101
+ All files are within the 400-LOC convention.
102
+ ```
103
+
104
+ ## Step 5: Offer Refactor Help
105
+
106
+ If there are critical-tier violations (1000+ LOC) without markers, ask:
107
+
108
+ ```
109
+ The following files are critically oversized and lack justification:
110
+ * path/to/file.ts (1523 lines)
111
+ * path/to/other.js (1201 lines)
112
+
113
+ Would you like me to route these to `code-organization-supervisor` for
114
+ a proposed split? (y/n)
115
+ ```
116
+
117
+ If user says yes, route to the agent:
118
+
119
+ ```
120
+ Call: merlin_route
121
+ Agent: code-organization-supervisor
122
+ Task: "Propose a refactor plan to split these oversized files into smaller, focused modules:
123
+ - <file1>: <LOC> lines
124
+ - <file2>: <LOC> lines
125
+
126
+ Each resulting module should be under 400 lines. Provide:
127
+ 1. Proposed module boundaries
128
+ 2. Which functions/classes go where
129
+ 3. Import graph after the split
130
+ 4. Step-by-step migration plan"
131
+ ```
132
+
133
+ </process>
134
+
135
+ <error_handling>
136
+
137
+ | Condition | Action |
138
+ |-----------|--------|
139
+ | No code files found | Report "No code files found in <path>." |
140
+ | Permission errors | Skip inaccessible files, note count skipped |
141
+ | wc/find unavailable | Fall back to Glob + Read with manual line counting |
142
+ | Path doesn't exist | Report error and suggest checking the path |
143
+
144
+ </error_handling>
145
+
146
+ <tips>
147
+ - This command is advisory — it doesn't block anything
148
+ - The PreToolUse hook (`~/.claude/hooks/check-file-size.sh`) does the actual blocking
149
+ - Add `// merlin:allow-large-file: <reason>` to justify genuinely large files
150
+ - Override the limit per-session with `MERLIN_FILE_SIZE_LIMIT=600`
151
+ - Skip all checks with `MERLIN_SKIP_FILE_SIZE_CHECK=1`
152
+ </tips>
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: merlin:install
3
+ description: Install a community agent/skill from the Merlin catalog by slug. Wraps `npx skills add` and similar install commands per the agent's metadata.
4
+ argument-hint: "<slug> — agent slug from merlin_discover_agents (e.g., 'payment-integration')"
5
+ allowed-tools:
6
+ - Bash
7
+ - Read
8
+ - mcp__merlin__merlin_get_agent_detail
9
+ ---
10
+
11
+ <objective>
12
+ Install a community agent or skill from the Merlin catalog into the user's local Claude environment.
13
+ </objective>
14
+
15
+ ## Steps
16
+
17
+ 1. Read the agent detail via `merlin_get_agent_detail(slug="$ARGUMENTS")` to get the install command and source.
18
+
19
+ 2. Show the user what's about to be installed:
20
+ - Name, grade, description
21
+ - Install command from agent metadata
22
+ - Source repo URL
23
+ Then ask explicit confirmation: "Install <name>? (Y/N)"
24
+
25
+ 3. On YES, run the install command:
26
+ - If it starts with `npx skills add`: `bash -c "<install_command>"`
27
+ - If it starts with `npm install`: `bash -c "<install_command>"` (in cwd or globally based on agent type)
28
+ - If unknown: surface the command and tell user to run it manually
29
+
30
+ 4. After install, verify the agent is now reachable:
31
+ - For Claude agents: check `~/.claude/agents/<slug>.md` exists
32
+ - For skills: check `~/.claude/skills/<slug>/SKILL.md` exists
33
+ - Otherwise: trust the install command's exit code
34
+
35
+ 5. Surface a usage hint: "Installed <name>. Use via `merlin_route(agent=\"<name>\", task=\"...\")` or just describe what you want — Merlin will route to it."
36
+
37
+ ## Safety
38
+
39
+ - NEVER run install commands without explicit user Y confirmation.
40
+ - NEVER pipe install commands through eval or shell injection unsafe channels.
41
+ - If the install command from the catalog looks suspicious (contains `curl | sh`, sudo, etc.), refuse and surface the command for manual review.
42
+ - Honor the user's deny list (`~/.claude/settings.json` permissions.deny).
43
+
44
+ ## Errors
45
+
46
+ - Slug not found → "Slug `<x>` not found. Try `merlin_discover_agents(query=\"...\")` to search."
47
+ - No install command in metadata → "This agent doesn't have an automated install. Visit <source_url> for instructions."
48
+ - Install command failed → show stderr, suggest manual run.
49
+
@@ -1,73 +1,181 @@
1
1
  #!/usr/bin/env bash
2
+ # check-file-size.sh — Claude Code PreToolUse hook
2
3
  #
3
- # Merlin Hook: PostToolUse (Write/Edit)
4
- # Checks if the modified file exceeds the 400-line convention.
5
- # Exits with code 2 to inject feedback when file is too large.
4
+ # Enforces the 400-LOC project rule. Blocks Edit/Write/MultiEdit when the
5
+ # resulting file would exceed the limit, unless the file contains an opt-out
6
+ # marker (`merlin:allow-large-file: <reason>`).
6
7
  #
7
- # Agent-type awareness: only enforce for implementation agents.
8
- # Non-code agents (docs, review, verify, etc.) are fully exempt.
8
+ # Contract per hooks-rules.md + Claude Code hooks docs:
9
+ # - stdin: JSON {tool_name, tool_input, ...}
10
+ # - block: exit 0 + stdout JSON {"decision":"block","reason":"..."}
11
+ # - allow: exit 0 + stdout {} (or empty)
12
+ # - any other exit code is treated as pass; never exit 1 to block
9
13
  #
10
- set -euo pipefail
11
- trap 'echo "{}"; exit 0' ERR
14
+ # Env opt-outs (allow legitimate overrides):
15
+ # MERLIN_SKIP_FILE_SIZE_CHECK=1 — skip entirely
16
+ # MERLIN_FILE_SIZE_LIMIT=N — override 400 default
12
17
 
13
- # Read CLAUDE_AGENT_TYPE from env — support both var names
14
- AGENT_TYPE="${CLAUDE_AGENT_TYPE:-${CLAUDE_CODE_AGENT_TYPE:-main}}"
18
+ set -uo pipefail
19
+ # NO `set -e` and NO ERR trap — explicit exit codes only, so a stray non-zero
20
+ # step (e.g. a grep that finds nothing) doesn't accidentally short-circuit the
21
+ # decision.
15
22
 
16
- # Only enforce for implementation agents
17
- # Skip for all doc/review/verification/analysis agents
18
- case "$AGENT_TYPE" in
19
- implementation-dev|merlin-executor)
20
- # Enforcement is active for these agents — continue
21
- ;;
22
- docs-keeper|merlin-reviewer|merlin-verifier|merlin-milestone-auditor|\
23
- merlin-integration-checker|merlin-work-verifier|code-organization-supervisor|\
24
- context-guardian|dry-refactor|tests-qa|merlin-codebase-mapper)
25
- echo '{}'
26
- exit 0
27
- ;;
28
- *)
29
- # For all other agents (including 'main'), skip enforcement
30
- echo '{}'
31
- exit 0
32
- ;;
33
- esac
23
+ allow() { echo '{}'; exit 0; }
24
+ block() {
25
+ local reason="$1"
26
+ # Escape backslashes and double quotes for JSON.
27
+ local escaped="${reason//\\/\\\\}"
28
+ escaped="${escaped//\"/\\\"}"
29
+ escaped="${escaped//$'\n'/\\n}"
30
+ printf '{"decision":"block","reason":"%s"}\n' "$escaped"
31
+ exit 0
32
+ }
33
+
34
+ # Opt-out via env
35
+ [ "${MERLIN_SKIP_FILE_SIZE_CHECK:-0}" = "1" ] && allow
36
+
37
+ LIMIT="${MERLIN_FILE_SIZE_LIMIT:-400}"
34
38
 
35
- # Read tool input from stdin (Claude Code pipes JSON)
36
- input=""
39
+ # Read stdin (defensive: never block on TTY)
40
+ INPUT=""
37
41
  if [ ! -t 0 ]; then
38
- input=$(cat 2>/dev/null || true)
42
+ INPUT=$(cat 2>/dev/null || true)
39
43
  fi
44
+ [ -z "$INPUT" ] && allow
40
45
 
41
- # Extract file path from tool input
42
- file_path=""
43
- if [ -n "$input" ] && command -v jq >/dev/null 2>&1; then
44
- file_path=$(echo "$input" | jq -r '.tool_input.file_path // .tool_input.path // empty' 2>/dev/null || true)
45
- fi
46
+ # Need python3 for reliable JSON parsing + line counting. If missing, allow.
47
+ command -v python3 >/dev/null 2>&1 || allow
46
48
 
47
- # If no file path found, exit cleanly
48
- if [ -z "$file_path" ] || [ ! -f "$file_path" ]; then
49
- echo '{}'
50
- exit 0
51
- fi
49
+ RESULT=$(MERLIN_LIMIT="$LIMIT" python3 - "$INPUT" <<'PYEOF' 2>/dev/null || echo "ERROR"
50
+ import sys, json, os, fnmatch, re
52
51
 
53
- # Skip non-code files (images, binaries, configs, etc.)
54
- case "$file_path" in
55
- *.png|*.jpg|*.jpeg|*.gif|*.svg|*.ico|*.woff|*.woff2|*.ttf|*.eot) echo '{}'; exit 0 ;;
56
- *.lock|*.json|*.yaml|*.yml|*.toml|*.env*) echo '{}'; exit 0 ;;
57
- *node_modules*|*.git/*) echo '{}'; exit 0 ;;
58
- esac
52
+ try:
53
+ payload = json.loads(sys.argv[1])
54
+ except Exception:
55
+ print("ALLOW||json-error"); sys.exit(0)
59
56
 
60
- # Count lines in the file
61
- line_count=$(wc -l < "$file_path" 2>/dev/null || echo "0")
62
- line_count=$(echo "$line_count" | tr -d ' ')
57
+ limit = int(os.environ.get("MERLIN_LIMIT", "400"))
58
+ tool = payload.get("tool_name", "")
59
+ ti = payload.get("tool_input") or {}
60
+ fp = ti.get("file_path") or ""
63
61
 
64
- # If file exceeds 400 lines, send feedback via exit code 2
65
- if [ "$line_count" -gt 400 ]; then
66
- echo "WARNING: ${file_path} is ${line_count} lines (convention is <400). Consider splitting into smaller, focused modules." >&2
67
- echo '{}'
68
- exit 2
69
- fi
62
+ IGNORE_GLOBS = [
63
+ "*.lock", "*-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb",
64
+ "Cargo.lock", "Pipfile.lock", "composer.lock", "Gemfile.lock",
65
+ "*.min.*", "*.bundle.*",
66
+ "*.svg", "*.png", "*.jpg", "*.jpeg", "*.gif", "*.ico", "*.webp", "*.pdf",
67
+ "*.woff", "*.woff2", "*.ttf", "*.eot",
68
+ "*.snap", "*.csv", "*.tsv",
69
+ "*.md",
70
+ ]
71
+ IGNORE_PATH_SUBSTRINGS = [
72
+ "/node_modules/", "/dist/", "/build/", "/.next/", "/.git/", "/out/",
73
+ "/coverage/", "/.vite/", "/migrations/", "/__fixtures__/", "/fixtures/",
74
+ "/__snapshots__/",
75
+ ]
76
+
77
+ def is_ignored(path):
78
+ if not path: return True
79
+ base = os.path.basename(path).lower()
80
+ for g in IGNORE_GLOBS:
81
+ if fnmatch.fnmatchcase(base, g.lower()): return True
82
+ norm = path.replace("\\", "/")
83
+ for s in IGNORE_PATH_SUBSTRINGS:
84
+ if s in norm: return True
85
+ return False
86
+
87
+ if is_ignored(fp):
88
+ print("ALLOW||ignored"); sys.exit(0)
89
+
90
+ def read_existing():
91
+ try:
92
+ with open(fp, "r", encoding="utf-8") as f:
93
+ return f.read()
94
+ except Exception:
95
+ return ""
70
96
 
71
- # File is within limits
72
- echo '{}'
73
- exit 0
97
+ if tool == "Write":
98
+ new_content = ti.get("content") or ""
99
+ elif tool == "Edit":
100
+ existing = read_existing()
101
+ old = ti.get("old_string", "")
102
+ new = ti.get("new_string", "")
103
+ if not existing:
104
+ new_content = new
105
+ elif ti.get("replace_all"):
106
+ new_content = existing.replace(old, new)
107
+ else:
108
+ new_content = existing.replace(old, new, 1)
109
+ elif tool == "MultiEdit":
110
+ cur = read_existing()
111
+ for e in ti.get("edits") or []:
112
+ old = e.get("old_string", "")
113
+ new = e.get("new_string", "")
114
+ if e.get("replace_all"):
115
+ cur = cur.replace(old, new)
116
+ else:
117
+ cur = cur.replace(old, new, 1)
118
+ new_content = cur
119
+ else:
120
+ print("ALLOW||unknown-tool"); sys.exit(0)
121
+
122
+ # Opt-out marker scan (first 50 + last 50 lines — let big middles still trigger)
123
+ lines = new_content.split("\n")
124
+ loc = len(lines)
125
+ if loc > 100:
126
+ sample = "\n".join(lines[:50] + lines[-50:])
127
+ else:
128
+ sample = new_content
129
+ marker = re.search(r"merlin:allow-large-file:\s*([^\n\r]*)", sample)
130
+ if marker:
131
+ reason = marker.group(1).strip()[:200].replace("|", "/")
132
+ print(f"ALLOW||marker:{reason}"); sys.exit(0)
133
+
134
+ if loc > limit:
135
+ print(f"BLOCK||{loc}||{fp}"); sys.exit(0)
136
+
137
+ print(f"ALLOW||{loc}"); sys.exit(0)
138
+ PYEOF
139
+ )
140
+
141
+ # Defensive: any python error → allow
142
+ [ "$RESULT" = "ERROR" ] && allow
143
+ [ -z "$RESULT" ] && allow
144
+
145
+ ACTION="${RESULT%%||*}"
146
+
147
+ case "$ACTION" in
148
+ BLOCK)
149
+ REST="${RESULT#BLOCK||}"
150
+ LOC_COUNT="${REST%%||*}"
151
+ FILE_PATH="${REST#*||}"
152
+ REASON="File ${FILE_PATH} would be ${LOC_COUNT} LOC, exceeding the ${LIMIT}-LOC project rule.
153
+
154
+ To proceed, either:
155
+
156
+ 1. REFACTOR — split this file into smaller modules by feature.
157
+ • Invoke the code-organization-supervisor agent for proposed splits
158
+ • Run /merlin:check-size to scan the whole repo for offenders
159
+
160
+ 2. JUSTIFY — add this comment in the first 50 lines of the file:
161
+ // merlin:allow-large-file: <one-line reason this file must stay long>
162
+ (Python/shell: # merlin:allow-large-file: <reason>)
163
+ (CSS: /* merlin:allow-large-file: <reason> */)
164
+ (HTML/JSX: <!-- merlin:allow-large-file: <reason> -->)
165
+ The reason is your audit trail — make it specific (e.g. 'generated by codegen', 'single-source-of-truth lookup table', 'vendored library').
166
+
167
+ Override per-session: MERLIN_SKIP_FILE_SIZE_CHECK=1
168
+ Override limit: MERLIN_FILE_SIZE_LIMIT=600"
169
+ block "$REASON"
170
+ ;;
171
+ ALLOW)
172
+ REST="${RESULT#ALLOW||}"
173
+ if [[ "$REST" == marker:* ]]; then
174
+ echo "[merlin] Allowed large file with marker: ${REST#marker:}" >&2
175
+ fi
176
+ allow
177
+ ;;
178
+ *)
179
+ allow
180
+ ;;
181
+ esac
@@ -32,4 +32,8 @@ wait
32
32
 
33
33
  **Badge:** Always prefix every action with `⟡🔮↔🔮 MERLIN·DUO ›` when duo is on, `⟡🔮 MERLIN ›` when off.
34
34
 
35
- TASK OPTIMIZATION: Before EVERY routing decision (workflows, agents, specialists), run ~/.claude/scripts/task-optimize.sh --task "<user text>". It returns {intent, skills[], agent, score, matched_phrases}. If score>=25, ALWAYS announce "⟡🔮 MERLIN › Intent: <X>. Loading <skills> + routing to <agent>." then route with skills prepended to context. Registry: ~/.claude/merlin/skills/TASK-OPTIMIZER.json. Slash commands /merlin:optimize, /merlin:design-audit, /merlin:polish, /merlin:redesign wrap common flows.
35
+ TASK OPTIMIZATION: Before EVERY routing decision (workflows, agents, specialists), run ~/.claude/scripts/task-optimize.sh --task "<user text>". It returns {intent, skills[], agent, score, matched_phrases}. If score>=25, ALWAYS announce "⟡🔮 MERLIN › Intent: <X>. Loading <skills> + routing to <agent>." then route with skills prepended to context. Registry: ~/.claude/merlin/skills/TASK-OPTIMIZER.json. Slash commands /merlin:optimize, /merlin:design-audit, /merlin:polish, /merlin:redesign wrap common flows.
36
+
37
+ DISCOVERY-FIRST: Before routing any non-trivial task to a built-in specialist, call `merlin_smart_route(task="...")` and `merlin_discover_agents(query="...")` to check the community catalog (1000+ indexed agents/skills). If a catalog match scores a higher grade (A+/A++) than the best built-in for the task, surface it: "⟡🔮 MERLIN › I found a community agent that fits better: <name> (Grade: <X>). Install with /merlin:install <slug> or stick with built-in <built-in>?" — then wait for user choice. NEVER install without confirmation. Skip discovery only for: trivial single-file edits, debug runs, doc updates, or when the user explicitly names an agent.
38
+
39
+ FILE-SIZE ENFORCEMENT: Every Write/Edit/MultiEdit is blocked by ~/.claude/hooks/check-file-size.sh if the resulting file exceeds 400 LOC (configurable via MERLIN_FILE_SIZE_LIMIT). When blocked, EITHER refactor into smaller modules (preferred) OR add `// merlin:allow-large-file: <one-line reason>` in the first 50 lines if the size is genuinely justified (e.g., generated code, big lookup table, single-file library). Use /merlin:check-size to scan the whole repo at any time.
@@ -55,6 +55,41 @@ Slash commands: `/merlin:optimize`, `/merlin:design-audit`, `/merlin:polish`, `/
55
55
 
56
56
  The optimizer is the AUTHORITY. Don't override its recommendations unless the user explicitly asks for a different agent.
57
57
 
58
+ ## Discovery-First Routing (1000+ community agents)
59
+
60
+ The Merlin Sights server indexes 1000+ community agents/skills from GitHub, npm, skills.sh, and other sources. Before routing any non-trivial task to a built-in, ALWAYS check if a better community agent exists.
61
+
62
+ ### Protocol
63
+
64
+ For tasks that are NOT trivial (i.e., > 5 minutes of work, or touching a new domain):
65
+
66
+ 1. Call `merlin_smart_route(task="<full user text>")` — returns the best match from BOTH installed local agents AND the community catalog.
67
+ 2. If the response includes a catalog match (source: catalog, grade A+/A++):
68
+ - Surface it to the user: `⟡🔮 MERLIN › Catalog match: <name> (Grade <X>). Install with /merlin:install <slug>, or use built-in <fallback>?`
69
+ - Wait for user choice. Never install without confirmation.
70
+ 3. If only built-in matches, proceed with normal routing.
71
+
72
+ For tasks that ARE trivial (single-file edit, rename, comment fix, debug print):
73
+ - Skip discovery. Use the optimizer + built-in directly.
74
+
75
+ ### When to use discover_agents vs smart_route
76
+
77
+ - `merlin_smart_route(task)` — best for "what agent should I use" decisions (returns ranked recommendation)
78
+ - `merlin_discover_agents(query)` — best for "what's available for X technology" exploration (returns 5-10 matches with install commands)
79
+
80
+ ### Examples
81
+
82
+ Bad:
83
+ > User: "build me a Stripe payments integration"
84
+ > Merlin: routes to implementation-dev without checking catalog
85
+
86
+ Good:
87
+ > User: "build me a Stripe payments integration"
88
+ > Merlin: `merlin_smart_route("build Stripe payments...")` → finds "Payment Integration" (Grade A) catalog agent
89
+ > Merlin: "⟡🔮 MERLIN › Found a community agent: **Payment Integration** (Grade A) by ChatAndBuild. Install with `/merlin:install payment-integration`, or use built-in implementation-dev?"
90
+
91
+ This is what makes the "1000+ skills on the server" actually useful.
92
+
58
93
  ## Agent Routing
59
94
 
60
95
  Call `merlin_smart_route(task="...")` FIRST (searches 500+ community agents). Then:
@@ -33,8 +33,13 @@ pair=$(grep -o '"pair"[[:space:]]*:[[:space:]]*"[^"]*"' "$STATE_FILE" 2>/dev/nul
33
33
  [[ "$enabled" != "true" ]] && { if [[ "$PAIR_MODE" == "true" ]]; then echo "none"; else echo "disabled"; fi; exit 0; }
34
34
  [[ -z "$since" || "$since" == "null" ]] && { if [[ "$PAIR_MODE" == "true" ]]; then echo "none"; else echo "disabled"; fi; exit 0; }
35
35
 
36
- # Check 24h expiry using portable date commands (macOS has date -j, Linux has date -d)
37
- since_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$since" "+%s" 2>/dev/null || date -d "$since" "+%s" 2>/dev/null || echo "")
36
+ # Check 24h expiry using portable date commands (macOS has date -j, Linux has date -d).
37
+ # Normalize +00:00 / +0000 offsets to Z so the strict macOS parser accepts them.
38
+ since_normalized=$(echo "$since" | sed 's/\+00:00$/Z/; s/\+0000$/Z/; s/\.[0-9][0-9][0-9]Z$/Z/; s/\.[0-9][0-9][0-9]\+00:00$/Z/')
39
+ since_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$since_normalized" "+%s" 2>/dev/null \
40
+ || date -d "$since" "+%s" 2>/dev/null \
41
+ || date -d "$since_normalized" "+%s" 2>/dev/null \
42
+ || echo "")
38
43
  if [[ -z "$since_epoch" ]]; then
39
44
  # Unparseable timestamp — treat as expired
40
45
  if [[ "$PAIR_MODE" == "true" ]]; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-merlin-brain",
3
- "version": "5.3.5",
3
+ "version": "5.3.8",
4
4
  "description": "Merlin - The Ultimate AI Brain for Claude Code, Codex, and other AI CLIs. One install: workflows, agents, loop, and Sights MCP server.",
5
5
  "type": "module",
6
6
  "main": "./dist/server/index.js",