→ trau --help
Documentation
Everything you need to install, serve, and run the herd — the hub, remote access, the engine, configuration, and the full CLI reference.
Getting started
trau is a single static Go binary that ships two surfaces: the hub — a machine-local web app started by trau serve — and the terminal TUI. Same engine, same queue underneath: cold, isolated agents drive each ticket build → verify → PR → merge.
Before your first run, make sure these are on your PATH and authenticated:
- git — the repo you point trau at must be a git checkout.
- gh — the source host CLI, authenticated (gh auth login). trau opens and merges PRs through it on source host. For Bitbucket Cloud, set BITBUCKET_EMAIL and BITBUCKET_API_TOKEN instead and trau talks to the API directly.
- An agent CLI on your PATH: claude, codex, kimi, or auggie. Auggie ships on npm and needs Node 20+ (npm install -g @augmentcode/auggie, then auggie login); Augment publishes no native Windows build, so on Windows run it inside WSL2.
- An issue tracker — Linear, Jira, Azure DevOps Boards, or source host Issues, over MCP or a direct API token — or none at all: trau's internal issue store runs tickets on repos with no external tracker.
# macOS / Linux / WSL2 — no license key needed; the free trial starts in the hub.
# It installs to $HOME/.local/bin without sudo; TRAU_INSTALL_DIR=<absolute dir> picks another directory:
curl -fsSL https://get.trau.sh/install.sh | sh
trau --version
# Already hold a license key? Pass it and the installer stores it:
curl -fsSL https://get.trau.sh/install.sh | TRAU_LICENSE_KEY=<your-key> sh
# Later: update in place from the terminal, or Settings → Updates in the hub:
trau update # trau update --check only reports what is available
# Store a key by hand — after a manual install, or when it changes:
trau license set <your-key>
# Linux / WSL2 packages — .deb and .rpm (amd64 and arm64):
V=$(curl -fsS "https://get.trau.sh/v1/latest" | sed -n 's/.*"version": *"\([^"]*\)".*/\1/p')
curl -fsSL -o trau.deb "https://dl.trau.sh/v1/download/$V/trau_${V}_linux_amd64.deb"
sudo dpkg -i trau.deb # Debian, Ubuntu — .rpm + rpm -i on Fedora, RHEL, openSUSE# swap amd64 for arm64 on an ARM machine — no license key needed
$v = (Invoke-RestMethod "https://get.trau.sh/v1/latest").version
Invoke-WebRequest "https://dl.trau.sh/v1/download/$v/trau_${v}_windows_amd64.zip" -OutFile trau.zip
Expand-Archive trau.zip -DestinationPath "$env:LOCALAPPDATA\trau" -Force
# put it on your PATH (new shell afterwards)
[Environment]::SetEnvironmentVariable("Path", "$env:LOCALAPPDATA\trau;" + [Environment]::GetEnvironmentVariable("Path", "User"), "User")
trau --version
# optional: already hold a license key? store it
trau license set <your-key>
# from then on, trau update or the hub’s Update to X swaps trau.exe for youOr build from source (Go 1.27+):
git clone https://github.com/RomkaLTU/trau && cd trau make build # produces bin/trau
First run, hub path (recommended): start the hub and open it in a browser. With no license yet, the hub opens on a lock card: enter your email and the 6-digit code we mail you, and the 14-day trial starts (see Trial and license). The New project wizard takes a repo from a path to a live backlog — point it at the checkout, let it inspect the repo, wire the tracker (or pick internal issues), confirm the essentials, and seed the board with a first sync.
trau hub start # runs the hub as a service # then open http://127.0.0.1:8728 # trau serve runs the hub in the foreground instead — # it stops when you close the terminal
First run, terminal path: cd into a repo that has no project config layer and run trau with no arguments. The TUI onboarding wizard walks you through tracker, branch, and provider, writes the project and user config layers to the Hub database — and brings the hub up first, before it even resolves the repo.
cd ~/code/your-app trau
Either way, trau doctor is the preflight: it probes git, gh, the provider CLI, config sanity, tracker labels, write permissions, and whether the hub is reachable and running the same version as the binary — exiting non-zero on any failure.
The hub is not optional scenery: starting trau brings it up and waits for it to answer healthy before the session continues. If it cannot start, trau says so and points at the hub log rather than running blind. The TUI header carries the hub’s status, W opens it in a browser, and --no-serve skips the autostart for one session.
Trial and license
trau installs with no license key. The first time you open the hub without one, it shows a lock card: enter your email, type the 6-digit code we mail you, and a 14-day trial starts — every feature, no card. There is one trial per email and one per install.
To keep going, subscribe from inside the hub. It opens a Stripe checkout page; once the payment goes through, the license upgrades itself and a mail brings you the license key. There is one plan, Trau Solo, billed monthly or annually — prices are on trau.sh/#pricing and in the app.
- Two installs per license. To move trau to another machine, release the one you no longer use from the hub, then start trau on the new one.
- Manage subscription in the hub opens the Stripe customer portal: cancel, change the card, or download invoices.
- A paid license keeps working for 7 days without a connection, so a flight or a flaky network does not stop the loop.
- Already hold a key? Pass TRAU_LICENSE_KEY=<your-key> to the installer, or store it on an existing install with trau license set <your-key>. A perpetual key keeps working as it always has.
When the trial ends, a payment fails or the subscription ends, trau locks:
when trau locks
- Finishes
- Runs already in progress run to the end.
- Stays open
- The hub, read-only: you can still open it and read everything in it.
- Refused
- Anything new. No run starts, from the hub or from the CLI.
- Unlocks
- Subscribe from the hub; the license updates itself once the payment goes through.
Cancel at any time from Manage subscription in the hub. Refunds and the EU right of withdrawal are on trau.sh/refunds.
The hub
trau hub start runs the hub as a service: a machine-local web app — embedded in the same binary — that fronts the engine. Registered repos, run history, and internal issues live in a durable local database, so history survives restarts. One hub per machine; every screen is scoped to one active repo, or to All projects. (trau serve runs the same hub in the foreground, tied to your terminal.)
operate
- Overview
- The board: what trau is doing and what needs you. A pulse strip, launch actions, and per-repo cards with queue depth, running ticket, needs-attention items, and spend today — scope-aware, one repo or all.
- Loop
- One ordered queue per repo. Run next promotes a ticket to the front of the drain; Run now starts it immediately in a free lane. Every running lane shows live with a lane counter, and when nothing new is spawning a banner names why. Reorder, skip, batch, or override provider/model for a single launch — each ticket keeps a Loop timeline of what happened when.
- Backlog
- The ticket board: epic → sub-issue nesting, an Archive, read-only assignee filters (Me / Unassigned), in-queue indicators, an openable "Done today" strip, and add-to-queue from any row. Internal issues are authored here on repos with no tracker.
- Inbox
- Where raw ideas become ready tickets. The Interview asks one question at a time until the ticket is buildable; Ask ahead batches remaining questions, Start over resets, Drafts hold work in progress. Provider and model switch per conversation, and one or two challenger providers can draft second opinions from the finished transcript for a side-by-side review.
- Research
- Start, watch, and read research sessions. A finished report turns into a seeded ticket with one click — Draft an issue — and the issue stays anchored back to the report.
observe
- Runs
- The Run ledger — every tracked run, bucketed active / needs you / awaiting QA / stopped / merged, with an author filter once teammates share runs. Run detail shows per-phase cost, the verify verdict, browser-verify proofs, the handoff brief, and the run’s worktree with app start/stop controls and a log tail, plus Resume / Reset / Clear actions.
- Terminal
- Live PTY transcripts of the agent at work, streamed to the browser — the web counterpart of the TUI’s w key — with a worktree selector and the phase list for the ticket you picked.
- Atlas
- Agent-generated architecture Views per repo (Data model, App flows). Each View is generated at a stamped commit, flags itself stale as the repo moves, and regenerates on demand.
- Costs
- Daily / per-repo / per-phase spend rollups with anomaly flags, off the same normalized ledger the CLI prints.
- Lessons
- Browse the durable lessons memory that failed runs feed.
configure
- New project
- The onboarding wizard: point it at a checkout, let it inspect the repo, wire the tracker (or pick internal issues), confirm the essentials, and seed the board with a first sync.
- Skills
- What the repo has installed, when each skill activates, and what runs actually loaded — plus installs from the skills.sh registry and a ui.sh manager for the skills your ui.sh account owns (UIDOTSH_TOKEN; installs land in user scope under ~/.claude/skills, no repo touched).
- Settings
- The layered config, catalog-driven: every section shows which layer a value comes from and writes to an explicit target (repo or home). The editable prompt catalog and per-repo overrides live here too.
- Hub
- The running hub itself: update state and restart-pending handling, Web Push delivery, and External agents — copy-paste MCP setup for Claude Code, Codex, or Cursor.
The whole UI is keyboard-first. ⌘K (Ctrl-K on Linux) opens the command palette from anywhere: switch projects, jump to any page, return to somewhere you were recently, or hop straight into a run that is currently active. ⌘P switches projects, ? opens the shortcuts sheet, g then a letter jumps straight to a page, and j/k or the arrow keys walk rows on Backlog, Loop, Inbox, and the runs ledger — with per-page keys for expanding, archiving, reordering the queue, and starting runs.
The hub is installable. It ships a web manifest and a service worker, so it can live on a phone home screen or a dock like a native app, and it falls back to a branded offline shell that retries on its own when the machine is unreachable. Opt into Web Push (on the Hub page) and the needs-attention set reaches you with a deep link to the run or ticket that wants you; come back later and an away recap summarises what happened while you were gone.
The hub also speaks MCP at /api/v1/mcp, so an agent you already run — Claude Code, Codex, Cursor — can file tickets, arm the queue, read the backlog and live runs, and steer a running agent without opening the web UI. Hub → External agents has the copy-paste setup for each client with the endpoint already resolved, under the same auth posture as the rest of the API: loopback is open, any other bind needs SERVE_TOKEN.
Sync is inbound-authoritative: trau reads tickets from your tracker and writes back statuses and comments. Two things also travel outbound, and only ever on your gesture — assigning a ticket from the board, which writes to the tracker first and mirrors locally only on success, and QUEUED_LABEL, which mirrors the hub queue onto the tracker so planned work is visible there. No phase writes either one, and the next inbound sync always wins.
Remote access
The hub binds to 127.0.0.1 by default and is open on loopback — it is yours, on your machine. Everything beyond loopback is opt-in and gated.
exposure policy
- SERVE_TOKEN
- Bearer token required on any non-loopback bind. trau serve refuses to start on an exposed address without it.
- SERVE_ALLOW_REGISTER
- Set to 1 to allow registering/unregistering repos over an exposed bind. Off by default — remote clients can watch but not rewire.
- SERVE_REMOTE
- How the hub is reachable off this machine: off (loopback only) | tailscale (published on the tailnet’s HTTPS port, so only devices signed in to your tailnet can reach it). trau hub remote on|off writes this key, and every hub start reconciles the forward against it — a reboot, a supervised restart or a changed SERVE_PORT comes back reachable with no manual step. Tailscale missing or logged out is a startup warning, never a failure to serve locally. Default off.
Want the hub on your phone while the loop runs on your desktop? Tailscale is the blessed path — a private tailnet, not a public port. trau hub remote on publishes the running hub and prints its tailnet URL with a QR code to scan; status reports what is published, off takes it down again, and --take moves a forward that is already pointing elsewhere. SERVE_REMOTE=tailscale makes it the standing arrangement rather than a per-start command — every hub start reconciles the forward, so a reboot or a changed SERVE_PORT comes back reachable on its own. Settings → Remote access shows the same URL, a copy button and the QR, offers to publish this hub here when a live forward points somewhere else, and says plainly when the tailnet is down or signed out.
What you reach on the phone is laid out for it. Below the tablet breakpoint the hub switches to a mobile shell with a bottom nav, and every route — overview, the loop, the runs ledger and run detail, the live run view, inbox triage and interviews, backlog and settings — was designed at that width rather than left to reflow. Dialogs, drop-downs, the command palette and the terminal stay inside the viewport, wide tables and diffs scroll in their own frame, and anything that used to appear only on hover has a tap that reaches it.
Reaching the hub from another device changes what some links can do: a worktree app served on a localhost port or a Herd .test site only answers on the hub machine, so those URLs are drawn as host-only markers that explain themselves instead of links into nothing. State-changing API routes additionally require a same-origin request, so a page on another site cannot aim a drain or a restart at your hub.
One hub per machine, machine-local by design: there are no accounts, no teams, and no cloud sync.
The loop
trau processes one ticket per iteration through three steps — Build, Verify, Ship — each made of activities. Every activity starts a brand-new agent process that inherits only a durable handoff brief and the code on disk — no --continue, no --resume. The build agent’s reasoning, and its blind spots, never carry forward.
BUILD build → handoff ‖ lintfix → cleanup VERIFY test gate → verify (fresh eyes) → repair/bugfix on fail → re-verify SHIP commit → PR → CI → QA hold (if armed) → merge
- Build — writes the code against the ticket, its acceptance criteria, and its non-goals, then distills a handoff brief while the style chain — lint autofixers, then an AI-slop strip — runs alongside it.
- Verify — a deterministic test gate first (a failing suite supplies the verdict without spending an agent), then a fresh, skeptical agent that sees only the brief and the diff. It grades the work, runs the repo’s verify-check library, drives the app in a browser on UI slices, and can convene a cross-vendor panel.
- Ship — stages the verified diff with a clean message, opens the PR, waits for your existing CI checks to land green, holds for your approval when the QA gate is armed, then merges and picks the next ticket. Epic branches sync with main continuously and auto-merge once their children land (AUTO_MERGE-gated).
Self-heal: a failed verify spawns a bounded REPAIR pass (MAX_REPAIRS), then a heavier BUGFIX pass (MAX_BUGFIXES), re-verifying each time. Still failing, the ticket is quarantined and the loop moves on. Re-running the same command resumes from the next unfinished phase via the durable per-ticket checkpoint.
When a run stops, the reason has a class. Paused (blameless) — a provider rate-limit or outage; nobody’s fault, resume when the window resets. Faulted — a transient step failure that exhausted its retries and fallbacks; work-in-progress stays on the branch. Quarantined — verify gave a verdict and the repair budget ran out; the ticket gets the QUARANTINE_LABEL and waits for a human. Draining a queue produces a drain report on pause or fault, and the on-fault skip policy decides whether the queue moves on or holds. A run can also park on purpose — awaiting-pick holds mid-build for a design choice (see Design picks), and awaiting-qa holds a finished run for your approval before merge (QA_GATE=1). Those are holds, not failures: the lane frees at once and the work stays healthy.
Taking the wheel: when a run goes sideways and you would rather steer the agent yourself than let it retry, trau hands you its actual session. Each claude phase records its session id into the ticket checkpoint, so the session outlives the process that minted it. Open in terminal on the hub’s run view — or trau takeover <ID> from a shell — stops the run, waits until the loop has genuinely let go of the working tree, and only then resumes that session in your terminal. Two writers on one checkout is the failure mode the wait exists to prevent.
The takeover holds the repo for as long as your terminal lives, and hand-back is manual: closing it resumes nothing. The ticket stays parked and re-enters the loop only when you queue it again with Run next.
quality passes
- LINT_FIX
- Run the project’s lint/format autofixers before verify. Default 1.
- LINT_FIX_CMD
- Deterministic lint-fix command (e.g. vendor/bin/pint, npm run lint:fix). Empty = a cheap agent auto-detects and runs the project’s fixers.
- CLEANUP
- Strip AI-slop from the slice’s diff before verify. Default 1.
- TEST_EFFORT
- How much effort the build, repair, and bugfix agents spend writing tests: off, low (default — only the core happy path of the changed behavior), medium, or high. Browser end-to-end verification is unaffected.
Parallel lanes (worktrees)
With WORKTREES=1, trau stops working one ticket at a time. Every run is provisioned its own git worktree — its own checkout, its own branch, and (with an app command) its own running app — created under WORKTREES_DIR as <dir>/<repo>/<ticket> and removed when the ticket settles. Your registered checkout stays yours: a dirty working copy never blocks a run and never gets stashed.
Every eligible queued ticket then drains at once, one spawn per tick — there is no lane cap, so the ceiling is your provider quota, CPU and disk rather than a number you set, and any shared dev database or port stays WORKTREE_SETUP_CMD’s to separate. An epic takes a single lane and its children share the epic’s tree, so a release never interleaves with itself. The Loop screen shows every lane live, including a starting lane while a tree is still being provisioned and which stage it is on, and the hub’s Worktrees page (via ⌘K) lists every provisioned tree.
Provisioning is three steps: the tree gets the checkout, WORKTREE_COPY globs of gitignored files are copied over from the registered root (.env and .env.* by default), and WORKTREE_SETUP_CMD runs with the tree as its working directory (npm ci, composer install, …). A non-zero exit parks the run and keeps the tree for inspection.
Each lane can serve its own app, and APP_SERVE picks how. Point APP_START_CMD at how the project runs and every worktree boots it on its own port, allocated upward from WORKTREE_PORT_BASE. On a Laravel machine running Herd, the tree is instead linked as its own site and served at http://<ticket>.test — mirroring the repo’s main site best-effort, so a secured main site makes the tree’s URL https and rewrites APP_URL in its .env, and an isolated one pins the tree to the same PHP version; both are undone when the tree settles. Either way the run page links straight to that instance with start/stop (or link/unlink) controls and a live log tail — Herd trees tail the tree’s own Laravel log — so browser verify, the QA hold, and the design-pick hold all drive the branch under test instead of your dev server.
worktrees
- WORKTREES
- Every run works in its own per-ticket worktree instead of the registered checkout. Default 0.
- WORKTREES_DIR
- Directory trees are created under, as <dir>/<repo>/<ticket>. Must not sit inside a registered repo. Default <TRAU_HOME>/worktrees.
- WORKTREE_COPY
- Comma-separated globs of gitignored files copied from the registered root into a fresh tree. Default .env,.env.*.
- WORKTREE_SETUP_CMD
- Shell command run in a freshly provisioned tree after the copy step (e.g. npm ci). A non-zero exit parks the run and keeps the tree.
- APP_SERVE
- How a worktree’s app is served: auto (Herd when the machine has it and the repo is one of its sites and APP_START_CMD is empty, the command otherwise, nothing when neither applies) | herd (always Herd — a machine without the herd CLI fails the start with a clear event rather than falling back) | command (APP_START_CMD only, on an allocated localhost port) | off (nothing is served, whatever else is set). Default auto.
- APP_START_CMD
- Shell command that serves the app from inside a worktree, run with the tree as its working directory and TRAU_APP_PORT/PORT set to its allocated port (e.g. npm run dev -- --port $PORT). Empty = no app is served per worktree.
- WORKTREE_PORT_BASE
- Lowest port a worktree app may be given; each tree takes the lowest free port at or above it, so concurrent lanes serve side by side. Default 4300.
Design picks (ui.sh)
A design choice is not a correctness question, so trau refuses to let the agent make one silently. When a build routes the ui.sh ideas skill, the agent lays out several annotated UI variants with a picker toolbar injected into the app, then parks the run at awaiting-pick instead of choosing for itself. The queue lane is freed at once — the drain keeps moving — while the branch, its work-in-progress, and its app stay up for whoever does the choosing.
Setup is two steps. Install: put your ui.sh account token in Settings as UIDOTSH_TOKEN, and the hub’s Skills page becomes a skills manager — browse the catalogue your account owns, install, update, and remove, with everything landing in user scope under ~/.claude/skills. Route: add ideas to REQUIRED_SKILLS, or to a rule in .trau/skills-rules.json so only design-flavored tickets carry it. Routing the skill is the whole opt-in — there is no arming toggle — and a build that routes it but ends without laying out variants finishes exactly as it always did.
The hold lives on the run page: every decision with its options, and — with worktrees on and APP_START_CMD set (see Parallel lanes) — a link to the branch’s own served app, so you click through the real variants rather than screenshots. A repo serving no app still holds; the card works from the labels alone. Submitting is all-or-nothing, one choice per decision, and resumes the run: a fresh finalize agent keeps what you picked, removes the rest, strips every trace of the picker scaffolding, and only then hands off to verify → commit → PR → CI as usual. That finalize (and each regenerate) is the PICK phase in per-phase model routing.
“None of these” is also an answer. Rejecting every variant requires notes on what is wrong and buys a regenerate round: one agent cleans the rejected round away, lays out fresh variants that answer your notes, and comes back to the same gate. Rounds are bounded by PICK_ROUNDS; a regenerate past the bound parks the run for a human with your notes as the reason.
design picks
- UIDOTSH_TOKEN
- Account token for the ui.sh skill library (https://ui.sh) — the hub lists, reads, and installs the skills that account owns with it. A credential: stored write-only, reads back redacted.
- PICK_ROUNDS
- How many “none of these — regenerate” rounds a held run gets before a further one parks it for a human. Default 2 (0 = the first regenerate parks it).
Configuration
trau stores its project and user config layers in the Hub database. The remaining file layer is ./trau.ini — a flat INI subset (KEY=value with # comments) for local overrides. Config keys are also environment-variable names, so PROVIDER in a layer and TRAU_PROVIDER in your shell are the same knob. Settings resolve in layers, from lowest to highest precedence:
precedence
- built-in defaults
- Shipped with the binary.
- user layer (Hub database)
- Personal and machine defaults — binaries, API keys, and trust flags.
- ./trau.ini
- Local fallback for the current directory (or TRAU_ENV).
- project layer (Hub database)
- Project facts — tracker, base branch, and loop policy. Project config beats user config and the local file.
- environment
- Any KEY above, or its TRAU_<KEY> alias (e.g. TRAU_PROVIDER), which wins.
- CLI flags
- --repo, --provider, etc. Highest precedence of all.
A minimal project config layer contains values like these:
TRACKER_PROVIDER=linear # linear | jira | azure | github LINEAR_TEAM=YourTeam # team name / Jira key / Azure project / source host slug READY_LABEL=ready-for-agent QUARANTINE_LABEL=needs-human BASE_BRANCH=main REMOTE=origin PROVIDER=claude # claude | codex | kimi AUTO_MERGE=1 # 1 = merge on green CI; 0 = stop at the PR MERGE_METHOD=squash # squash | merge | rebase MAX_ITERATIONS=15
project knobs
- TRACKER_PROVIDER
- Which tracker backs the loop: linear, jira, azure, or github.
- LINEAR_TEAM
- Team name (Linear), project key (Jira), team project name (Azure DevOps), or repo slug (source host).
- ISSUE_PREFIX
- Ticket-ID prefix for parsing, branch names, and sentinels (e.g. COD, TMS, ENG). Empty = derive from the team key, falling back to COD.
- READY_LABEL
- Tickets carrying this label are eligible to run. Default ready-for-agent.
- QUARANTINE_LABEL
- Applied when a ticket exhausts its repair budget. Default needs-human.
- QUEUED_LABEL
- Label mirrored onto tickets waiting in the hub queue, so planned work is visible in the tracker. Default queued.
- BASE_BRANCH / REMOTE
- Git target for branches and PRs. Default main / origin.
- PROVIDER
- Default agent backend for the loop. Default claude.
- PROJECT
- Linear project this repo owns. When set, the loop only picks tickets in this project, refuses a cross-project run, and files bugs here. Empty = no scoping.
tracker access (stored config layers)
- LINEAR_API_KEY
- Optional Linear personal API key — enables the fast direct GraphQL path instead of MCP-only access.
- JIRA_BASE_URL
- Jira Cloud site base URL for the direct REST adapter (e.g. https://acme.atlassian.net).
- JIRA_EMAIL / JIRA_API_TOKEN
- Atlassian account email plus a classic (unscoped) API token. Together with JIRA_BASE_URL they enable direct REST calls, with MCP as the fallback.
- AZURE_ORG_URL
- Azure DevOps Services organization URL for the direct REST adapter (e.g. https://dev.azure.com/acme).
- AZURE_PAT
- Azure DevOps personal access token. There is no MCP fallback for this provider, so it is required.
more knobs
- APP_URLS
- Monorepo mapping of workspace → local app URL (e.g. web=http://localhost:3000,admin=http://localhost:3001), so browser verify hits the right app for the slice. Single-app repos keep using APP_URL.
- AUTO_STASH
- Stash uncommitted tracked WIP before a fresh run and restore it when the run ends; 0 aborts instead. Default 1 — and moot under worktrees, which never touch your checkout.
- FORGE
- Code host the repo’s remote is on (github, azure, gitlab, bitbucket). Empty identifies it from the remote itself; set it for self-hosted installs on hostnames trau cannot recognize.
- DETERMINISTIC_COMMIT
- On squash-merge repos, stage and commit the slice deterministically with a templated Conventional Commit — the squash discards the message anyway — falling back to the commit agent when hooks reject it. Default 1.
- SERVE_TOKEN
- Bearer token for the hub on any non-loopback bind — see Remote access.
- SERVE_ALLOW_REGISTER
- Allow repo (un)registration over an exposed hub bind. Default 0.
- TRACKER_PROVIDER=internal
- Use trau's internal issue store — author and run tickets with no external tracker. A repo with no tracker configured falls back to it automatically.
Loop vs. solo tickets
trau pulls tickets labelled with your READY_LABEL (default ready-for-agent). What happens next depends on whether the ticket has sub-issues.
- Solo — a ticket with no sub-issues runs as a single pass on its own branch off BASE_BRANCH. One task in, one task done.
- Loop / epic — a ticket with sub-issues fans out onto a shared epic branch and processes each child tagged ready-for-agent. The epic branch keeps syncing with main, and once its children land it auto-merges on green CI (AUTO_MERGE-gated); children run directly later stack onto the same branch.
EPIC_FLOW controls this. Set EPIC_FLOW=1 to fan out sub-issues onto an epic branch, or EPIC_FLOW=0 to always treat the passed ticket as a standalone branch. Children that lack the ready label are skipped.
Monorepos: project detection is workspace-aware, APP_URLS maps each workspace to its own local URL for browser verify, and commits and PR titles conform to the conventions the repo already uses.
loop control
- MAX_ITERATIONS
- How many tickets a full loop run will work before stopping. Default 15.
- MAX_REPAIRS
- Quick verify-fail self-heal attempts before a bugfix. Default 2 (0 = none).
- MAX_BUGFIXES
- Comprehensive bugfix passes after quick repairs. Default 2 (0 = none).
- EPIC_FLOW
- 1 = fan sub-issues onto an epic branch; 0 = standalone branch. Default 1.
Per-phase model routing
Pick one PROVIDER for the project, then tune model and effort per phase. Phases you can address: BUILD, HANDOFF, VERIFY, REPAIR, BUGFIX, CLEANUP, LINTFIX, COMMIT, PICK. Keys are namespaced by provider, so each backend keeps its own routing. Mechanical phases ship with cheap defaults — handoff, cleanup, commit, and pick fall back to Sonnet and lintfix to Haiku unless you route them yourself.
# Claude: Fable 5 for the hard thinking, Sonnet 5 for the cold verify CLAUDE_BUILD_MODEL=fable CLAUDE_BUILD_EFFORT=max CLAUDE_VERIFY_MODEL=claude-sonnet-5 CLAUDE_VERIFY_EFFORT=medium # Codex: hardest work on GPT-5.6 Sol (the default), mechanical phases lighter CODEX_BUILD_MODEL=gpt-5.6-sol CODEX_BUILD_EFFORT=xhigh CODEX_COMMIT_MODEL=gpt-5.4-mini CODEX_COMMIT_EFFORT=low
Pattern is <PROVIDER>_<PHASE>_MODEL and <PROVIDER>_<PHASE>_EFFORT (kimi routes models only — its CLI exposes no per-phase effort knob). Leave a phase unset to fall back to the provider default (CLAUDE_MODEL / CLAUDE_EFFORT, etc.). Override the whole provider for a single run with --provider.
Prompts
The prompts are the loop’s real behaviour surface, so they are editable. Every phase prompt — build, handoff, verify, commit, repair, bugfix, cleanup, lint-fix, and the rest — is a named template in a registry, each with a title, a description, and its list of placeholders. Edit them from the hub: Settings → Prompts sets the wording for the whole machine, and a repo’s own Prompts section overrides just that project.
how an override resolves
- repo > global > built-in
- The narrowest override wins. Nothing set anywhere means the shipped default, which is always one click away via Reset to default.
- validated fail-closed
- An override that does not parse, or that drops a required placeholder, is rejected and the built-in default is used instead. Required placeholders are the ones carrying contracts the loop parses back — verdict and rubric JSON shapes, handoff and notes file paths, the REFUSED sentinel — so a reworded prompt cannot silently break the pipeline.
- snapshotted per run
- Prompts resolve once, when a ticket starts. Editing mid-run never splits a single run across two versions of a prompt.
Two things are deliberately not editable: tracker MCP prompt fragments and the pointer notes for rubric, build-notes, and lessons files. They are mechanical glue around loop-owned artifacts, not wording worth retuning.
Providers
trau drives the agent CLI you already use, interactively and on the subscription you already pay for — never a metered headless API call, and no provider key for trau to hold, subject to each CLI’s own terms. claude is the most exercised path today; codex (default model GPT-5.6 Sol) and kimi are wired and get sharper with every run. Models come from a single shared catalog, so the hub pickers and the config keys always agree.
provider knobs (stored user layer)
- CLAUDE_BIN / CODEX_BIN / KIMI_BIN
- Binary name or path for each provider. Default to the bare command.
- CLAUDE_FLAGS / CODEX_FLAGS / KIMI_FLAGS
- Extra flags passed to the agent CLI. Claude and Codex default to their permission-skip flags; kimi defaults to none.
- CLAUDE_MODEL / CLAUDE_EFFORT (etc.)
- Provider default model and reasoning effort when a phase route does not override them.
- CLAUDE_DISALLOWED_TOOLS
- Tools disabled inside agents. Default Agent,Workflow — denies in-agent subagent fan-out (each phase is already its own process).
- CODEX_PROFILE
- Optional Codex exec profile, passed through as codex exec --profile <name>.
- CLAUDE_CONFIG / CODEX_CONFIG / KIMI_CONFIG
- Optional provider-local KEY=value files, resolved relative to the env file that names them.
- AGENT_TIMEOUT
- Per-agent-call hard timeout in seconds — a backstop for runaway calls; unproductive hangs are killed earlier by AGENT_STALL_WINDOW. Default 3600.
Machine trust is the default posture: CLAUDE_FLAGS and CODEX_FLAGS ship with the providers’ permission-skip flags (--dangerously-skip-permissions, --dangerously-bypass-approvals-and-sandbox), because an autonomous loop cannot stop to click Approve. Point trau only at checkouts you are willing to have modified autonomously — and to restore approval prompts, set the FLAGS key yourself: a present-but-empty value overrides the default.
Verify, CI & merge
The verify phase is the gate. By default trau waits for whatever checks your PR runs and merges only when they are green and none are pending — set EXPECTED_CHECKS when tests run on the PR itself rather than locally.
merge & verify
- AUTO_MERGE
- 1 merges on green CI; 0 stops at the PR for you. Default 1.
- MERGE_METHOD
- squash, merge, or rebase. Default squash.
- EXPECTED_CHECKS
- Comma-separated check names that must be present and green. Empty = any existing checks.
- REQUIRE_CI
- Merge gate on CI: auto (default — wait for checks when a pull_request workflow targets the PR’s base branch, and merge with a warning when none does, so a base with no CI never quarantines) | 1 (always wait; absent checks time out) | 0 (never wait).
- CI_TIMEOUT / CI_POLL
- Seconds to wait for checks, and seconds between polls. Default 600 / 30.
- VERIFY_EFFORT
- How strictly verify grades a slice: low (the rubric contract alone), medium (default — the rubric plus regressions in what the slice touched), or high (full adversarial QA with an open-ended hunt). Unrelated to the per-phase reasoning-effort routing keys.
- BROWSER_VERIFY
- auto (UI slices only), always, or never. Drives browser-based verification.
- BROWSER_ISOLATION
- Which browser a verifying agent drives: managed (default — trau launches a dedicated headless browser for that one agent and ends it, its harness daemon and its temp dirs when the agent exits, so no window opens, your own browser gains no tabs, and two agents verifying at once cannot see each other’s) or attach (the shared browser its environment already names, the pre-managed behavior).
- BROWSER_BIN
- Explicit Chrome/Chromium binary a managed launch starts. Empty auto-discovers it. A binary that will not launch falls back to attach for that spawn with a warning in the run log, and the run still completes.
- VERIFY_PROOFS
- When browser verify drives the app, record a trace and key screenshots and harvest them to the hub, so the run page shows proof instead of prose. Default on.
- APP_URL
- Base URL of your locally-running app, used by browser verify. Default http://localhost.
- VERIFY_CHECKS
- Run the pluggable verify-check library each verify phase. Default 1. Checks live in the target repo under .trau/checks/*.yaml; severity gates the merge (error blocks, warn surfaces).
- QA_NOTES
- Post the run’s QA report as a ticket comment — verify result, checks and browser-QA lines, and the PR link on delivery, or the failure lines when the run gives up. Default 1.
- VERIFY_PANEL
- Cross-vendor verify panel: run verify as several fresh, isolated processes from different providers, each judging the diff independently. Each member is provider:model:effort. Empty = a single verifier.
- VERIFY_PANEL_POLICY
- How panel verdicts merge: unanimous (any dissent blocks, the default), majority, or any-pass.
The QA gate
QA_GATE=1 holds every run after its CI goes green and before it merges, in a durable awaiting-qa state with its own strip in the run ledger. The lane is freed while it waits — the queue starts the next item — and the worktree and its app stay up, so you drive the branch under test rather than reading a description of it.
Approve merges. Reject requires notes on what is wrong and spawns a bounded fix round that returns to the same gate. The repo-wide default is only a default: each queued item’s own Hold-for-QA choice in the run-steps dialog overrides it in both directions. The QA gate and the design-pick hold are independent — one run can hit both, the pick before verify and QA after CI.
qa gate
- QA_GATE
- Hold every run at awaiting-qa after green CI, released by Approve on the run page. Default 0; a queued item’s Hold-for-QA choice overrides either way.
Self-heal & fallback
A transient agent-step failure — a stalled subprocess, a hard timeout, or a non-rate-limit crash — self-heals instead of parking the ticket. The step retries on a fresh process, then hands off to the next fallback provider; only when the whole chain is exhausted does the run fault, with the work-in-progress preserved on its branch and the ticket left resumable. Rate-limits and provider outages pause the run blamelessly — nobody’s fault, resume when the window resets — and a verified give-up still quarantines. The Run ledger buckets each outcome so you can tell a blameless pause from a fault at a glance.
transient-failure recovery (stored user layer)
- AGENT_STALL_WINDOW
- Kill and recover a step that emits no output for this many seconds, well before AGENT_TIMEOUT (Claude interactive only). Default 180 (0 = disabled).
- AGENT_RETRIES
- Transient retries on the same provider before falling back or parking. Default 2.
- AGENT_BACKOFF
- Base seconds to wait between transient retries (grows with the attempt). Default 10.
- FALLBACK_PROVIDERS
- Ordered provider[:model[:effort]] specs to try after the primary is exhausted, e.g. codex,kimi. Empty = retry-only.
Lessons memory
Failed runs teach later runs. Each repair experiment — the failure type, the attempted fix, the evidence, the result, and a distilled lesson — is appended to .trau/runs/memory/lessons.jsonl after a repaired success or a quarantine. Lessons relevant to a slice are recalled into later build, verify, and repair prompts. Relevance is filtered and capped, so a thin or empty ledger injects nothing.
lessons memory
- LESSONS
- Record and recall lessons. Default 1 (0 = off: no recording, no recall).
- LESSONS_DISTILL
- Enrich each lesson with a cheap, isolated agent pass for a richer, ticket-agnostic takeaway. Default 0 (mechanical record only).
- TEAM_SYNC
- Share the repo’s lessons ledger with teammates over its own git remote: the hub publishes this machine’s records to refs/trau/team/<writer-id> and folds teammates’ records back into recall and the Lessons view. No server, no new credentials; needs a git remote. Default 0.
Time & cost tracking
Every run keeps per-phase token and cost accounting, summed at the end and printable any time with trau --status. The ~$X estimate is notional, not a bill: trau prices tokens itself because interactive runs report no provider cost.
Most of a phase’s token TOTAL is cache-read tokens, billed at 0.1× input (5-minute cache writes at 1.25×), so a multi-million-token phase is mostly cheap cache hits. On a subscription your marginal cost is the flat plan fee — read the estimate as a relative signal between phases and models, not a charge.
artifacts
- RUNS_DIR
- Root for per-ticket artifacts: <RUNS_DIR>/<ID>/{state, *.log, tokens.jsonl}. Default .trau/runs — auto-gitignored, and a legacy ./runs migrates automatically on startup.
terminal ui & usage hud
- TRAU_TUI
- Use the Bubble Tea TUI in a terminal. Default 1 (toggle per-run with --no-tui; pipes, cron, and --status always use plain output).
- THEME
- TUI color theme preset: default, catppuccin, dracula, gruvbox, or nord. Any semantic role can be overridden with a THEME_<ROLE> hex value.
- NOTIFY
- Desktop notifications on pause, quarantine, and session end. Opt-in. Default 0.
- AGENT_COLS / AGENT_ROWS
- Geometry of the agent PTY; the live agent view (the TUI’s w key, or trau watch headless) reconstructs at this size. Default 120 × 40.
- USAGE_WINDOW
- Track the active provider's real rate-limit window in the HUD (Claude OAuth usage, Codex app-server, Kimi balance). Metadata-only, fails closed. Default 1.
- USAGE_WINDOW_PTY
- Pseudo-terminal /usage fallback for providers with no structured window (Kimi subscription). Brittle, opt-in. Default 0.
Opt-in time logs: with TIMELOG_ENABLED=1, every merged ticket also writes a per-ticket effort log compatible with dev-flow tooling.
time logs (opt-in)
- TIMELOG_ENABLED
- Write a per-ticket effort time log (JSON) after merge. Default 0.
- TIMELOG_STORAGE
- Where logs land: repo (<repo>/.dev-flow/time/), user (~/.dev-flow/time/<repo>/), or none. Default repo.
- TIMELOG_OUTPUT_FORMAT
- Export rendering: default (JSON), jira-worklog, toggl-csv, or plain.
- TIMELOG_ESTIMATOR
- Per-ticket effort estimate: heuristic (deterministic table) or agent (a cheap agent call). Default heuristic.
Spend caps
Optional spend ceilings, enforced off the same normalized token/cost ledger that --status prints and checked before each agent call. A ticket that reaches its per-ticket cap is quarantined and the loop moves on; reaching a per-day cap stops the run cleanly so it can resume once the budget resets or you raise it. Empty = no cap. On unmetered providers prefer the token caps, since the USD figure is a notional estimate.
budget governance
- MAX_TICKET_USD
- Quarantine a ticket once its estimated cost reaches this many dollars. Empty = no cap.
- MAX_TICKET_TOKENS
- Quarantine a ticket once it reaches this many tokens. Empty = no cap.
- MAX_DAILY_USD
- Stop the run once the day's spend across all tickets reaches this many dollars. Empty = no cap.
- MAX_DAILY_TOKENS
- Stop the run once the day's tokens across all tickets reach this figure. Empty = no cap.
CLI reference
commands & flags
- trau
- Launch the TUI in the current repo — bringing the hub up first and waiting for it to answer healthy. With no project config layer, starts the onboarding wizard.
- trau serve
- Start the hub: a machine-local web app on http://127.0.0.1:8728. Binds to loopback by default; any other bind requires SERVE_TOKEN, and remote registration additionally requires SERVE_ALLOW_REGISTER=1.
- trau stop
- Stop the hub and leave it stopped, blocking until the port is free. Refuses while any loop is live — naming each run’s pid, repo and ticket — since a loop with no hub can neither checkpoint nor reach its tracker; --force parks those runs at their checkpoints first.
- trau hub <cmd>
- Manage the hub: start it if nothing is listening, restart it onto the current on-disk binary (--force to clear a wedged one), supervise / unsupervise it so launchd (macOS) or a systemd user unit (Linux) brings a crashed hub back on its own, or preflight — open and migrate the hub databases, then exit.
- trau doctor
- Preflight check: git, gh, the provider CLI, config sanity, tracker labels, and write permissions. Exits non-zero on any failure, so it drops cleanly into CI.
- trau config export / import
- Export team-shareable project settings without credential values, or preview and apply a shared file to the project config layer. Import adds and updates; it never deletes settings that the file does not name.
- trau dump
- Build an unredacted support bundle for the current repo. It names the selected runs, warns about the credentials and source data inside, and requires confirmation unless --yes is set.
- trau watch
- Tail a running loop’s live agent activity from another shell — the headless counterpart to the TUI’s w key and the hub’s Terminal page.
- trau steer <ID> <note>
- Queue an operator note for a running ticket without stopping it — it reaches the agent mid-phase, or at the next spawn if the run is between agents. Pass "-" to read the note from stdin. Needs a hub already up.
- trau takeover <ID>
- Stop the run and resume that ticket’s recorded claude session in this terminal. The repo stays locked for as long as the terminal lives; the ticket parks when you close it.
- trau forensics <cmd>
- Read-only incident queries over the run history: runs, events, spend. See trau forensics --help.
- trau --no-serve
- Skip the hub autostart for this TUI session.
- trau --once
- Process the next eligible ticket end-to-end, then exit.
- trau --list-eligible [--json]
- List the tickets the loop would consider, in pick order, without running anything.
- trau --list-epic <ID> [--json]
- List an epic’s sub-issues and their states without running anything.
- trau <ID>
- Run one specific ticket; an epic with sub-issues fans out onto an epic branch.
- trau --parent <ID>
- Treat <ID> as an epic and process its sub-issues (a bare <PREFIX>-<n> arg is equivalent).
- trau --dry-run
- Show the next eligible ticket without executing — changes nothing on disk.
- trau --status [--json]
- Print durable checkpoints plus token and cost totals. Add --json for machine-readable output.
- trau --reset <ID>
- Drop the branch and state and re-queue the ticket. Refuses if it is already merged unless --force is given.
- trau --reset-local <ID>
- Drop only the branch and the run directory — run history and the tracker are left alone.
- trau --requeue <ID>
- Un-quarantine in one step: fix the tracker labels and status, clear the checkpoint, close the attempt’s PR, and drop its branch.
- trau --clear <ID>
- Drop only the local checkpoint — no git, no re-queue — for tickets finished out-of-band (--forget is an alias).
- trau --max <N>
- Cap iterations for this run, overriding MAX_ITERATIONS.
- trau --no-resume
- Skip the resume scan and always pick a fresh ticket.
- trau --repo <path>
- Operate on a repo other than the current directory.
- trau --provider <name>
- Override the configured provider for this run (claude | codex | kimi).
- trau --no-tui
- Force plain log output instead of the Bubble Tea TUI.
- trau --verbose / --debug
- Extra stderr diagnostics: --verbose shows what the loop is doing; --debug also logs every git/gh command invoked.
- trau --version
- Print the installed version.
- trau --help
- List every command and flag.
Safety
trau is experimental and it changes code on its own: it edits the target repo, opens PRs, and by default auto-merges green ones. Point it only at a checkout you are willing to have modified autonomously.
- Preview first — trau --dry-run shows the next ticket and planned phases without touching disk.
- Preflight — trau doctor checks git, gh, the provider, config, and tracker labels before a run can fail mid-phase.
- Bounded by design — MAX_ITERATIONS, MAX_REPAIRS, and MAX_BUGFIXES cap how far a run goes.
- Own lane — WORKTREES=1 keeps every run in its own per-ticket worktree, out of your working copy.
- Spend caps — MAX_TICKET_USD / MAX_TICKET_TOKENS quarantine a runaway ticket, and MAX_DAILY_USD / MAX_DAILY_TOKENS stop the run at a daily budget.
- Quarantine on failure — a ticket that exhausts its repair budget gets the QUARANTINE_LABEL and is left for a human.
- Per-agent timeout — AGENT_TIMEOUT halts a stuck phase and writes a transcript as evidence.
- Stop at the PR — set AUTO_MERGE=0 to keep a human in the merge loop, or QA_GATE=1 to hold even green runs for your approval.
- Hub exposure — the hub is loopback-only by default; anything beyond requires SERVE_TOKEN. See Remote access.