create-merlin-brain 5.0.2 → 5.3.2

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 (101) hide show
  1. package/README.md +25 -4
  2. package/bin/install.cjs +95 -0
  3. package/dist/server/server.d.ts.map +1 -1
  4. package/dist/server/server.js +75 -0
  5. package/dist/server/server.js.map +1 -1
  6. package/dist/server/tools/context.d.ts.map +1 -1
  7. package/dist/server/tools/context.js +60 -0
  8. package/dist/server/tools/context.js.map +1 -1
  9. package/dist/server/tools/project-picture.d.ts +17 -0
  10. package/dist/server/tools/project-picture.d.ts.map +1 -0
  11. package/dist/server/tools/project-picture.js +204 -0
  12. package/dist/server/tools/project-picture.js.map +1 -0
  13. package/dist/server/tools/types.d.ts +24 -0
  14. package/dist/server/tools/types.d.ts.map +1 -1
  15. package/files/agents/challenger-academic.md +8 -0
  16. package/files/agents/challenger-arbiter.md +8 -0
  17. package/files/agents/challenger-insider.md +8 -0
  18. package/files/agents/code-organization-supervisor.md +8 -0
  19. package/files/agents/codex-planner.md +36 -9
  20. package/files/agents/context-guardian.md +8 -0
  21. package/files/agents/docs-keeper.md +8 -0
  22. package/files/agents/dry-refactor.md +8 -0
  23. package/files/agents/elite-code-refactorer.md +8 -0
  24. package/files/agents/hardening-guard.md +8 -0
  25. package/files/agents/implementation-dev.md +8 -0
  26. package/files/agents/merlin-access-control-reviewer.md +8 -0
  27. package/files/agents/merlin-api-designer.md +8 -0
  28. package/files/agents/merlin-codebase-mapper.md +8 -0
  29. package/files/agents/merlin-debugger.md +8 -0
  30. package/files/agents/merlin-dependency-auditor.md +8 -0
  31. package/files/agents/merlin-edge-case-hunter.md +8 -0
  32. package/files/agents/merlin-executor.md +8 -0
  33. package/files/agents/merlin-frontend.md +8 -0
  34. package/files/agents/merlin-input-validator.md +8 -0
  35. package/files/agents/merlin-integration-checker.md +8 -0
  36. package/files/agents/merlin-migrator.md +8 -0
  37. package/files/agents/merlin-milestone-auditor.md +8 -0
  38. package/files/agents/merlin-party-review.md +8 -0
  39. package/files/agents/merlin-performance.md +8 -0
  40. package/files/agents/merlin-planner.md +9 -1
  41. package/files/agents/merlin-researcher.md +8 -0
  42. package/files/agents/merlin-reviewer.md +8 -0
  43. package/files/agents/merlin-sast-reviewer.md +8 -0
  44. package/files/agents/merlin-secret-scanner.md +8 -0
  45. package/files/agents/merlin-security.md +8 -0
  46. package/files/agents/merlin-verifier.md +8 -0
  47. package/files/agents/merlin-work-verifier.md +8 -0
  48. package/files/agents/merlin.md +8 -0
  49. package/files/agents/ops-railway.md +8 -0
  50. package/files/agents/orchestrator-retrofit.md +8 -0
  51. package/files/agents/product-spec.md +8 -0
  52. package/files/agents/remotion.md +8 -0
  53. package/files/agents/system-architect.md +8 -0
  54. package/files/agents/tests-qa.md +8 -0
  55. package/files/commands/merlin/course-correct.md +8 -0
  56. package/files/commands/merlin/design-audit.md +92 -0
  57. package/files/commands/merlin/health.md +8 -0
  58. package/files/commands/merlin/next.md +8 -0
  59. package/files/commands/merlin/optimize.md +89 -0
  60. package/files/commands/merlin/polish.md +99 -0
  61. package/files/commands/merlin/quick.md +8 -0
  62. package/files/commands/merlin/readiness-gate.md +8 -0
  63. package/files/commands/merlin/redesign.md +108 -0
  64. package/files/loop/README.md +11 -0
  65. package/files/merlin/skills/SKILLS-INDEX.md +16 -1
  66. package/files/merlin/skills/TASK-OPTIMIZER.json +310 -0
  67. package/files/merlin/skills/coding/focus-mode.md +8 -0
  68. package/files/merlin/skills/design/emil-design-eng.md +31 -0
  69. package/files/merlin/skills/design/impeccable.md +36 -0
  70. package/files/merlin/skills/duo/offer.md +20 -7
  71. package/files/merlin/skills/duo/on.md +26 -17
  72. package/files/merlin/skills/duo/status.md +10 -3
  73. package/files/merlin/templates/DEBUG.md +11 -0
  74. package/files/merlin/templates/UAT.md +11 -0
  75. package/files/merlin/templates/phase-prompt.md +11 -0
  76. package/files/merlin/templates/project.md +11 -0
  77. package/files/merlin/templates/requirements.md +11 -0
  78. package/files/merlin/templates/roadmap.md +11 -0
  79. package/files/merlin/templates/state.md +11 -0
  80. package/files/merlin/templates/verification-report.md +11 -0
  81. package/files/merlin/workflows/execute-phase.md +11 -0
  82. package/files/merlin/workflows/plan-phase.md +11 -0
  83. package/files/merlin/workflows/progress.md +11 -0
  84. package/files/merlin/workflows/resume-project.md +11 -0
  85. package/files/merlin/workflows/verify-phase.md +11 -0
  86. package/files/merlin/workflows/verify-work.md +11 -0
  87. package/files/merlin-system-prompt.txt +35 -1
  88. package/files/rules/codex-routing.md +19 -0
  89. package/files/rules/duo-routing.md +109 -10
  90. package/files/rules/merlin-routing.md +40 -0
  91. package/files/scripts/codex-as.sh +5 -2
  92. package/files/scripts/design-intent-detect.sh +8 -0
  93. package/files/scripts/duo-badge.sh +3 -5
  94. package/files/scripts/duo-installed.sh +3 -3
  95. package/files/scripts/duo-mode-read.sh +30 -10
  96. package/files/scripts/duo-mode-write.sh +28 -3
  97. package/files/scripts/duo-pre-route.sh +2 -8
  98. package/files/scripts/install-design-skills.sh +86 -0
  99. package/files/scripts/merlin-codex.sh +9 -4
  100. package/files/scripts/task-optimize.sh +335 -0
  101. package/package.json +1 -1
@@ -15,6 +15,46 @@ Route user intent to the matching workflow. Do not analyze or fix problems yours
15
15
  | "build API" / "backend" / "endpoint" | `Skill("merlin:workflow", args='run api-build "<task>"')` |
16
16
  | Small, isolated task | `merlin_smart_route(task="...")` then `merlin_route()` |
17
17
 
18
+ ## Universal Task Optimization (RUN FIRST on every routing decision)
19
+
20
+ BEFORE every routing decision (workflow, agent, or specialist), run:
21
+
22
+ ```
23
+ bash ~/.claude/scripts/task-optimize.sh --task "<full user task text>"
24
+ ```
25
+
26
+ The optimizer returns single-line JSON: `{"score":<0-100>,"intent":"<id>","skills":[<ids>],"agent":"<name>","matched_phrases":[...]}`.
27
+
28
+ If `score >= 25`:
29
+ 1. Read the matched skill files (`~/.claude/merlin/skills/<id>.md` or `~/.claude/skills/<external>/SKILL.md` for external skills).
30
+ 2. Announce the pairing: `⟡🔮 MERLIN › Intent: <intent>. Loading <skills> + routing to <agent>.` (use the duo badge variant if duo mode is on)
31
+ 3. Route to the optimizer-recommended `agent` with skill bodies prepended into context.
32
+
33
+ If `score < 25`: fall through to the existing routing tables below.
34
+
35
+ The registry of skill→agent pairings lives at `~/.claude/merlin/skills/TASK-OPTIMIZER.json`. To add a new skill, append an entry there — no code changes needed.
36
+
37
+ ### Common skill+agent pairings (reference; full registry in TASK-OPTIMIZER.json)
38
+
39
+ | Task signal | Skills | Agent |
40
+ |---|---|---|
41
+ | Design / UI / typography / color / responsive | design/impeccable, design/emil-design-eng | ui-builder |
42
+ | Animation / polish / micro-interactions | design/emil-design-eng | animation-expert |
43
+ | Accessibility / WCAG / a11y | coding/accessibility | hardening-guard |
44
+ | Auth / OWASP / CSRF / hardening | coding/security-hardening | hardening-guard |
45
+ | API / REST / OpenAPI / GraphQL | coding/api-design | merlin-api-designer |
46
+ | Performance / Core Web Vitals / bundle | coding/performance | merlin-performance |
47
+ | Tests / TDD / Jest / Vitest | testing/tdd-workflow | tests-qa |
48
+ | Docker / containers / CI | devops/docker-containers | ops-railway |
49
+ | Bug / crash / error / debug | coding/debug-mode | merlin-debugger |
50
+ | Stripe / billing / webhooks / email | automation/*, communication/* | implementation-dev |
51
+ | Brainstorm / ideate / options | research/brainstorm | merlin-researcher |
52
+ | React / hooks / Next.js / components | coding/react-patterns | merlin-frontend |
53
+
54
+ Slash commands: `/merlin:optimize`, `/merlin:design-audit`, `/merlin:polish`, `/merlin:redesign`.
55
+
56
+ The optimizer is the AUTHORITY. Don't override its recommendations unless the user explicitly asks for a different agent.
57
+
18
58
  ## Agent Routing
19
59
 
20
60
  Call `merlin_smart_route(task="...")` FIRST (searches 500+ community agents). Then:
@@ -69,6 +69,9 @@ FULL_PROMPT="${PROMPT_BODY}
69
69
 
70
70
  ${TASK_TEXT}"
71
71
 
72
- # Invoke codex with --write to allow file modifications
72
+ # Invoke codex with workspace-write sandbox to allow file modifications inside cwd.
73
+ # (The legacy --write flag was removed from `codex exec`; -s workspace-write is the
74
+ # current equivalent. Use --dangerously-bypass-approvals-and-sandbox only if you
75
+ # explicitly want to skip all prompts — workspace-write is the safer default.)
73
76
  # shellcheck disable=SC2086
74
- exec codex exec --write --cd "$PWD" $MODEL_FLAG "$FULL_PROMPT"
77
+ exec codex exec -s workspace-write --cd "$PWD" $MODEL_FLAG "$FULL_PROMPT"
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ # design-intent-detect.sh — thin wrapper around task-optimize.sh (v5.3+)
3
+ # Preserves the v5.2.0 contract for slash commands that reference this script.
4
+ # Usage: design-intent-detect.sh --task "<text>" [--self-test]
5
+ # Output: same JSON as task-optimize.sh
6
+ set -euo pipefail
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ exec "$SCRIPT_DIR/task-optimize.sh" "$@"
@@ -8,12 +8,10 @@ set -euo pipefail
8
8
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
9
  STEP_PHRASE="${1:-}"
10
10
 
11
- # Determine if duo is active: gate passes AND mode is enabled
11
+ # Determine if duo is active: mode is enabled (duo-installed.sh is always-pass, no longer checked)
12
12
  DUO_ACTIVE=false
13
- if "${SCRIPT_DIR}/duo-installed.sh" 2>/dev/null; then
14
- if [[ "$("${SCRIPT_DIR}/duo-mode-read.sh" 2>/dev/null)" == "enabled" ]]; then
15
- DUO_ACTIVE=true
16
- fi
13
+ if [[ "$("${SCRIPT_DIR}/duo-mode-read.sh" 2>/dev/null)" == "enabled" ]]; then
14
+ DUO_ACTIVE=true
17
15
  fi
18
16
 
19
17
  # Build badge
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env bash
2
2
  # duo-installed.sh — composite install gate for duo mode
3
- # Returns 0 only if codex-installed.sh (sibling) returns 0
3
+ # Always exits 0: duo is available regardless of Codex. Pair selection (claude+codex vs claude+claude)
4
+ # is determined separately via codex-installed.sh at toggle time.
4
5
 
5
6
  set -euo pipefail
6
7
 
7
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
- "${SCRIPT_DIR}/codex-installed.sh"
8
+ exit 0
@@ -1,51 +1,71 @@
1
1
  #!/usr/bin/env bash
2
2
  # duo-mode-read.sh — reads duo-mode.json, applies 24h auto-expire (read-time only, never modifies file)
3
- # Prints exactly "enabled" or "disabled" to stdout
3
+ # Without --pair: prints exactly "enabled" or "disabled" to stdout
4
+ # With --pair: prints the pair value: "claude+codex", "claude+claude", or "none"
4
5
 
5
6
  set -euo pipefail
6
7
 
7
8
  STATE_FILE="${HOME}/.claude/merlin-state/duo-mode.json"
9
+ PAIR_MODE=false
8
10
 
9
- # If state file missing, default to disabled
11
+ for arg in "$@"; do
12
+ if [[ "$arg" == "--pair" ]]; then
13
+ PAIR_MODE=true
14
+ fi
15
+ done
16
+
17
+ # If state file missing, default to disabled / none
10
18
  if [[ ! -f "$STATE_FILE" ]]; then
11
- echo "disabled"
19
+ if [[ "$PAIR_MODE" == "true" ]]; then
20
+ echo "none"
21
+ else
22
+ echo "disabled"
23
+ fi
12
24
  exit 0
13
25
  fi
14
26
 
15
- python3 - "$STATE_FILE" <<'PYEOF'
27
+ python3 - "$STATE_FILE" "$PAIR_MODE" <<'PYEOF'
16
28
  import sys
17
29
  import json
18
30
  from datetime import datetime, timezone, timedelta
19
31
 
20
32
  state_path = sys.argv[1]
33
+ pair_mode = sys.argv[2] == "true"
21
34
 
22
35
  try:
23
36
  with open(state_path, "r") as f:
24
37
  data = json.load(f)
25
38
  except (json.JSONDecodeError, OSError):
26
- print("disabled")
39
+ print("none" if pair_mode else "disabled")
27
40
  sys.exit(0)
28
41
 
29
42
  enabled = data.get("enabled", False)
30
43
  since_iso = data.get("sinceISO")
44
+ pair = data.get("pair")
31
45
 
32
46
  if not enabled or since_iso is None:
33
- print("disabled")
47
+ print("none" if pair_mode else "disabled")
34
48
  sys.exit(0)
35
49
 
36
50
  # Parse sinceISO and apply 24h auto-expire (read-time interpretation, no file write)
37
51
  try:
38
- # Handle both Z suffix and +00:00 format
39
52
  since_str = since_iso.replace("Z", "+00:00")
40
53
  since_dt = datetime.fromisoformat(since_str)
41
54
  now_dt = datetime.now(timezone.utc)
42
55
  if (now_dt - since_dt) > timedelta(hours=24):
43
- print("disabled")
56
+ print("none" if pair_mode else "disabled")
44
57
  sys.exit(0)
45
58
  except (ValueError, TypeError):
46
59
  # Unparseable timestamp — treat as expired
47
- print("disabled")
60
+ print("none" if pair_mode else "disabled")
48
61
  sys.exit(0)
49
62
 
50
- print("enabled")
63
+ if pair_mode:
64
+ # Legacy state (no pair field) when enabled defaults to claude+codex
65
+ if pair is None:
66
+ print("claude+codex")
67
+ else:
68
+ print(pair)
69
+ else:
70
+ print("enabled")
51
71
  PYEOF
@@ -1,18 +1,21 @@
1
1
  #!/usr/bin/env bash
2
2
  # duo-mode-write.sh — atomic write to duo-mode.json
3
- # Usage: duo-mode-write.sh on "<reason>" | off "<reason>"
3
+ # Usage: duo-mode-write.sh on "<reason>" [claude+codex|claude+claude]
4
+ # duo-mode-write.sh off "<reason>"
4
5
 
5
6
  set -euo pipefail
6
7
 
7
8
  if [[ $# -lt 2 ]]; then
8
- echo "Usage: duo-mode-write.sh on|off \"<reason>\"" >&2
9
+ echo "Usage: duo-mode-write.sh on|off \"<reason>\" [claude+codex|claude+claude|codex+codex]" >&2
9
10
  exit 1
10
11
  fi
11
12
 
12
13
  ACTION="$1"
13
14
  REASON="$2"
15
+ PAIR_ARG="${3:-}"
14
16
  STATE_FILE="${HOME}/.claude/merlin-state/duo-mode.json"
15
17
  STATE_DIR="$(dirname "$STATE_FILE")"
18
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
19
 
17
20
  # Ensure state directory exists
18
21
  mkdir -p "$STATE_DIR"
@@ -20,9 +23,28 @@ mkdir -p "$STATE_DIR"
20
23
  case "$ACTION" in
21
24
  on)
22
25
  ENABLED="true"
26
+
27
+ # Validate explicit pair arg if provided
28
+ if [[ -n "$PAIR_ARG" ]]; then
29
+ if [[ "$PAIR_ARG" != "claude+codex" && "$PAIR_ARG" != "claude+claude" && "$PAIR_ARG" != "codex+codex" ]]; then
30
+ echo "Error: pair must be 'claude+codex', 'claude+claude', or 'codex+codex', got: $PAIR_ARG" >&2
31
+ exit 1
32
+ fi
33
+ PAIR="$PAIR_ARG"
34
+ else
35
+ # Auto-detect pair: MERLIN_RUNTIME=codex → codex+codex; codex installed → claude+codex; else → claude+claude
36
+ if [[ "${MERLIN_RUNTIME:-}" == "codex" ]]; then
37
+ PAIR="codex+codex"
38
+ elif "${SCRIPT_DIR}/codex-installed.sh" 2>/dev/null; then
39
+ PAIR="claude+codex"
40
+ else
41
+ PAIR="claude+claude"
42
+ fi
43
+ fi
23
44
  ;;
24
45
  off)
25
46
  ENABLED="false"
47
+ PAIR="null"
26
48
  ;;
27
49
  *)
28
50
  echo "Error: first argument must be 'on' or 'off', got: $ACTION" >&2
@@ -31,7 +53,7 @@ case "$ACTION" in
31
53
  esac
32
54
 
33
55
  # Use python3 for JSON serialization and atomic write via mktemp + mv (same FS = atomic)
34
- python3 - "$STATE_FILE" "$ENABLED" "$REASON" <<'PYEOF'
56
+ python3 - "$STATE_FILE" "$ENABLED" "$REASON" "$PAIR" <<'PYEOF'
35
57
  import sys
36
58
  import json
37
59
  import os
@@ -41,13 +63,16 @@ from datetime import datetime, timezone
41
63
  state_path = sys.argv[1]
42
64
  enabled = sys.argv[2] == "true"
43
65
  reason = sys.argv[3]
66
+ pair_arg = sys.argv[4]
44
67
 
45
68
  now_iso = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") if enabled else None
69
+ pair_value = None if pair_arg == "null" else pair_arg
46
70
 
47
71
  data = {
48
72
  "enabled": enabled,
49
73
  "sinceISO": now_iso,
50
74
  "lastToggleReason": reason,
75
+ "pair": pair_value,
51
76
  }
52
77
 
53
78
  state_dir = os.path.dirname(state_path)
@@ -30,13 +30,7 @@ if [[ "$DUO_STATE" == "enabled" ]]; then
30
30
  exit 0
31
31
  fi
32
32
 
33
- # Branch 2: Codex absent stay solo silently (never mention duo)
34
- if ! "${SCRIPT_DIR}/duo-installed.sh" 2>/dev/null; then
35
- echo "mode=solo"
36
- exit 0
37
- fi
38
-
39
- # Branch 3: risk-detect suggestion
33
+ # Branch 2: risk-detect suggestion (duo-installed.sh is always-pass; offer fires regardless of Codex)
40
34
  RISK_DETECT="${SCRIPT_DIR}/duo-risk-detect.sh"
41
35
  if [[ ! -x "$RISK_DETECT" ]]; then
42
36
  echo "mode=solo"
@@ -62,7 +56,7 @@ if [[ "$SUGGEST_DUO" != "true" ]]; then
62
56
  exit 0
63
57
  fi
64
58
 
65
- # Branch 3a: suppression check — use a temp python script to avoid heredoc-in-subshell issues
59
+ # Branch 2a: suppression check — use a temp python script to avoid heredoc-in-subshell issues
66
60
  REASONS_JSON=$(python3 -c "
67
61
  import json, sys
68
62
  try:
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ # Merlin Design Skills Installer
5
+ # Installs and prioritizes emilkowalski/skill and pbakaus/impeccable
6
+
7
+ # Honor skip flag
8
+ if [ "${MERLIN_SKIP_DESIGN_SKILLS:-0}" = "1" ]; then
9
+ exit 0
10
+ fi
11
+
12
+ echo "[merlin] Installing priority design skills…"
13
+
14
+ SKILLS_DIR="${HOME}/.claude/skills"
15
+ mkdir -p "$SKILLS_DIR"
16
+
17
+ # ═══════════════════════════════════════════════════════════════
18
+ # Install emilkowalski/skill (install-only, no license vendoring)
19
+ # ═══════════════════════════════════════════════════════════════
20
+
21
+ if [ ! -f "$SKILLS_DIR/emil-design-eng/SKILL.md" ]; then
22
+ if command -v npx >/dev/null 2>&1; then
23
+ # Attempt install via skills CLI
24
+ if npx --yes skills add emilkowalski/skill 2>/dev/null; then
25
+ : # Success
26
+ else
27
+ # Non-fatal — user can install manually
28
+ echo "[merlin] emil skill install hint: npx --yes skills add emilkowalski/skill"
29
+ fi
30
+ else
31
+ echo "[merlin] npx not found; skipping emil skill (user can install: npx --yes skills add emilkowalski/skill)"
32
+ fi
33
+ fi
34
+
35
+ # ═══════════════════════════════════════════════════════════════
36
+ # Install pbakaus/impeccable (fetch + preserve Apache-2.0 attribution)
37
+ # ═══════════════════════════════════════════════════════════════
38
+
39
+ if [ ! -d "$SKILLS_DIR/impeccable" ]; then
40
+ if command -v git >/dev/null 2>&1; then
41
+ tmp=$(mktemp -d)
42
+ trap "rm -rf '$tmp'" EXIT
43
+
44
+ if git clone --depth 1 https://github.com/pbakaus/impeccable.git "$tmp" 2>/dev/null; then
45
+ # Copy the skill subtree (contains SKILL.md and commands/)
46
+ if [ -d "$tmp/dist/claude-code/.claude/skills/impeccable" ]; then
47
+ mkdir -p "$SKILLS_DIR"
48
+ cp -R "$tmp/dist/claude-code/.claude/skills/impeccable" "$SKILLS_DIR/"
49
+
50
+ # Preserve license attribution
51
+ if [ -f "$tmp/LICENSE" ]; then
52
+ cp "$tmp/LICENSE" "$SKILLS_DIR/impeccable/LICENSE"
53
+ fi
54
+ if [ -f "$tmp/NOTICE.md" ]; then
55
+ cp "$tmp/NOTICE.md" "$SKILLS_DIR/impeccable/NOTICE.md"
56
+ fi
57
+ else
58
+ echo "[merlin] impeccable skill structure not found in cloned repo"
59
+ fi
60
+ else
61
+ echo "[merlin] git clone failed for impeccable; user can install manually"
62
+ fi
63
+ else
64
+ echo "[merlin] git not found; skipping impeccable skill (user can install manually: git clone pbakaus/impeccable)"
65
+ fi
66
+ fi
67
+
68
+ # ═══════════════════════════════════════════════════════════════
69
+ # Verification
70
+ # ═══════════════════════════════════════════════════════════════
71
+
72
+ has_impeccable=0
73
+ has_emil=0
74
+
75
+ [ -d "$SKILLS_DIR/impeccable" ] && has_impeccable=1
76
+ [ -f "$SKILLS_DIR/emil-design-eng/SKILL.md" ] && has_emil=1
77
+
78
+ if [ "$has_impeccable" = "1" ] || [ "$has_emil" = "1" ]; then
79
+ echo "[merlin] Design skills ready:"
80
+ [ "$has_impeccable" = "1" ] && echo " ✓ impeccable"
81
+ [ "$has_emil" = "1" ] && echo " ✓ emil-design-eng"
82
+ else
83
+ echo "[merlin] Design skills install: no changes (already present or install failed)"
84
+ fi
85
+
86
+ exit 0
@@ -15,6 +15,8 @@
15
15
  #
16
16
  set -euo pipefail
17
17
 
18
+ export MERLIN_RUNTIME=codex
19
+
18
20
  SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
21
  SYSTEM_PROMPT_FILE="${HOME}/.claude/merlin-system-prompt.txt"
20
22
  FALLBACK_PROMPT="You are Merlin: orchestrator, not coder. Route implementation to specialists. Badge every action with ⟡🔮 MERLIN ›."
@@ -22,20 +24,23 @@ FALLBACK_PROMPT="You are Merlin: orchestrator, not coder. Route implementation t
22
24
  # ── Pass-through subcommands (no Merlin prompt injection) ──────
23
25
  PASSTHROUGH_CMDS="login logout mcp mcp-server app app-server completion sandbox debug"
24
26
 
25
- # ── Determine duo mode for banner ──────────────────────────────
27
+ # ── Determine duo mode and pair for banner ─────────────────────
26
28
  _mode_label="Solo"
29
+ _pair_label=""
27
30
  if [ -x "${SCRIPTS_DIR}/duo-mode-read.sh" ]; then
28
31
  _duo=$("${SCRIPTS_DIR}/duo-mode-read.sh" 2>/dev/null) || _duo="disabled"
29
32
  if [ "${_duo}" = "enabled" ]; then
30
- if [ -x "${SCRIPTS_DIR}/duo-installed.sh" ]; then
31
- "${SCRIPTS_DIR}/duo-installed.sh" 2>/dev/null && _mode_label="Duo" || true
33
+ _mode_label="Duo"
34
+ _pair=$("${SCRIPTS_DIR}/duo-mode-read.sh" --pair 2>/dev/null) || _pair="none"
35
+ if [ "${_pair}" != "none" ]; then
36
+ _pair_label=" (${_pair})"
32
37
  fi
33
38
  fi
34
39
  fi
35
40
 
36
41
  # ── Print banner to stderr (always) ───────────────────────────
37
42
  printf '⟡🔮 MERLIN · entering Codex via merlin-codex\n' >&2
38
- printf '🎯 Mode: %s\n' "${_mode_label}" >&2
43
+ printf '🎯 Mode: %s%s\n' "${_mode_label}" "${_pair_label}" >&2
39
44
  printf '▶ Codex will inherit Merlin'"'"'s orchestrator instructions\n' >&2
40
45
 
41
46
  # ── If no args, open interactive Codex shell ──────────────────