create-merlin-brain 5.0.0 โ†’ 5.0.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.
package/README.md CHANGED
@@ -153,6 +153,19 @@ When enabled, the badge swaps to `โŸก๐Ÿ”ฎโ†”๐Ÿ”ฎ MERLINยทDUO โ€บ` so you always
153
153
 
154
154
  Full rules: `~/.claude/rules/duo-routing.md`.
155
155
 
156
+ ## Standalone Codex Users
157
+
158
+ If you run Codex directly (without Claude Code), use `merlin-codex` as a drop-in wrapper to get the Merlin orchestrator persona on every invocation:
159
+
160
+ ```bash
161
+ merlin-codex # opens interactive Codex shell with Merlin banner
162
+ merlin-codex exec "add auth login" # exec with Merlin system prompt prepended
163
+ merlin-codex "fix the failing test" # prompt mode with Merlin prompt prepended
164
+ merlin-codex login # pass-through โ€” no prompt injection
165
+ ```
166
+
167
+ The wrapper prints the Merlin banner to stderr, loads `~/.claude/merlin-system-prompt.txt` (falls back to a one-liner if missing), and forwards all management subcommands (`login`, `logout`, `mcp`, etc.) unchanged.
168
+
156
169
  ## Documentation
157
170
 
158
171
  Visit [merlin.build/docs](https://merlin.build/docs) for full documentation.
package/files/CLAUDE.md CHANGED
@@ -90,6 +90,8 @@ Merlin can delegate code execution to OpenAI Codex while Claude handles planning
90
90
 
91
91
  **Brain/hands split:** Codex writes code; Claude always verifies via `merlin_run_verification()`.
92
92
 
93
+ **Standalone Codex users:** invoke `merlin-codex` instead of `codex` to get the Merlin orchestrator persona.
94
+
93
95
  ## Duo Mode (parallel + sequential dual-brain)
94
96
 
95
97
  Duo mode runs Claude AND Codex on the same task โ€” parallel for planning/docs/review/tests, sequential for code write/modify. The decider merges (parallel) or gates (sequential).
@@ -199,8 +199,94 @@ _merlin_check_voice_mode
199
199
  _voice_note=""
200
200
  [ "${MERLIN_VOICE_MODE:-}" = "1" ] && _voice_note=" Voice mode active: keep all responses short and direct."
201
201
 
202
- # Build the additionalContext with embedded routing rules.
203
- _context="STOP. Your FIRST action must be: call merlin_get_selected_repo, then call merlin_get_project_status, then call merlin_get_rules and merlin_get_brief in parallel. Do not respond to the user until you complete the boot sequence."
202
+ # โ”€โ”€ 4a. Session banner (best-effort, all reads use || true) โ”€โ”€โ”€โ”€
203
+ _SCRIPTS_DIR="${HOME}/.claude/scripts"
204
+
205
+ # Project name: git basename or pwd basename (handle spaces in path)
206
+ _git_top=$(git -C "${PWD}" rev-parse --show-toplevel 2>/dev/null || true)
207
+ if [ -n "${_git_top:-}" ]; then
208
+ _project_name=$(basename "${_git_top}" 2>/dev/null || true)
209
+ else
210
+ _project_name=$(basename "${PWD}" 2>/dev/null || true)
211
+ fi
212
+ if [ -z "${_project_name:-}" ]; then
213
+ _project_name="project"
214
+ fi
215
+
216
+ # Mode: Solo or Duo
217
+ _duo_status="disabled"
218
+ if [ -x "${_SCRIPTS_DIR}/duo-mode-read.sh" ]; then
219
+ _duo_status=$("${_SCRIPTS_DIR}/duo-mode-read.sh" 2>/dev/null || echo "disabled")
220
+ fi
221
+ _duo_installed=false
222
+ if [ -x "${_SCRIPTS_DIR}/duo-installed.sh" ]; then
223
+ if "${_SCRIPTS_DIR}/duo-installed.sh" 2>/dev/null; then
224
+ _duo_installed=true
225
+ fi
226
+ fi
227
+ if [ "${_duo_status}" = "enabled" ] && [ "${_duo_installed}" = "true" ]; then
228
+ _mode_label="Duo"
229
+ else
230
+ _mode_label="Solo"
231
+ fi
232
+
233
+ # Codex: installed or missing
234
+ _codex_label="missing"
235
+ if [ -x "${_SCRIPTS_DIR}/codex-installed.sh" ]; then
236
+ if "${_SCRIPTS_DIR}/codex-installed.sh" 2>/dev/null; then
237
+ _codex_label="installed"
238
+ fi
239
+ fi
240
+
241
+ # Badge: use duo-badge.sh if available
242
+ _badge="โŸก๐Ÿ”ฎ MERLIN โ€บ"
243
+ if [ -x "${_SCRIPTS_DIR}/duo-badge.sh" ]; then
244
+ _badge=$("${_SCRIPTS_DIR}/duo-badge.sh" 2>/dev/null || echo "โŸก๐Ÿ”ฎ MERLIN โ€บ")
245
+ fi
246
+
247
+ # Recommended next action (priority order, all reads use || true)
248
+ _next_action="Ready: ask anything or /merlin:help"
249
+ if [ -f "${HOME}/.merlin/state/active-plan.md" ] || \
250
+ [ -f "${HOME}/.claude/merlin/active-plan.md" ] || \
251
+ [ -f "${PWD}/PLAN.md" ]; then
252
+ _next_action="Continue execution: /merlin:execute-phase"
253
+ elif [ -f "${HOME}/.merlin/state/verification.json" ]; then
254
+ _vfailed=""
255
+ if command -v jq >/dev/null 2>&1; then
256
+ _vfailed=$(jq -r '.status // ""' "${HOME}/.merlin/state/verification.json" 2>/dev/null || echo "")
257
+ fi
258
+ if [ "${_vfailed:-}" = "failed" ]; then
259
+ _next_action="Verification failed last time โ€” investigate or rerun"
260
+ fi
261
+ fi
262
+ if [ "${_next_action}" = "Ready: ask anything or /merlin:help" ]; then
263
+ if git -C "${PWD}" rev-parse --git-dir >/dev/null 2>&1 && [ ! -f "${PWD}/PROJECT.md" ]; then
264
+ _next_action="New project: /merlin:new-project"
265
+ fi
266
+ fi
267
+ if [ "${_next_action}" = "Ready: ask anything or /merlin:help" ] && \
268
+ [ -f "${HOME}/.merlin/state/tasks.json" ]; then
269
+ _pending=0
270
+ if command -v jq >/dev/null 2>&1; then
271
+ _tdone=$(jq '.done // 0' "${HOME}/.merlin/state/tasks.json" 2>/dev/null || echo "0")
272
+ _ttotal=$(jq '.total // 0' "${HOME}/.merlin/state/tasks.json" 2>/dev/null || echo "0")
273
+ if [ "${_ttotal:-0}" -gt 0 ] 2>/dev/null && [ "${_tdone:-0}" -lt "${_ttotal:-0}" ] 2>/dev/null; then
274
+ _pending=$(( _ttotal - _tdone ))
275
+ fi
276
+ fi
277
+ if [ "${_pending:-0}" -gt 0 ] 2>/dev/null; then
278
+ _next_action="${_pending} tasks pending: /merlin:next"
279
+ fi
280
+ fi
281
+
282
+ # Banner line 1: "โŸก๐Ÿ”ฎ MERLIN ยท connected ยท {project}" (spec format)
283
+ # Use the badge prefix (everything before "MERLIN") plus fixed text so
284
+ # "MERLIN ยท connected" always appears regardless of duo/solo badge variant.
285
+ _badge_prefix=$(echo "${_badge}" | sed 's/MERLIN.*//' 2>/dev/null || true)
286
+ _banner="${_badge_prefix}MERLIN ยท connected ยท ${_project_name} | Mode: ${_mode_label} ยท Codex: ${_codex_label} | Next: ${_next_action}"
287
+
288
+ # โ”€โ”€ 4b. Build the additionalContext with banner + routing rules โ”€
289
+ _context="${_banner} || STOP. Your FIRST action must be: call merlin_get_selected_repo, then call merlin_get_project_status, then call merlin_get_rules and merlin_get_brief in parallel. Do not respond to the user until you complete the boot sequence."
204
290
  _context="${_context} AFTER BOOT โ€” MANDATORY ROUTING (you MUST follow this, do NOT skip):"
205
291
  _context="${_context} Bug/crash/error logs/deploy failure: use Skill(merlin:workflow, args=run bug-fix <summary>)."
206
292
  _context="${_context} Build feature/add feature: use Skill(merlin:workflow, args=run feature-dev <summary>)."
@@ -9,6 +9,7 @@
9
9
  # {"hookSpecificOutput":{"hookEventName":"Notification","statusLine":"..."}}
10
10
  #
11
11
  # Metrics included:
12
+ # - Merlin badge (from ~/.claude/scripts/duo-badge.sh โ€” duo-aware)
12
13
  # - Merlin version (from ~/.claude/merlin/VERSION)
13
14
  # - Active agents (from ~/.merlin/state/agents.json)
14
15
  # - Task progress (from ~/.merlin/state/tasks.json)
@@ -132,8 +133,15 @@ else
132
133
  RATE_DISPLAY="OK"
133
134
  fi
134
135
 
136
+ # โ”€โ”€ Badge (duo-aware) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
137
+ SCRIPTS_DIR="${HOME}/.claude/scripts"
138
+ BADGE="โŸก๐Ÿ”ฎ MERLIN โ€บ"
139
+ if [ -x "${SCRIPTS_DIR}/duo-badge.sh" ]; then
140
+ BADGE=$("${SCRIPTS_DIR}/duo-badge.sh" 2>/dev/null || echo "โŸก๐Ÿ”ฎ MERLIN โ€บ")
141
+ fi
142
+
135
143
  # โ”€โ”€ Compose statusline โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
136
- STATUSLINE="v${MERLIN_VERSION} | ${AGENT_COUNT} agents | ${TASKS_DISPLAY} | ${COST_DISPLAY} | ${GIT_BRANCH} | ctx:${CTX_DISPLAY} | rate:${RATE_DISPLAY}"
144
+ STATUSLINE="${BADGE} v${MERLIN_VERSION} | ${AGENT_COUNT} agents | ${TASKS_DISPLAY} | ${COST_DISPLAY} | ${GIT_BRANCH} | ctx:${CTX_DISPLAY} | rate:${RATE_DISPLAY}"
137
145
 
138
146
  # โ”€โ”€ Output โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
139
147
  if command -v jq >/dev/null 2>&1; then
@@ -6,7 +6,7 @@
6
6
  # session start.
7
7
  #
8
8
  # Contract:
9
- # - Reads JSON from stdin: {"userPrompt": "..."}
9
+ # - Reads JSON from stdin: {"prompt": "..."}
10
10
  # - Outputs {} when no pattern matches (no noise)
11
11
  # - Outputs additionalContext JSON when a routing signal is found
12
12
  # - MUST be <100ms: no network calls, no merlin CLI, no curl
@@ -23,13 +23,13 @@ fi
23
23
 
24
24
  [ -z "$input" ] && echo "{}" && exit 0
25
25
 
26
- # โ”€โ”€ Extract userPrompt โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
26
+ # โ”€โ”€ Extract prompt โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
27
27
  prompt=""
28
28
  if command -v jq >/dev/null 2>&1; then
29
- prompt=$(echo "$input" | jq -r '.userPrompt // empty' 2>/dev/null || true)
29
+ prompt=$(echo "$input" | jq -r '.prompt // empty' 2>/dev/null || true)
30
30
  else
31
31
  # Minimal extraction without jq โ€” strip surrounding JSON scaffolding
32
- prompt=$(echo "$input" | sed 's/.*"userPrompt"[[:space:]]*:[[:space:]]*"\(.*\)".*/\1/' 2>/dev/null || true)
32
+ prompt=$(echo "$input" | sed 's/.*"prompt"[[:space:]]*:[[:space:]]*"\(.*\)".*/\1/' 2>/dev/null || true)
33
33
  fi
34
34
 
35
35
  [ -z "$prompt" ] && echo "{}" && exit 0
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # merlin-codex.sh โ€” Merlin-aware Codex CLI wrapper
4
+ #
5
+ # Prints the Merlin engagement banner to stderr and injects the Merlin
6
+ # orchestrator system prompt into every Codex invocation. Pass-through
7
+ # subcommands (login, logout, mcp, etc.) are forwarded unchanged.
8
+ #
9
+ # Usage:
10
+ # merlin-codex # interactive Codex shell with Merlin banner
11
+ # merlin-codex exec "list files" # exec with Merlin prompt prepended
12
+ # merlin-codex "fix the auth bug" # prompt with Merlin prompt prepended
13
+ # merlin-codex --help # forwarded directly to codex
14
+ # merlin-codex login # forwarded directly (no prompt injection)
15
+ #
16
+ set -euo pipefail
17
+
18
+ SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
+ SYSTEM_PROMPT_FILE="${HOME}/.claude/merlin-system-prompt.txt"
20
+ FALLBACK_PROMPT="You are Merlin: orchestrator, not coder. Route implementation to specialists. Badge every action with โŸก๐Ÿ”ฎ MERLIN โ€บ."
21
+
22
+ # โ”€โ”€ Pass-through subcommands (no Merlin prompt injection) โ”€โ”€โ”€โ”€โ”€โ”€
23
+ PASSTHROUGH_CMDS="login logout mcp mcp-server app app-server completion sandbox debug"
24
+
25
+ # โ”€โ”€ Determine duo mode for banner โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
26
+ _mode_label="Solo"
27
+ if [ -x "${SCRIPTS_DIR}/duo-mode-read.sh" ]; then
28
+ _duo=$("${SCRIPTS_DIR}/duo-mode-read.sh" 2>/dev/null) || _duo="disabled"
29
+ 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
32
+ fi
33
+ fi
34
+ fi
35
+
36
+ # โ”€โ”€ Print banner to stderr (always) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
37
+ printf 'โŸก๐Ÿ”ฎ MERLIN ยท entering Codex via merlin-codex\n' >&2
38
+ printf '๐ŸŽฏ Mode: %s\n' "${_mode_label}" >&2
39
+ printf 'โ–ถ Codex will inherit Merlin'"'"'s orchestrator instructions\n' >&2
40
+
41
+ # โ”€โ”€ If no args, open interactive Codex shell โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
42
+ if [ $# -eq 0 ]; then
43
+ exec codex
44
+ fi
45
+
46
+ # โ”€โ”€ Check for pass-through subcommand or flags โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
47
+ FIRST_ARG="${1:-}"
48
+ for cmd in ${PASSTHROUGH_CMDS}; do
49
+ if [ "${FIRST_ARG}" = "${cmd}" ]; then
50
+ exec codex "$@"
51
+ fi
52
+ done
53
+ # Also pass through if first arg is a flag like --help, --version
54
+ if [[ "${FIRST_ARG}" == --* ]] || [[ "${FIRST_ARG}" == -* ]]; then
55
+ exec codex "$@"
56
+ fi
57
+
58
+ # โ”€โ”€ Load Merlin system prompt โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
59
+ MERLIN_PROMPT="${FALLBACK_PROMPT}"
60
+ if [ -f "${SYSTEM_PROMPT_FILE}" ]; then
61
+ MERLIN_PROMPT=$(cat "${SYSTEM_PROMPT_FILE}" 2>/dev/null) || MERLIN_PROMPT="${FALLBACK_PROMPT}"
62
+ fi
63
+
64
+ # โ”€โ”€ Inject Merlin prompt into Codex invocation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
65
+ # Try -c instructions= config override first (documented Codex flag).
66
+ # If the subcommand is "exec", inject into the prompt argument.
67
+ # Otherwise prepend to the full prompt string.
68
+ if [ "${FIRST_ARG}" = "exec" ]; then
69
+ shift
70
+ # $@ is now the prompt(s) passed to codex exec
71
+ ORIGINAL_PROMPT="${*:-}"
72
+ FULL_PROMPT="${MERLIN_PROMPT}"$'\n\n'"---USER---"$'\n\n'"${ORIGINAL_PROMPT}"
73
+ exec codex exec "${FULL_PROMPT}"
74
+ else
75
+ # Treat remaining args as a single prompt string
76
+ ORIGINAL_PROMPT="${*:-}"
77
+ FULL_PROMPT="${MERLIN_PROMPT}"$'\n\n'"---USER---"$'\n\n'"${ORIGINAL_PROMPT}"
78
+ exec codex "${FULL_PROMPT}"
79
+ fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-merlin-brain",
3
- "version": "5.0.0",
3
+ "version": "5.0.2",
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",