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

# Chat (Experimental)

> Ask questions about your experiments in the Pluto UI, answered by your own Claude Code or Codex running locally.

<Warning>
  Experimental features are new and their interface and implementation may change at any time. Expect sharp edges.
</Warning>

**Chat** in the Pluto sidebar answers questions about your runs in plain language — "why did MMP-42 diverge?", "which of last week's runs had the most stable loss?" — by querying your metrics, logs, config and files directly.

It has two backends, chosen from the **Chat backend** selector at the top of the page:

| Backend | Who runs the model | Availability |
| - | - | - |
| **Local agent** | Your own Claude Code or Codex, on your machine | Anyone with a Pluto API key |
| **Server model** | A model hosted by Trainy | Private preview — [ask us](mailto:support@trainy.ai) to enable it for your organization |

This page covers **Local agent** mode, which is available today.

## How local agent mode works

A small program called the **bridge** runs on your machine. The Pluto web app sends it your chat messages over loopback; the bridge runs your agent CLI, and the agent looks up experiment data through the [Pluto MCP server](/pluto/mcp) using your API key.

```
Pluto Chat (browser) ──▶ pluto-bridge (127.0.0.1) ──▶ claude / codex ──▶ Pluto MCP
```

Two consequences worth knowing up front:

* **Inference runs on your machine**, under your own Claude or ChatGPT subscription. Chat costs nothing extra and uses no Trainy model quota.
* **Conversations never pass through Trainy's servers.** Only the data lookups your agent makes reach Pluto, as ordinary authenticated API calls.

## Requirements

* Node.js 20.10 or newer
* [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (`claude`) or [Codex](https://github.com/openai/codex), installed and signed in
* A Pluto API key — **Settings > Developers > API Keys** at [pluto.trainy.ai](https://pluto.trainy.ai)

You do **not** need to set up the MCP server separately. The bridge configures it for the agent session it starts.

## Setup

### Step 1: Start the bridge

In the Pluto UI, open **Chat** and set the backend selector to **Local agent**. The page shows the exact command to run, pinned to a version:

```bash theme={null}
PLUTO_API_KEY=mlpi_... npx @trainy-ai/pluto-bridge@1.0.0
```

Run it in a terminal. Use the command shown on the Chat page rather than this one — it pins the version that page expects, which is how a compromised release cannot reach you automatically.

The bridge prints a port and a pairing token:

```
Pluto bridge listening on http://127.0.0.1:8377
Agent: claude
Allowed origins: https://pluto.trainy.ai
Pluto tools: read-only (pass --allow-writes to let the agent change tags, notes and dashboards)

In the Pluto Chat page, choose "Local agent" and enter:
  Port:  8377
  Token: 4f1f4ea69b...
```

### Step 2: Pair the browser

Click **Connect agent**, enter that port and token, and save. The dot next to the button turns green once the health check succeeds.

The token is stored at `~/.config/pluto-bridge/token` and reused, so restarting the bridge does not break the pairing. You only pair again if you rotate the token with `--rotate-token`.

### Step 3: Ask

Pick a project from the selector and ask away:

> "Compare train/loss across my last three runs — which one converged fastest?"

> "Run MMP-42 failed at step 12000. What do the logs say?"

> "Are there any loss spikes in the runs tagged `baseline`?"

Multi-turn context uses your agent's own session resume, so follow-up questions keep the thread.

## What the agent can reach

The agent gets an explicit allowlist of **read-only** Pluto tools — projects, runs, metrics, logs, files, statistics, comparisons and dashboards. The full tool list is on the [MCP Integration](/pluto/mcp#available-tools) page.

Pass `--allow-writes` to additionally let it add or remove tags, edit notes, and create, edit or restore dashboards:

```bash theme={null}
PLUTO_API_KEY=mlpi_... npx @trainy-ai/pluto-bridge@1.0.0 --allow-writes
```

<Warning>
  Everything the agent can reach is bounded by **your** API key, so it sees exactly the projects you do — no more. With `--allow-writes` it can change tags, notes and dashboards for anyone in your organization, so leave it off unless you want the agent editing shared state.
</Warning>

## Options

| Flag | Meaning |
| - | - |
| `--agent claude\|codex` | Which CLI answers chats (default `claude`) |
| `--port <n>` | Loopback port (default `8377`) |
| `--allow-writes` | Let the agent change tags, notes and dashboards. Off by default. |
| `--origin <origin>` | Also accept chats from this Pluto web origin. Repeatable. Needed for self-hosted Pluto. |
| `--mcp-url <url>` | Pluto MCP endpoint for self-hosted Pluto (default `https://pluto-mcp.trainy.ai/mcp/`) |
| `--mcp-config <path>` | Claude only: an MCP config file to use instead of `--mcp-url`. It must define a server named `pluto`. |
| `--token <s>` | Use this pairing token for one run, without saving it |
| `--rotate-token` | Replace the saved pairing token. Pair the Chat page again afterwards. |
| `--claude-bin` / `--codex-bin` | Paths to the agent binaries |

### Self-hosted Pluto

A self-hosted deployment serves the UI and the MCP from your own domains, so name both:

```bash theme={null}
PLUTO_API_KEY=mlpi_... npx @trainy-ai/pluto-bridge@1.0.0 \
  --origin https://pluto.example.com \
  --mcp-url https://pluto-mcp.example.com/mcp/
```

## Security

* **Loopback only.** The bridge listens on `127.0.0.1`, so other machines cannot reach it.
* **Pairing token.** Every request must carry the token, and the token file is readable only by you (`0600`).
* **Origin allowlist.** Browsers may call the bridge only from `https://pluto.trainy.ai` plus any origins you add with `--origin`. Someone who sees your token still cannot use it from another website.
* **Read-only is enforced by the agent, not by a prompt.** Claude Code runs with `--strict-mcp-config` and the write tools in `--disallowedTools`, which beats your own allow rules; Codex runs with `--ignore-user-config`, `enabled_tools` limited to the granted tools, and shell commands in the `read-only` sandbox. Text sitting in run data cannot talk the model past that boundary.
* **Your API key stays out of the process list.** The agent reads `PLUTO_API_KEY` from its environment, never from a command-line argument.
* **No runtime dependencies and no install scripts** in the published package.

<Note>
  Because Codex runs with `--ignore-user-config`, settings in your `~/.codex/config.toml` — model choice among them — do not apply to bridge chats. Sign-in still comes from `CODEX_HOME`.
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="The bridge logs 'Refused a request from <origin>'">
    The browser origin is not on the allowlist. Restart the bridge with `--origin <that origin>` — needed for any self-hosted Pluto, and for `http://localhost:3000` during local development.
  </Accordion>

  <Accordion title="'Lost contact with the local agent bridge'">
    The bridge stopped answering — usually the terminal was closed or the machine slept. Your conversation is still on screen; restart the same command and it reconnects automatically, because the pairing token persists.
  </Accordion>

  <Accordion title="'Chat is not enabled' when the backend is Server model">
    Your organization is not in the private preview for the hosted model. Switch the selector to **Local agent**, which works regardless, or [contact us](mailto:support@trainy.ai).
  </Accordion>

  <Accordion title="The agent answers without looking anything up">
    Check that the terminal running the bridge shows `Agent: claude` (or `codex`) and no MCP errors. If the agent CLI is not signed in, it fails before reaching the Pluto tools — run `claude` or `codex` once on its own first.
  </Accordion>
</AccordionGroup>

## Feedback

Chat and the bridge are experimental. We'd love to hear how they behave on real experiments:

* **Discord**: [Join our community](https://discord.com/invite/HQUBJSVgAP)
* **Email**: [support@trainy.ai](mailto:support@trainy.ai)
