RPC protocol

Control Tau as a subprocess with Pi-compatible JSONL commands and events.

Run Tau as a headless subprocess:

tau --mode rpc [--provider NAME] [--model MODEL] [--cwd PATH] [--session ID]

RPC mode reads one JSON object per LF-terminated line from stdin and writes responses and session events as compact JSON lines to stdout. Diagnostics use stderr. Clients may include an id; the corresponding response echoes it. Event records are asynchronous and do not normally carry request IDs.

{"id":"1","type":"prompt","message":"Inspect this project"}
{"id":"1","type":"response","command":"prompt","success":true}
{"type":"agent_start"}

The protocol supports Pi-compatible prompting (prompt, steer, follow_up, abort), state and message inspection, complete Pi-shaped model references, model and thinking cycling, auto-compaction control, direct shell commands, HTML export, new/resumed sessions, entry cursors, session statistics and trees, forking, last-assistant lookup, session naming, and command discovery. Unknown commands and invalid arguments return success: false without stopping the process.

Use agent_settled, not agent_end, to decide that a run is fully idle: retries, overflow compaction, or queued continuations can follow agent_end.

Framing

Split records only on LF (\n). A trailing CR is accepted for CRLF input. Unicode line separators such as U+2028 and U+2029 are ordinary characters inside JSON strings. Records are limited to 16 MiB.

Minimal Node/Electron client

import { spawn } from "node:child_process";

const tau = spawn("tau", ["--mode", "rpc"], { stdio: ["pipe", "pipe", "inherit"] });
tau.stdout.setEncoding("utf8");
let buffer = "";
tau.stdout.on("data", chunk => {
  buffer += chunk;
  for (;;) {
    const index = buffer.indexOf("\n");
    if (index < 0) break;
    const line = buffer.slice(0, index);
    buffer = buffer.slice(index + 1);
    console.log(JSON.parse(line));
  }
});
tau.stdin.write(JSON.stringify({ id: "1", type: "prompt", message: "Hello" }) + "\n");

RPC compaction preserves recent entries and returns the first pre-existing retained entry as firstKeptEntryId, matching Pi. Older Tau compaction records and TUI compactions that replaced all active context have no such boundary; session inspection exposes those honestly as customType: "tau.compaction" entries instead of fabricating Pi compaction metadata.

Tau mirrors Pi where its public CodingSession has equivalent behavior. Direct bash is supported, but abort_bash requires a future cancellable session API. Queue delivery modes, retry controls, cloning, image prompts, and the extension UI request/response subprotocol remain staged compatibility work. See dev-notes/design/rpc-runtime-interchangeability-plan.md for the contract, completed frontend-critical phase, and remaining production phases.