# Mosaic runtime adapters An adapter is the entire harness-specific surface of the system. Everything upstream of an adapter — configuration, contracts, missions, tasks, run records — is harness-agnostic; everything inside an adapter may assume one specific agent runtime. ## Contract An adapter lives at: ```text /opt/mosaic/adapters//adapter.sh ``` and must be executable. The dispatcher (`/opt/mosaic/src/run-agent.sh`) selects it via `MOSAIC_ADAPTER` (default: `pi`) and execs it after the system prompt has been generated. **Inputs (environment):** | Variable | Meaning | |---|---| | `MOSAIC_SYSTEM_PROMPT_FILE` | Absolute path to the generated system prompt (contracts + optional mission section). Read it; do not modify it. | | `MOSAIC_REQUEST` | The exact user request text (may contain newlines). | | `MOSAIC_PROVIDER` | Configured provider name. | | `MOSAIC_MODEL` | Configured model id. | Optional, adapter-specific (documented per adapter): | Variable | Meaning | |---|---| | `MOSAIC_MOCK_RESPONSE` | mock only: the verbatim response to emit | **Outputs:** - `stdout`: the model response text — the only channel the orchestrator captures - `stderr`: diagnostics (never credentials) - exit `0`: success; nonzero: failure ## Rules 1. Adapters print ONLY the response on stdout. Status lines go to stderr. 2. Adapters never read configuration files; the resolved settings arrive via environment. 3. Adapters never write outside `/var/lib/mosaic`. 4. Adding a worker adapter requires: a new directory, the contract implementation, and adding the name to the allowlist in `scripts/mosaic-config.mjs`. A managed-session adapter (below) is selected by the launch bundle, not by `execution.adapter`, and is not on that allowlist unless it also works as a worker adapter. ## Included adapters - `pi` — the pinned `@earendil-works/pi-coding-agent` CLI in noninteractive 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). Not a worker adapter: the image has no `claude`, and the adapter refuses without the bundle's hook and MCP files. ## Managed sessions (slice 1 S6) The session runner (`packages/harness/src/runner.mjs`) runs one adapter call per turn on the host, as `/bin/sh /adapter.sh>` (the repository keeps adapters 0644; only the image sets the mode), in the session's workspace and its own process group. Same contract, plus: | Variable | Meaning | |---|---| | `MOSAIC_WORKSPACE` | The session's workspace; the adapter runs there. | | `MOSAIC_SESSION_DIR` | The session's persistent directory; later turns resume the session kept there. | | `MOSAIC_TOOLS` | The built-in tool limit (pi names for `pi`, Claude Code names for `claude`), comma-separated. | | `MOSAIC_POLICY_FILE`, `MOSAIC_TOOLS_FILE` | The bundle's gate policy and typed tools. | | `MOSAIC_TOOL_SOCKET` | The runner's tool socket, which the typed tools call. | | `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. | The layers each adapter relies on, and what they don't cover, are in `packages/harness/README.md`.