Opair

The coding harness that eschews autonomy

Tools

This guide is for Opair users. If you want to write or maintain a tool definition, see the tools reference instead.

What are tools?

Tools are everything the agent can actually do: read files, edit files, run go test, call MCP servers and so on. There is no tool that grants shell access and no way for the agent to run an arbitrary executable. Each tool is scoped to one restricted job.

Most tools are just JSON files on disk. If you can write a bit of JSON, you can give the agent a new tool. A handful are implemented in Go inside Opair itself, notably askQuestion and the sub-agent entry points like plan and reviewDiff.

Where tools live

Each tool is one JSON file in your Opair config directory:

The location can be overridden with OPAIR_TOOLS_DIR.

Edits to tool files take effect while Opair is open. New tool files need a restart before they can be called.

Which tools you get

Opair ships with a set of tools covering common file operations, git and GitHub, and popular language toolchains. Tools that run external commands are only offered when their binary exists in $PATH. Opair checks at startup. If Go isn't installed, the agent never sees goTest. Install the toolchain, then start a new session.

There's no availability configuration to maintain: if the binary is there, the tool is offered.

Which loops can call which tools is a separate matter, covered in Adding your own.

Approvals

Every tool declares what it reads and writes using a small set of categories (project files, gitignored files, build outputs and so on). The full list is in the reference.

Reads of project files and git history are auto-approved. Reads of dotfiles, gitignored files and paths outside the project prompt for approval.

Build outputs are auto-approved too. Writes inside the project prompt, with an option to auto-approve for the remainder of the session. Dotfiles and gitignored paths can't be session-approved, and neither can anything that mutates git state.

Tools that can execute third-party code, like npm and npx, always prompt, whatever their write category.

MCP tools always prompt as well, unless a loop grants the server. See the MCP guide.

The defaults can be overridden per loop in config.json. See the configuration doc.

Adding your own

Add a JSON file to your tools directory and it shows up alongside the shipped tools. For example, markdownlint.json:

{
  "internal": false,
  "schema": {
    "function": {
      "description": "Run `markdownlint` from the project root to lint markdown files. All markdownlint args are supported.",
      "name": "markdownlint",
      "parameters": {
        "properties": {
          "args": {
            "description": "Arguments for markdownlint.",
            "items": { "type": "string" },
            "type": "array"
          }
        },
        "required": [],
        "type": "object"
      },
      "strict": true
    },
    "type": "function"
  },
  "writes": "none",
  "handler": {
    "type": "exec",
    "bin": "markdownlint"
  }
}

The file name is the snake_case form of the tool's name: markdownlint lives in markdownlint.json.

Tools are also filtered per loop by each loop's toolWhitelist, so add the tool's name to the whitelists of the loops that should use it (e.g. driver in loops/driver.json). Then restart Opair and the tool is available to the agent.

Since writes is "none", the agent can run it without approval. A tool that writes anything needs an honest write category so that approvals work correctly.

A file that fails validation stops Opair starting. That's deliberate: a typo shouldn't silently drop a tool.

The reference documents every field.

Customising shipped tools

Upgrades overwrite the shipped tools with the canonical set from the release. If you've edited shipped tools, your changes will be lost.

To keep your own set, copy the tools directory somewhere else, edit freely and point OPAIR_TOOLS_DIR at it.