Adds the harness plug-in kind (interface 1). packages/plugins/harness/pi and claude-code hold what core branched on: the adapter, thinking levels, preflight, version probe, sandbox mounts, builtins line, typed tool names, gate timeout, bundle files, adapter env, turn end and session-files path. Core reaches a module only through the loader. A session's route is the instance's harness, model and thinking vars, or the three fallback. vars; a missing one refuses no-route, and the system file's execution keys are never read for a session. The launcher checks the primary route, then the fallback: harness-off, harness-refused, thinking-unsupported, then preflight. A failed preflight falls back when a fallback is set, and any refusal of the fallback names the primary's failure too. Account checks run only when the route's module counts an account. The manifest records route, routeReason and harnessVersion, replacing piVersion and claudeVersion. pi gets --thinking, Claude Code --effort, both from MOSAIC_THINKING. The business file refuses a partial fallback. routes and routes.set are human-only bus verbs outside ORGANIZATION_KEYS; checkRoutes is shared by routes.set, instances.set and limits.set and checks only changed routes. The chief of staff changes an instance's model, and the assistant's whole vars (Q169), through limits.set, so its route write runs the same checks. A model outside launch.models refuses unknown-model, primary or fallback, and routes.set passes that code through. A new run binds only on a switched-on harness module name and records its transcript path, which the usage reader uses. Settings gains a Routing table with six selects per instance and loses the Role models fieldset; it posts changed rows to /api/routes. webui/src/bus.mjs is unchanged. Until Jason's `mosaic plugins set` adds "harness": ["claude-code"], a new launch refuses harness-off.
85 lines
4.1 KiB
Markdown
85 lines
4.1 KiB
Markdown
# 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/<name>/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):
|
|
`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.
|
|
|
|
## 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 <adapters/<name>/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. |
|
|
| `MOSAIC_THINKING` | The route's thinking level (row 65), which the harness module's `levels()` already checked. `pi` passes `--thinking` (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`) and omits it when unset, as for `run-task.sh` workers. `claude` passes `--effort` (`low`, `medium`, `high`, `xhigh`, `max`) and requires it; unset exits 2. |
|
|
| `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`.
|