> ## Documentation Index
> Fetch the complete documentation index at: https://docs.boat.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Customize the harness

> Add house rules, MCP servers, skills and tools to the harnesses on a sandbox, reach your own app, or bring your own harness.

Every harness reads its own config files from the sandbox home. Boat adds only two things:

* A short system prompt. It tells the harness that it runs headless in a sandbox, and that the `boat` CLI exists.
* The `boat` skill.

You add everything else. Use any of these:

* `boat ssh`, `boat exec` or `boat scp`
* a file that the agent writes
* an [environment setup script](/environments)
* a [named snapshot](/snapshots), so every new sandbox starts with it

We tested each row on this page end to end through `boat prompt`, on the current harness versions. Each row names the file that changed the answer of the harness.

## Instructions and hidden rules

Add a rules file. Every prompt on that sandbox then obeys it, even when the prompt does not mention it:

| Harness | Files read (all applied together) | Not read |
| - | - | - |
| Claude Code | `~/CLAUDE.md`, `~/.claude/CLAUDE.md` | `AGENTS.md` |
| Codex | `~/AGENTS.md`, `~/.codex/AGENTS.md` | `config.toml` `developer_instructions` (Boat sets the base instructions) |
| pi | `~/AGENTS.md`, `~/.pi/agent/AGENTS.md`, `~/.pi/agent/APPEND_SYSTEM.md` | `CLAUDE.md` when an `AGENTS.md` exists |
| OpenCode | `~/AGENTS.md`, `~/.config/opencode/AGENTS.md`, files listed in `opencode.json` `instructions` | |
| Prime Agent | `~/AGENTS.md`, `~/.prime/agent/AGENTS.md`, `~/.prime/agent/APPEND_SYSTEM.md` | |
| Kimi Code | `~/AGENTS.md`, `~/.kimi-code/AGENTS.md`, `~/.agents/AGENTS.md` | `CLAUDE.md` |
| Mistral Vibe | `AGENTS.md` at the root of a git repository it works in, after you trust that folder (`~/.vibe/trusted_folders.toml`) | `~/AGENTS.md`, `CLAUDE.md`. Use a skill for house rules |

* One `~/AGENTS.md` plus one `~/CLAUDE.md` covers every harness except Mistral Vibe.
* `APPEND_SYSTEM.md` (pi, Prime) goes at the end of the system prompt itself, not into the project context.
* When an environment clones a single repository, Claude Code starts inside that repository. So a `CLAUDE.md` there also applies.

```bash theme={null}
boat exec "printf '# House rules\nAlways run the test suite before saying you are done.\n' > ~/AGENTS.md; cp ~/AGENTS.md ~/CLAUDE.md"
```

## MCP servers

| Harness | How to register | Config written |
| - | - | - |
| Claude Code | `claude mcp add --scope user <name> -- <command>` | `~/.claude.json` (project scope: `~/.mcp.json`) |
| Codex | `codex mcp add <name> -- <command>` | `~/.codex/config.toml` `[mcp_servers.<name>]` |
| pi | `pi install npm:pi-mcp-extension`, then `~/.pi/agent/mcp.json` | `{"mcpServers": {"<name>": {"transport": "stdio", "command": …, "lifecycle": "eager"}}}` |
| OpenCode | `~/.config/opencode/opencode.json` | `"mcp": {"<name>": {"type": "local", "command": [...]}}` |
| Prime Agent | `prime-agent mcp add <name> -- <command>` | `~/.prime/agent/settings.json` `mcpServers` |
| Kimi Code | `~/.kimi-code/mcp.json` | `{"mcpServers": {"<name>": {"command": …, "args": [...]}}}` (`{"url": …}` for HTTP) |
| Mistral Vibe | `~/.vibe/config.toml` | `[[mcp_servers]]` with `name`, `transport = "stdio"`, `command`, `args` (`url` for HTTP) |

* Remote (HTTP) servers work the same way, with a URL instead of a command.
* On a sandbox, the MCP resource browsing tools of Claude Code are turned off. MCP tools stay on.

Every sandbox already has one server registered this way: `computer`, in these same files. Your server next to it does not change it, and it never overwrites yours. Read [Computer use](/integrated-agents/computer-use).

## Reach your own app from the sandbox

A sandbox has no route back to your laptop. So the agents in it cannot see an MCP server, a local model, or a webhook receiver on your `localhost`.

`boat forward --reverse` opens that route. A port on your machine then answers at `127.0.0.1:<port>` inside the sandbox. It uses the same SSH session as `boat ssh`. Nothing is public on either end.

```bash theme={null}
# leave this running; your MCP server on localhost:7777 is now in the sandbox
boat forward bx_f7k2q9hd --reverse --local 7777
```

Register it one time inside the sandbox. Then every harness can call it:

```bash theme={null}
boat exec bx_f7k2q9hd "claude mcp add --scope user mine --transport http http://127.0.0.1:7777/mcp"
```

* The registration is in the sandbox home. It survives `boat stop`, `boat resume`, and `boat fork`.
* The tunnel does not survive. Start it again the next time the agent must reach you.
* A local model works the same way. `boat forward <id> --reverse --local 11434` puts Ollama on `http://127.0.0.1:11434` inside the sandbox. Any harness that uses that base URL can call it.

For the flags and the redial behaviour, read [`boat forward --reverse`](/cli-reference#--reverse-reach-your-machine-from-the-sandbox).

Products that do not ship the CLI can open the same tunnel. The CLI only wraps stock OpenSSH:

```bash theme={null}
# 1. authorize your public key on the sandbox; the reply carries machineIp
curl -s -X POST https://boat.dev/api/v1/sandboxes/$BOAT_ID/sshkey \
  -H "Authorization: Bearer $BOAT_API_KEY" -H 'Content-Type: application/json' \
  -d "{\"key\": \"$(cat ~/.ssh/id_ed25519.pub)\"}"
# 2. open the reverse tunnel and leave it running
ssh -o ExitOnForwardFailure=yes -i ~/.ssh/id_ed25519 -N -R 7777:127.0.0.1:7777 user@<machineIp>
```

## Skills

A skill is a folder with a `SKILL.md` file. The file has frontmatter with `name` and `description`, then the instructions. Every harness on a sandbox already has a skills directory with the `boat` skill in it. Add yours next to it:

| Harness | Skills directory |
| - | - |
| Claude Code | `~/.claude/skills/<name>/SKILL.md` |
| Codex | `~/.codex/skills/<name>/SKILL.md` |
| pi | `~/.pi/agent/skills/<name>/SKILL.md` |
| OpenCode | `~/.config/opencode/skills/<name>/SKILL.md` |
| Prime Agent | `~/.prime/agent/skills/<name>/SKILL.md` |
| Kimi Code | `~/.kimi-code/skills/<name>/SKILL.md` (also `~/.agents/skills/<name>/SKILL.md`) |
| Mistral Vibe | `~/.vibe/skills/<name>/SKILL.md` (also `~/.agents/skills/<name>/SKILL.md`) |

## Command-line tools

Anything on `PATH` is a tool. To add one, do one of these:

* Put a script in `~/.local/bin` or `/usr/local/bin`.
* Install it with `npm i -g`, `pip install` or `apt install`.

Then ask for it by name. All seven harnesses run it through their shell tool.

## Custom in-process tools and extensions

Use these when a tool must show as a native function call, not a shell command:

| Harness | Mechanism | Path |
| - | - | - |
| pi | extension calling `pi.registerTool({...})` | `~/.pi/agent/extensions/<name>.ts` |
| Prime Agent | same extension API | `~/.prime/agent/extensions/<name>.ts` |
| OpenCode | `tool({description, args, execute})` from `@opencode-ai/plugin` (dependencies install themselves on first run) | `~/.config/opencode/tools/<name>.ts` |
| Claude Code | hooks in `~/.claude/settings.json`, plugins | see [Claude Code docs](https://code.claude.com/docs/en/hooks) |
| Codex | hooks in `~/.codex/hooks.json` | see [Codex docs](https://learn.chatgpt.com/docs/hooks) |
| Kimi Code | `[[hooks]]` in `~/.kimi-code/config.toml`, plugins | see [Kimi Code docs](https://www.kimi.com/code/docs/en/kimi-code-cli/customization/hooks.html) |
| Mistral Vibe | hooks in `~/.vibe/hooks.toml` | see [Mistral Vibe on GitHub](https://github.com/mistralai/mistral-vibe#hooks) |

## What is shared, what persists

* **Config is per sandbox, not per conversation.** Every parallel conversation on a sandbox reads the same home directory, whatever its harness. There is one `AGENTS.md`, one skills folder, one MCP list. For rules per user, use a sandbox per user, or put the rules in the prompt.
* **Boat captures everything in `/home/user` on stop.** Rules, MCP registrations, skills, extensions, tools you installed under home, and the harness sessions all come back on `boat resume` and `boat fork`. Tools installed outside home (`apt`, `/usr/local`) are also part of the system snapshot.
* **Set it up one time.** An [environment](/environments) setup script or a [named snapshot](/snapshots) gives every new sandbox the same rules, tools and servers from the first prompt.

## Bring your own harness

The built-in harnesses are ordinary binaries on `PATH`. They have the same credentials that the agent server uses. You have three ways to go further than `boat prompt`:

* **Run a built-in harness yourself.** Use `boat ssh` or `boat exec`. Run `claude`, `codex`, `pi`, `opencode`, `prime-agent`, `kimi`, or `vibe` (Mistral Vibe) directly, in any mode they support. The agent server does not lock the files or the processes.
* **Install a harness that Boat does not ship.** Run `boat exec "npm i -g <harness>"`, or add it to an environment or a snapshot. Run it over `boat exec` or SSH. It works next to the built-in harnesses and reads the same per-sandbox `-e` keys.
* **Run your own agent loop.** Put a small HTTP daemon in the sandbox and talk to it directly. The [Platform Guide](/platform-guide/agents#bring-your-own-harness-the-daemon-pattern) shows how. `boat host` gives it a URL. [Webhooks](/webhooks) tell your control plane when the sandbox is up.

Whatever you run, these keep working: `boat events`, attachments under `~/attachments`, [desktop streaming](/desktop-streaming), snapshots, and forks.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.