feat(bus): the bus host runs an explicit Claude Code binary (#1561, row 68)

MOSAIC_CLAUDE_BIN names the claude binary by absolute path instead of
finding it on PATH. scripts/bus-service.sh render|install --claude PATH
writes it into the unit (default: command -v claude in the installing
shell); the claude adapter, the launcher's version read and the seat
session environment all use it. Mos's Q18 ask: the unit's PATH found
/usr/bin/claude 2.1.259, which refuses claude-opus-5-5.

Candidate: round 2 manifest 21c1ab05, round 1 (a2008d8b) rebased onto
f2f2861b after row 55 changed docs/TOOLS.md and packages/cli/README.md;
the changed lines are byte-identical. Approved by Filbert (27349, 27374)
and Dewey (27350, 27375). Sage's gate on f2f2861b plus the patch: cli
112, seat 27, harness 57, nine scripts/test-*.sh 0 failed, Docker on.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-11 16:42:23 -05:00
co-authored by Claude Opus 5.5
parent 6ee63518a3
commit 11dae0c7d8
13 changed files with 248 additions and 25 deletions
+3 -1
View File
@@ -55,7 +55,8 @@ Optional, adapter-specific (documented per adapter):
print mode (`-p`), ambient discovery disabled, stdin detached.
- `mock` — deterministic echo of `MOSAIC_MOCK_RESPONSE`. Test-only: never use
it where a real model response is required.
- `claude` — the host's `claude` CLI, for managed sessions only (below).
- `claude` — the host's `claude` CLI, for managed sessions only (below):
`MOSAIC_CLAUDE_BIN` when set, else `claude` on `PATH`.
Not a worker adapter: the image has no `claude`, and the adapter refuses
without the bundle's hook and MCP files.
@@ -76,6 +77,7 @@ session's workspace and its own process group. Same contract, plus:
| `MOSAIC_TURN_MARKER` | `pi`: the extension writes it at `agent_end`; a pi turn that exits 0 without it failed. |
| `MOSAIC_EXTENSIONS` | `pi` only: extension files loaded with `-e`; a missing one exits 2. |
| `MOSAIC_CLAUDE_SETTINGS`, `MOSAIC_CLAUDE_MCP_CONFIG` | `claude` only: the bundle's gate hook and MCP server; required. |
| `MOSAIC_CLAUDE_BIN` | `claude` only: absolute path of the CLI to run, from the host's environment (the bus unit pins it). Unset or empty runs `claude` from `PATH`; a relative path or a non-executable file exits 2. |
The layers each adapter relies on, and what they don't cover, are in
`packages/harness/README.md`.
+12 -2
View File
@@ -1,6 +1,7 @@
#!/bin/sh
# Claude Code adapter: implements the Mosaic adapter contract for the host's
# `claude` CLI, for managed sessions (slice 1 S6). Headless only.
# `claude` CLI, for managed sessions (slice 1 S6). Headless only. The CLI is
# MOSAIC_CLAUDE_BIN when set (the bus unit pins it), else `claude` on PATH.
#
# Contract: see adapters/README.md.
# stdout = the turn's answer only; stderr = diagnostics; exit 0 on success.
@@ -26,6 +27,15 @@ for f in "$MOSAIC_SYSTEM_PROMPT_FILE" "$MOSAIC_CLAUDE_SETTINGS" "$MOSAIC_CLAUDE_
[ -r "$f" ] || { echo "claude adapter: not readable: $f" >&2; exit 2; }
done
[ "${MOSAIC_INTERACTIVE:-}" != "1" ] || { echo "claude adapter: interactive mode isn't supported" >&2; exit 2; }
CLAUDE=claude
if [ -n "${MOSAIC_CLAUDE_BIN:-}" ]; then
case "$MOSAIC_CLAUDE_BIN" in
/*) ;;
*) echo "claude adapter: MOSAIC_CLAUDE_BIN must be an absolute path: $MOSAIC_CLAUDE_BIN" >&2; exit 2 ;;
esac
[ -f "$MOSAIC_CLAUDE_BIN" ] && [ -x "$MOSAIC_CLAUDE_BIN" ] || { echo "claude adapter: MOSAIC_CLAUDE_BIN is not an executable file: $MOSAIC_CLAUDE_BIN" >&2; exit 2; }
CLAUDE=$MOSAIC_CLAUDE_BIN
fi
mkdir -p "$MOSAIC_WORKSPACE" "$MOSAIC_SESSION_DIR"
cd "$MOSAIC_WORKSPACE"
@@ -63,7 +73,7 @@ fi
ALLOWED=mcp__mosaic
[ -z "${MOSAIC_TOOLS:-}" ] || ALLOWED="$MOSAIC_TOOLS,mcp__mosaic"
PROMPT_CONTENT="$(cat "$MOSAIC_SYSTEM_PROMPT_FILE")"
claude -p "$MOSAIC_REQUEST" \
"$CLAUDE" -p "$MOSAIC_REQUEST" \
--output-format text \
--system-prompt "$PROMPT_CONTENT" \
--model "$MOSAIC_MODEL" \