Runi Help

Any other agent

Brief, remember and observe any agent Runi does not support natively.

Six agents have a native adapter. Everything else, a harness you wrote, a tool Runi has never heard of, a CI job, uses one or both of the two generic channels: a standalone CLI, and the MCP server.

Which channel to use#

Your agentUse
Speaks MCP The MCP server. Six tools, results straight into the conversation, no copying. Register it manually with your client, pointing at ~/.relay/daemon/mcp-server.js.
Does not speak MCP, but you control the prompt relay-cli brief. Print the packet and have the harness prepend it to the first prompt.
You just want its file changes observed relay-cli wrap. Run the command through it.

The CLI#

It lives beside the daemon, at ~/.relay/daemon/relay-cli.js. Three subcommands, all of which go through the same redaction and outbound gate as a hook publication. There is no second, weaker path here.

brief: print what a session should know#

terminal
$ node ~/.relay/daemon/relay-cli.js brief
$ node ~/.relay/daemon/relay-cli.js brief --task tsk_9f2c

This is the same packet the hooks inject and the MCP server serves, rendered by the same function. It goes to stdout, so it pipes.

remember: file a memory for review#

terminal
$ node ~/.relay/daemon/relay-cli.js remember \
    --kind decision \
    --title "Retry the rollout parser rather than re-reading the file" \
    --body "Re-reading raced the writer on Windows and produced half-written JSON." \
    --reason "The writer is not atomic, so a read can land mid-write."

What comes back is proposed, in your name. It reaches nobody's brief until you confirm it in the app, because an agent can be talked into filing a memory by a page it read. A decision without a --reason is refused outright.

wrap: observe a command Runi knows nothing about#

terminal
$ node ~/.relay/daemon/relay-cli.js wrap -- my-agent --do-the-thing

It snapshots git status before and after, runs your command with stdio inherited so it behaves normally, and publishes one change event naming the files that moved. File contents never leave the machine. The detail carries a diff stat, not the diff.

Exit codes#

The hooks exit 0 on every failure, because a broken network must never break your agent. The CLI is user-invoked, so it fails loudly.

ExitMeans
0The answer is on stdout.
1There is no answer, and the reason is on stderr: not signed in, repository untracked, or publication refused.

An exit code a harness can branch on, and a sentence a person can act on. The two you will meet:

stderr
runi: Runi is not signed in on this machine. Connect an agent from
      the Runi app, or run `node ~/.relay/daemon/login.js`.

runi: This repository is not registered to the Runi workspace.
      Add it under Settings → Repository access in the Runi app.

Testing the MCP server without a client#

Two JSON-RPC lines on stdin tell you whether the server is alive and what it offers:

terminal
$ printf '%s\n' \
    '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}' \
    '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
    | node ~/.relay/daemon/mcp-server.js

Known limits of the generic path#

  • Observation covers only what changes on disk during a wrapped command. Prompts, replies and test output are not seen, because there is no session protocol to read them from.
  • Briefings are pulled, not pushed. Nothing tells your agent that a teammate started editing mid-run. That requires a session-start hook, which is what an adapter is.
  • Only repositories your workspace tracks are published. Anything else is refused with the reason printed.

Tip

Using an agent you would like a real adapter for? Tell us which one. Adapters are written against the agent's own shipped code rather than its documentation, so knowing which ones people run decides what gets built next.

Did this solve it?