An open-source coding agent, written to be read
A coding agent you can read in an afternoon.
Tau is a small, working coding agent in Python. It talks to a model, reads and edits your files, and runs shell commands from your terminal — with no framework hiding how any of it works.
Use it as a tool. Read it as a textbook. Fork it as a starting point.
An agent is a loop
Definition 1.1A coding agent is a language model run in a loop, where each reply may ask for a tool — read a file, edit it, run a command — and each tool result is fed back as the next input. The loop stops when the model answers without asking for anything.
That's the whole idea. Everything else in Tau — sessions, skills, the terminal UI — is built around this loop, not inside it.
Three layers, nested
Tau is three Python packages, nested like boxes. Each one controls its own job and only uses what's inside it — so you can learn, or replace, them one at a time.
Everything is an event
The agent doesn't print, draw, or save anything itself. Each layer emits small, typed events, and the layer above turns them into its own. Whoever listens at the top — a one-shot CLI, the terminal UI, your own frontend, or a JSONL session file — decides what to do with them.
A tool is just a function
Where do tool calls come from? A tool is half schema — a name, a description, and parameters the model can read — and half plain async function. This is a complete Tau extension, from examples/extensions/hello_tool.py:
from tau_agent.messages import TextContent
from tau_agent.tools import AgentTool, AgentToolResult
async def _run_hello(tool_call_id, arguments,
signal=None, on_update=None):
who = str(arguments.get("who", "world"))
return AgentToolResult(
content=[TextContent(text=f"Hello, {who}!")])
def setup(tau):
tau.register_tool(AgentTool(
name="hello",
label="hello",
description="Greet someone by name.",
parameters={
"type": "object",
"properties": {"who": {"type": "string"}},
},
execute_fn=_run_hello,
))A frontend in a dozen lines
The terminal UI is one listener among many. Anything that can loop over the session's events is a frontend — here is one that prints to stdout, using the real event names from §3.
async for event in session.prompt(text):
match event.type:
case "message_update":
e = event.assistant_message_event
if e.type == "text_delta":
print(e.delta, end="")
case "tool_execution_start":
print(f"\n→ {event.tool_name}({event.args})")
case "tool_execution_end":
print(" ✗" if event.is_error else " ✓")
case "agent_settled":
breakmatch on event typesA syllabus
Seven files, read in order, take you from a single event to a working coding agent. Line counts are from the current source.
| § | Lesson | File | Lines |
|---|---|---|---|
| 1 | Events, the contract | tau_agent/events.py | 87 |
| 2 | Models become events | tau_ai/_provider_events.py | 93 |
| 3 | What a tool is | tau_agent/tools.py | 118 |
| 4 | The loop | tau_agent/loop.py | 376 |
| 5 | The harness | tau_agent/harness.py | 259 |
| 6 | Sessions on disk | tau_agent/session/jsonl.py | 171 |
| 7 | Real tools | tau_coding/tools.py | 1,218 |
Pi, and why τ
Tau began as a way to understand Pi, a small coding agent written in TypeScript. Pi keeps three things apart: the loop, the machine it works on, and the screen you watch it on. Tau keeps that split and rebuilds it in Python, with notes on every step.
The name is a joke that stuck. π is half a turn; τ = 2π is the whole circle. Pi was the first half of the trip — Tau tries to go the rest of the way round, slowly, and show its work. More on τ than you asked for →
Start with events, add a loop, give it tools, wrap it in a UI. That's a coding agent.