A Go-native AI coding agent — single binary, composable, and importable as a library.
tau is a coding agent built from scratch in Go. It ships as one static binary with a full-screen terminal UI, a headless print mode for scripting and CI, and a line-based REPL. Its core — the LLM client and the agent loop — is designed as clean, consumer-first Go packages you can import into your own projects.
tau is under active development; APIs and behavior may change.
- Single static binary. No runtime, no node_modules —
go buildand run. - Three ways to run: full-screen TUI (default), headless
-pprint mode, and a--repl. - Provider-agnostic. Talks the Anthropic-messages and OpenAI-completions/responses wire protocols; auto-detects the provider from whichever API key is in your environment (Anthropic, OpenAI, DeepSeek, Gemini, Groq, xAI, OpenRouter, Mistral, and more).
- Built-in tools:
bash,read,write,edit,ls,find,grep— typed and composable, with output truncation and diff rendering. - Skills & sessions. Loads project-local and user-global skills; persists sessions and can resume them.
- Custom inline renderer. A from-scratch differential terminal renderer (
internal/render) drives the TUI: it diffs whole frames and emits minimal ANSI (relative cursor moves, synchronized output, overlay compositing), staying inline so your scrollback is preserved. - Importable core.
pkg/llm(model requests/streaming) andpkg/agent(the tool loop) are public, dependency-light Go packages.
Requires Go 1.25+.
git clone https://github.com/lucasdevco/tau
cd tau
go build -o tau ./cmdThis produces a tau binary in the repo root. Move it onto your PATH to use it anywhere.
Set an API key for any supported provider and run:
export ANTHROPIC_API_KEY=sk-... # or OPENAI_API_KEY, DEEPSEEK_API_KEY, ...
# Full-screen interactive TUI (default when no prompt is given)
tau
# Headless: run one agent loop and exit
tau -p "fix the failing test in ./parser"
tau "explain what cmd/main.go does" # positional prompt also works
# Pipe a prompt in
git diff | tau -p "review this change"
# Line-based REPL instead of the TUI
tau --repl
# Machine-readable output (one JSON event per line)
tau -p "list the exported functions in pkg/agent" --json| Flag | Description |
|---|---|
-p, -print |
Prompt to run in headless print mode |
-model |
Model id (e.g. claude-sonnet-4-6, deepseek-v4-flash) |
-provider / -api / -base-url / -api-key |
Provider and endpoint overrides |
-thinking |
Thinking level: off, minimal, low, medium, high, xhigh |
-repl |
Use the line-based REPL instead of the TUI |
-resume |
Resume an existing session file by path |
-no-session |
Do not persist the session |
-cwd |
Working directory (default: current directory) |
-system-prompt / -append-system-prompt |
Replace or extend the system prompt |
-json |
Emit one JSON event per line to stdout |
-version |
Print version and exit |
Run tau -h for the full list.
- Model & provider resolve from flags first, then from environment. With no
-model, tau auto-selects a default from whichever provider API key is present (falling back todeepseek-v4-flash). - API keys are read from the standard per-provider environment variables
(
ANTHROPIC_API_KEY,OPENAI_API_KEY,DEEPSEEK_API_KEY,GEMINI_API_KEY, …) or overridden with-api-key/TAU_API_KEY. - Skills are loaded from
.tau/skillsand.agents/skillsin the project, plus the user-global skills directory. - Paths can be overridden with
TAU_DIR,TAU_CONFIG,TAU_SESSIONS_DIR, andTAU_LOG_FILE.
The core is two small packages: pkg/llm (one model request, response, and stream) and
pkg/agent (the agent: tool loop, steering, compaction, persistence).
package main
import (
"context"
"fmt"
"os"
"github.com/lucasdevco/tau/pkg/agent"
"github.com/lucasdevco/tau/pkg/llm/providers/anthropic"
)
func main() {
client := anthropic.New(os.Getenv("ANTHROPIC_API_KEY"))
ag := agent.New(client, "claude-sonnet-4-6")
res, err := ag.Run(context.Background(), "Summarize what this repo does.")
if err != nil {
panic(err)
}
fmt.Println(res.Text)
}Stream a turn token by token:
conv := ag.NewConversation()
for chunk := range conv.Send(ctx, "Explain main.go").Text() {
fmt.Print(chunk)
}Give the model a typed tool:
import "github.com/lucasdevco/tau/pkg/llm"
weather := llm.NewTool("get_weather", "Get the weather for a city",
func(ctx context.Context, in struct {
City string `json:"city"`
}) (string, error) {
return "sunny in " + in.City, nil
})Dependencies flow strictly downward.
cmd → internal/app/{print,repl,tui} → internal/app/runner → pkg/agent → pkg/llm
├──→ internal/tools (→ pkg/llm)
└──→ internal/{config,model,skills,sysprompt}
pkg/agent → pkg/llm
pkg/llm/providers/{anthropic,openai,faux} → pkg/llm/transport → pkg/llm
internal/render — inline differential terminal renderer (drives the TUI)
pkg/llm— one model request/response/stream;Clientis a single-method interface (Stream),Generateis the convenience wrapper. Knows nothing about agents or UI.pkg/agent—Agent(immutable definition) /Conversation(stateful) /Run(one-turn handle); the tool loop, steering, compaction, and pluggable persistence.internal/app/{print,repl,tui}— the three front ends, all drivingrunner.Runtime.internal/render— the from-scratch differential renderer used by the TUI.
See AGENTS.md for the design principles (also injected into tau's own system prompt).
go build -o ./tmp/tau ./cmd # build
go test -race ./... # test (offline tests use a faux provider)
go vet ./...- Offline, deterministic tests use the
fauxprovider; live smoke tests are gated behind provider API-key environment variables and skip when unset. - The
grep/findtools rely onrg/fdbeing onPATH.
See CONTRIBUTING.md for the contribution workflow and AGENTS.md for project rules and Go design principles.
MIT. See LICENSE.