# Remote agents

How an agent that its provider will not let keep a Fossil login key, such as
one of OpenAI's or Anthropic's, works on a project through OCX: it reaches
OCX's MCP tools through its provider's tunnel, which connects out from the
server's host, so no port is opened, and OCX syncs its work for it, as its
own Fossil user. The plan behind it is [PLAN.md](../PLAN.md), "Agents on
protocol v1"; the tools' common shape is [USAGE.md](../USAGE.md).

## MCP for a remote agent

* `ocx2 --mcp-http HOST:PORT` serves MCP over HTTP on this host's loopback
  alone, each JSON-RPC message posted to `/mcp`, for a client beside it such
  as a provider's tunnel.
* `ocx2 --mcp-tunnel TUNNEL-ID` is OCX's own client of OpenAI's Secure MCP
  Tunnel, long-polling the tunnel's control plane and connecting out alone,
  its key in `OCX_TUNNEL_KEY`, which its run's node fills from the run's
  secret.
* In a clone, as a run's process is, the MCP server answers for its user as
  the server grants that user, asked of the server's `receipt`, not as the
  clone lists its cloner, setup.

## Set a secret a run may use

`secret NAME VALUE` sets a secret on the served repository, such as a tunnel's
key, for a user with admin or setup, from the web page, where the value is a
password field, or the served host's command line; never over MCP. It is a
setting of the repository's own, `ocx-secret-NAME`, which no clone a run's
user makes holds, and no answer, log or page shows its value. A run an admin
sends names it as `$$secret:NAME$$` in its process's `env`, and the node fills
it in there alone, on the server's node; `started` and the kept logs show its
name where its value would be
([protocol v1, section 2](protocol-v1.md#values)).

## Sync an agent's work through the call

`sync BRANCH`, for an agent that keeps no Fossil login key, through its run's
MCP (`ocx_sync`) or in a clone's checkout: the agent commits in its own clone
on its working branch, never trunk, each comment with Intent, Expression and
Demonstrates lines, runs `fossil bundle export push.bundle --branch BRANCH
--standalone`, and gives the file base64 as `bundle`. Each check-in is read
before anything is imported, and one off the branch or unstated refuses the
whole bundle; the rest are imported into the run's clone and pushed as the
run's user, whose capabilities the server holds them to. Its answer names
each check-in pushed as the server holds it: its hash in full, its link, and
the user the server's receipt says sent it. With `have`, a check-in the agent
holds, the clone pulls and answers a bundle of every check-in after it, which
the agent applies with `fossil bundle import pulled.bundle --publish`.
`receipt` in a run's clone asks the server's own receipt tool, as anyone
may, and says so.

`commit_and_sync_guide BRANCH`, offered everywhere, says those steps as
commands for the agent's own shell, filling the stated message from the
`title`, `intent`, `expression` and `demonstrates` it gives. `commit_and_sync`
takes them, for an agent running `ocx2 --mcp` on its own machine: it commits
its checkout's changes on its working branch with that message, without
syncing, and answers the branch's bundle for `ocx_sync`; called remotely,
through a tunnel, MCP over HTTP or the web page, it does nothing and points
to the guide.

## Edit the run's checkout

An agent with no clone of its own works on the run's checkout through its
MCP ([docs/agent-tools-proposal.md](agent-tools-proposal.md) says why each is
shaped as it is): `ocx_context`, what the run is for and where its work
stands; `ocx_find`, the lines holding a text; `ocx_read`, a file's lines
exactly, their numbers apart; `ocx_edit`, a text that appears once replaced;
`ocx_test`, one of the tests the project names in `ocx-tests.json` at its
checkout's root, each a name and its command as a list of words; and
`ocx_save`, every change committed on the working branch, `agent/`, the
user and eight hex digits, once each test has passed with the checkout as it
is, and pushed as the run's user. `ocx_wiki_read` and `ocx_wiki_edit` share
wiki pages, a page changed as `ocx_edit` changes a file; `ocx_unversioned_list`,
`ocx_unversioned_get` and `ocx_unversioned_put` share binaries as Fossil's
unversioned files, base64. Every tool's answer begins with `ok`, and a
refusal gives `next_step`, what to do instead.

## The pattern `run/mcp-tunnel`

One run of it per remote agent brings that agent in: its process is OCX's
tunnel client, in the run's own clone, acting as the run's user, the agent's
own Fossil user. Save the block below, with a line saying what it is for, as
the wiki page `run/mcp-tunnel`, as a user holding admin or setup.

```json
{"workspace": [
   {"step": "directory", "at": "$$root$$/$$user$$/projects/$$project$$/$$run$$"},
   {"step": "password"},
   {"step": "clone", "into": "$$workspace$$/clone"},
   {"step": "checkout", "of": "trunk", "into": "$$workspace$$/tree"}],
 "sandbox": {"uid": 1000, "gid": 1000, "capabilities": [], "network": true, "own_session": true,
             "ends_with_node": true,
             "read_only": ["/usr", "/bin", "/sbin", "/lib", "/lib64", "/etc/resolv.conf", "/etc/hosts",
                           "/etc/nsswitch.conf", "/etc/ssl", "$$release$$"],
             "read_write": ["$$workspace$$"], "homes": [],
             "files": [{"at": "/etc/passwd", "text": "$$user$$:x:1000:1000::$$workspace$$:/bin/sh\n"}],
             "proc": "/proc", "dev": "/dev", "tmp": "/tmp"},
 "limits": {"wall": "30d"},
 "process": {"command": ["ocx2", "--mcp-tunnel", "TUNNEL-ID"], "cwd": "$$tree$$",
             "env": {"HOME": "$$workspace$$", "USER": "$$user$$", "PATH": "$$release$$:/usr/bin:/bin",
                     "OCX_TUNNEL_KEY": "$$secret:SECRET-NAME$$"}}}
```

To bring an agent in:

1. In Fossil's Admin → Users, make the agent's user, holding what it may do,
   such as `gio24` (clone, read code, check in, read the forum, post there).
2. In OpenAI's Platform, create a tunnel; note its id and its runtime key.
3. Set the key: `secret NAME KEY` on the OCX page, NAME such as `chatgpt`.
4. On the OCX page, `create` with the objective, `pattern` `run/mcp-tunnel`,
   `user` the agent's user, and `fields`
   `{"process": {"command": ["ocx2", "--mcp-tunnel", "TUNNEL-ID"], "env": {"OCX_TUNNEL_KEY": "$$secret:NAME$$"}}}`
   with the tunnel's id and the secret's name.
5. Give the agent the tunnel, by its id, as its MCP server: in a ChatGPT
   workspace, the tunnel alone is not enough: at <https://chatgpt.com/plugins>,
   **Add** a plugin that uses it, and the workspace's agent then lists OCX's
   tools. It learns the rest from
   `tools/list`, `ocx_commit_and_sync_guide` first.

A stop ends the run, and the tunnel with it.
