rig without its terminal view: a script or another agent drives it over
its stdin and stdout. Logs go to stderr.

One task:
  rig -p "task"           Answers the task and exits; stdout gets only the
                          final answer, stderr its progress. Text piped in
                          follows the task: give stdin /dev/null otherwise
                          (an open stdin that stays silent costs a second).
  rig -p --json "task"    The same run as JSON lines (below); its last line
                          is {"v":1,"type":"exit","ms":…,"code":0,
                          "answer":"…","error":null,"session":"…",
                          "usage":{…}}.
  Exit codes: 0 answered, 1 failed, 2 no task or a refused /command.
  A failed turn hands its unanswered task back: stderr says "rig: not
  answered: <task>" (with --json, a recalled event), and the session no
  longer holds it.
  Runs side by side in one directory see each other's edits: give each
  its own files, or its own directory (such as a git worktree).
  Nobody answers its questions: they are refused unless --answer=ID[,ID…]
  gives the choices to take, such as --answer=allow.

A conversation:
  rig --json              Reads one request per line on stdin and writes
                          events on stdout. Closing stdin ends rig at once.

Both take --model vendor/model, --tools read,shell (only those tools) and
-r <session id or name> (go on with a session; the id is in the `ready`
line). rig works in its current directory. RIG_HOME (default ~/.rig)
holds its builds, settings and sessions. The first start builds the agent,
which takes minutes, and a start waits for another rig's build; stderr
says so meanwhile.

Every line, both ways, is a JSON object with "v":1. A line of another
version is refused with a reply saying whether rig or the driver needs
updating. Every event has "ms", when it was written (Unix milliseconds).

Requests, each with an optional "id" its reply repeats, and "agent" (an
agent's id; the main agent without one):
  {"v":1,"type":"send","text":"Fix the tests."}   a message: it starts a
        turn, or joins the running one at its next model call
  {"v":1,"type":"stop"}                           stop the turn
  {"v":1,"type":"answer","ask":7,"choices":["allow"]}   answer a question;
        "text":"…" answers one whose "text" is true
  {"v":1,"type":"state"}      the agents (working or not, model) and the
        open questions, in the reply's "state"

Events, each with "agent" when it is an agent's:
  ready {session}                      the first line
  turn_start
  text {text}                          the reply as it streams
  tool_call {id, name, args}
  tool_result {id, name, ok, refused, output}   refused: refused before
        it ran, such as a tool the agent may not use
  ask {ask, title, body, choices: [{id, label}], text, multiple}
        an approval (choices deny and allow) or a question, waiting
  turn_end {outcome, answer, error, usage, first_token_ms}   answered
        with its final answer, or failed or stopped with why; usage has
        the turn's tokens, calls, and cost in USD, which leaves out the
        "unpriced" calls, such as a subscription model's; first_token_ms
        is when a reply first streamed
  notice {level, text}                 info, warn or error; what is
        written at once puts its notices before the text streamed with it
  recalled {text, why}                 messages the agent did not answer
        or send, taken out of the session: a failed turn's, which go
        again only if sent again, or a refused /command, with why
  reply {id, ok, error, state}         one per request
  exit {code, answer, error, session, usage}   the last line of
        `rig -p --json`, after which nothing is written, not even a
        notice of the same frame; error says why for any code but 0;
        usage counts this session's own model calls, not its helpers'

A turn's final answer is its turn_end "answer". A message sent mid-turn
joins that turn, so one turn_end answers both.

In Python:

  import json, subprocess
  rig = subprocess.Popen(["rig", "--json"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
  def send(**request):
      rig.stdin.write(json.dumps({"v": 1, **request}) + "\n"); rig.stdin.flush()
  send(type="send", text="Which file here is the largest?")
  for event in map(json.loads, rig.stdout):
      if event["type"] == "ask":
          send(type="answer", ask=event["ask"], choices=["allow"])
      if event["type"] == "turn_end":
          print(event["answer"] or event["error"]); break
  rig.stdin.close(); rig.wait()

A session is kept in RIG_HOME/sessions/<id>/: logs/<agent>.jsonl, one JSON
record per line (the conversation's messages as "push" records, each
turn as an "aside" of kind "rig.turn", with "end" once it ended), and
agent.log, the agent's own log.
