Skip to main content
Your agent already has a shell, a browser, a search engine, an email address and a phone number. This section says what each of those does, how to add more, and where the credentials for the ones that need an account are kept. A tool is a Python function. The agent calls it by writing code:
Two tools, one round trip. Written as separate JSON tool calls that is four messages through the model, each carrying the previous result back through the context window. Why the platform prefers code is worth reading once; the rest of this section assumes it.

The three ways a tool arrives

A platform package

system:compute, system:search, system:media and the rest. The platform runs them, credentials them and bills them. Nothing to install.

An MCP server you connect

Something from the catalog, or your own server by URL. It gets a uuid, and that uuid is what an agent names.

A file in your harness

tools/notes.py in your own repository. One file, one docstring, no publish step to see it change. See writing your own.
All three end up as functions the agent calls, but they do not arrive by the same road, and knowing which is which saves an afternoon. A platform package is projected onto the machine as Python. One directory per source, one file per tool:
Each file is a plain function with type hints and a docstring, so the agent reads the signature before the first call instead of guessing at it. catalog.json is the platform’s record of the same thing — the packages, the names inside them, the keys of the environment secrets and the models the machine may name:
A file of your own lives in the harness checkout at ~/harness/tools/, and a long-lived process in the sandbox imports it and answers the calls. Its tools are offered to the model by name — telegram.py with a notify in it is the tool telegram__notify. An MCP server has no file anywhere. The platform holds the connection, calls the server over the wire and attaches your credential on the way out; its tools are offered to the model by their own slugs.

How a tool is chosen for a turn

Three decisions, in this order. The agent’s declaration decides which sources exist for it at all. Each entry in tools=[…] names a platform source, a file of your tools/ tree, or the uuid of a server you connected:
That is the real declaration from the starter harness, and it names one source. Everything else that agent uses — search, media, email — it reaches by importing from ~/tools/ and running the code with compute_exec. An MCP server is the exception: it has to be named in tools, because there is nothing on the machine to import. A # narrows an entry to particular tools: "system:compute#compute_read_file,compute_grep" is those two and nothing else. The full rules are in Tools. The account decides which platform packages exist for every agent on it. The Tools screen lists them under System tools, each marked Available in every run with a Turn off beside it:
The System tools tab of the Splox Tools screen

System tools: the platform packages this account gives its agents

hooks/tools.py decides what a particular call may do. It sees the call by name with its arguments before it runs, and can deny it with a sentence the model reads:
A refusal is not a dead run: it comes back to the model as the reason, so it can choose something else. See Hooks.

The packages

system:compute is the odd member of the set: it is the runner every other tool executes through, which is why your own tools import it rather than the agent calling it for them.

Where to go next

The MCP catalog

The servers you can add to your account, and what shows up afterwards.

Connections

OAuth, tokens and headers: where a credential is kept and how to revoke it.

Driving a browser

Which job belongs on the desktop, which belongs in the CLI, and what a captcha means.

Writing your own

One file, one docstring, and the agent has a new tool on the next call.