Login
Proposal: editing tools for agents over OCX’s MCP
Login

Decided and built (HISTORY.md decisions 65 to 68); the tools below are as built, and the maintainer's answers are under "Decided". Written 2026-10-15 on branch agent-tools, from the maintainer's direction: "take the "trunk" lessons learned along with other lessons learned and produce a set of easy to use agent tools available over the remote MCP that even local agents could use to perform editing." "Trunk" there is OCX's earlier design, on the branch trunk of this repository. This proposal settled PLAN.md's "An agent's MCP surface"; the names are the maintainer's first answer.

The problem

An agent reached through OCX's MCP can talk, post and sync, but cannot read or change a file. A remote agent, one reached through its provider's tunnel (docs/remote-agents.md), edits its own clone and brings its work in through sync, as a Fossil bundle: five shell steps that a weak model gets wrong. A local model, one OCX runs itself on a node (PLAN.md's "native agent"), has no clone of its own at all. Both need the same thing: a few tools that read and change the run's own checkout, test the change, and save it.

What the tools act on

The run's checkout, $$tree$$, the one its workspace steps made, where its MCP server runs. The agent needs no clone, no Fossil and no password. The run's sandbox and the capabilities of the run's user, the Fossil user its process acts as (process.user), bound everything, as for every run. Edits stay in the run's workspace until saved; a run that ends drops what it did not save. A remote agent that keeps its own clone may still use sync.

The tools

Six, the fewest that cover one edit from start to saved; the wiki and unversioned files' tools came with the maintainer's fifth answer, and one more is added only when a task shows the need. Every answer starts with ok, true or false; a refusal's next_step says in one line what to do instead.

Tool Takes Gives
ocx_context nothing the run's objective, its working branch, the files changed and not saved, and the tests it may run
ocx_find text, matched exactly, case and all; optionally path, to search under each line holding it, as its path, its line number and its text, at most 50; and how many more there are
ocx_read path; from, a line number, default 1 text: up to 200 lines from from, exactly as in the file, with no numbers in it; first_line, last_line and lines, how many the file has
ocx_edit path; old, the exact text to replace, copied from ocx_read's text; new, its replacement the changed lines, as ocx_read gives them
ocx_test optionally name, one of the tests ocx_context lists; without it, every test whether each passed, and the last 100 lines it wrote
ocx_save title, intent, expression, demonstrates: one line each, a part that runs over lines read as one the check-in, by its hash, its link on the server, and the user the server's receipt names

ocx_edit replaces old only where it appears exactly once. With old empty it adds new at the file's end, making the file if there is none, since the battery's first live trial showed models adding to a file that way (decision 66). It neither deletes nor renames a file.

A test is a command the checkout's ocx-tests.json names, run in the checkout within the run's limits.

ocx_save commits every change on the run's working branch, never the branch trunk, and pushes it as the run's user. It refuses unless each test the run lists has passed since the last edit. Its four lines are the check-in's comment, which the server requires of every check-in:

When the push fails, the check-in stays in the run's clone, and next_step says to save again; with nothing changed, ocx_save pushes what is saved but not yet sent. It writes no verdict; a review is a person's or another agent's, as now. Answering on the forum stays post.

Lessons it follows

Each from trunk's code and history; from the battery, OCX's trials of fresh readers, small local models among them; or from agents' use since, such as Slowpen's, a ChatGPT agent's report on mechanical-turk.

  1. Copy, never guess, the text to replace. ocx_read's text is exactly what ocx_edit's old takes, its line numbers kept apart so none is pasted in. Found nowhere, the refusal says "read the lines again with read and copy old exactly from its text"; found more than once, "add a line before or after to old to make it unique". Trunk's prompt: "read the exact surrounding range and copy the literal text; do not guess anchors from memory."
  2. One field per meaning, and no example to copy as a value. The battery's smallest model filled a field with the caller in 19 of 30 runs, until it was renamed for whose it is, and copied example values into real calls.
  3. A few tools, each named for what it does. Trunk's MCP grew to about 90 tools, and two names drifted from its list, so "every real client saw 'unknown tool'".
  4. Every answer says first whether it did what was asked. The maintainer, 2026-10-14: "I read the "stopped" as an error. These tools should return a pass/fail condition somewhere."
  5. Bounded output. 200 lines read, 50 matches, 100 lines of a test: a small model given 7,500 tokens missed most of them.
  6. A refusal steers. It names what was wrong and the tool or field that would work, so a weak model corrects itself (trunk); never a value with a hidden meaning, such as trunk's __all__, which matched nothing and sent a model round to its step cap.
  7. Test before saving, and trust the record over the model. What was run is what the log says, not what the model claims.
  8. Names a client can call. ChatGPT's client called ocx.status as ocx_status; MCP names are safest of letters, digits, _ and -.

Decided

The maintainer's answers, 2026-10-15, each as built:

  1. The names: "don't care, just be consistent." Every tool is ocx_ and its name over MCP; these are context, find, read, edit, test and save.
  2. Where a run's tests come from: "our workspace clone is what i'd expect." The project names them in its own checkout, ocx-tests.json, each a name and its command; no key is added to a run.
  3. The working branch: "make it unique like the runner name." agent/, the run's user, and eight hex digits from its checkout, as a run user's name has eight.
  4. ok and next: "what does the data show works best?" Every tool's answer begins with ok, and a refusal gives next_step (next is a word Crystal keeps). The battery measured no effect either way, so both stay (decision 68).
  5. Slowpen's other asks: "yes, include wiki and unversioned files (for binary file sharing). gain parity with trunk agent tools that justify themselves." wiki_read, wiki_edit (first wiki_write, a page whole against its version, until the battery showed models edit a page as a file), unversioned_list, unversioned_get and unversioned_put; trunk's other tools come when the battery shows a model needs one.