The auto-runner
The runner polls To Do for tickets assigned to claude-code (REV0_ASSIGNEE) and runs an
agent in each ticket’s working directory, up to Max concurrent agents at once
(Settings > Workspace > Board: 8 once setup has run, seeded by REV0_MAX_PARALLEL
before that). It starts with
serve --with-runner, or on its own with rev0 run. Every variable named here is also in
Configuration.
auto:permission_mode=acceptEditsand the full standard toolset (Read, Edit, Write, Bash, web search and fetch, subagents, skills, the kanban tools). The agent implements and callsfinish_ticketorrequest_action.plan_required,flow_planandspa_plan:permission_mode=plan, so no edits. The agent submits a plan and stops in Pending Action for your approval; accepting it in the UI re-queues the ticket.
Accepting a plan also switches the ticket to auto: the plan is agreed, so from then on the
agent is implementing rather than iterating on it, and the Mode picker says so. Want a
second plan inside the same ticket? Pick a plan mode again (or ask the agent, which asks for
the switch itself): that re-arms the sign-off, and the next run plans the remaining work in
the mode it planned in the first time. Picking a mode never moves or starts the ticket, it
only says what the next turn does, so start that turn yourself with a reply or by moving the
ticket to To Do.
When the agent reaches for a tool outside its pre-approved set, the run parks for you; see Approve a tool request. Extra MCP servers are covered in Connect an MCP client, and running on Codex or Cursor in the engines guide.
Run length and context
Section titled “Run length and context”The full transcript is streamed and stored on the ticket, and the agent’s session id is
saved for resume. There is no per-run turn cap: a run ends when the agent reaches a
terminal action (finish_ticket or request_action) or when a human presses Stop.
Spend is what bounds a run. Before each agent turn the runner checks two ceilings, and a breach parks the ticket in Pending Action instead of starting the turn:
- the board’s daily, weekly and monthly budgets, when Enforce spend budgets is on (Settings > Agents > Spend budgets, off by default, overridable per board);
- the ticket’s own Spend limit (in the ticket toolbar, blank by default), against everything the ticket has spent so far.
Neither stops a turn already running, so a single long turn can still overshoot. See
Track usage and cap spend.
Context stays in bounds through the CLI’s own auto-compact plus the board’s proactive
compaction before any resume (REV0_COMPACT_THRESHOLD, default 0.75).
Per-ticket model
Section titled “Per-ticket model”Each ticket can pick which model the agent runs with, overriding the board default
(seeded by REV0_MODEL). Choose it on the create form, in the ticket toolbar next to the
mode, with the CLI (--model), or with the update_ticket MCP tool. The presets carry a
proper model name backed by a pinned id (the Claude models, and the GPT models, which run
on Codex); Custom version / id… takes any other pinned model id. The board default is
Default model in Settings > Agents > Agent and model defaults. Models the installed
CLIs report are added to the list by themselves. Blank means “use the default”.
Subtickets inherit the parent’s model unless overridden. Newer models also get a small
system prompt append from config/model_prompting.json, following the official
prompting guide.
Per-ticket thinking level
Section titled “Per-ticket thinking level”Each ticket can also pick how hard the agent reasons, mirroring the model override. The
levels are each engine’s own effort names: off, low, medium, high, xhigh and
max for Claude Code, plus minimal and ultra for Codex, listed per model in
config/thinking_levels.json. More thinking means deeper reasoning but slower, more
expensive runs, and a level a run’s model does not support is clamped down. Set it on the
create form, in the ticket toolbar next to the model, or with the update_ticket MCP
tool; set the board default with Default thinking level in
Settings > Agents > Model & thinking (or seed it with REV0_THINKING_LEVEL). Blank means “use the board default”, and a blank board default
leaves the CLI’s own thinking behaviour untouched. Subtickets inherit the parent’s level
unless overridden.
Built-in browser
Section titled “Built-in browser”WebFetch is blocked by the anti-bot protection on most retailers and many modern sites,
which return 403, 503 or an empty JavaScript shell, so it cannot read live prices,
ratings or product links. So every agent gets a real headless Chromium through the
Playwright MCP server, on by default. The
server is version-pinned and its Chromium is installed once at setup (install.sh or the
Docker image), so nothing reinstalls per run. The safe browser_* tools (navigate,
snapshot, click, type, evaluate, …) are pre-approved so a browse never parks on a
permission prompt; the sensitive ones (browser_file_upload, browser_run_code_unsafe)
still ask on first use.
# It just works after install.sh. To turn it off on a RAM or disk constrained runner:export REV0_BROWSER=0 # then restart the runnerEach ticket’s browser is its own computer. In the default
browser_session_mode (ticket, Settings > Connections > Built in browser) the browser
tools do not launch a throwaway Chromium per run: they attach over CDP to one the BOARD
starts for the ticket, the first time its agent browses. It keeps a persistent profile, so
a login survives the run, the agent’s next turn and a board restart. In the ticket view it
is a small monitor icon that streams nothing until you click it, even when the ticket parks
on a sign in wall: a park is not consent to stream. From the panel you watch
Chrome’s screencast and drive it (click, type, address bar) while no run is live, then
Hand back with a normal reply. The Chromium is a board background job, so it shows in
Running tasks and is stopped with the others at In Review / Done; its profile is deleted
when the ticket is archived or deleted. Installed Google Chrome is preferred over
Playwright’s build (some sign in pages refuse “Chrome for Testing”);
REV0_COMPUTER_CHROME=/path/to/chrome picks another. Known ceiling: the CDP port is on
loopback with no auth, the same trust boundary as the agent’s own shell on that host.
isolated restores the old browser per run.
Extensions on the computer. computer_extensions (Agent Browser Extensions
under Settings > Connections, browser-only) lists unpacked extension folders, a password
manager being the usual one. Pasting a Chrome Web Store link there downloads the extension
into <data root>/extensions/<id> (browser-only POST /config/extensions/install, which
fetches the CRX from Google’s update endpoint and unpacks it; the same link again updates it
in place) and adds that folder. The board loads them into every computer at every launch over
the debugging port (--enable-unsafe-extension-debugging plus Extensions.loadUnpacked,
which Google Chrome still honours after dropping --load-extension), and the panel’s
Extensions button lists them and opens their pages. The computer always sends a normal
Chrome user agent and runs with --disable-blink-features=AutomationControlled: headless
Chrome otherwise reports navigator.webdriver = true, and Cloudflare’s “Verify you are
human” check then loops forever. Two agent hooks go with it, on whenever the built-in browser is: browser
results have secret-looking textbox values redacted (inline and in saved snapshots), and
browser_navigate to chrome-extension:// is refused. See
Use a password manager on a ticket’s computer.
To customize the browser (a different version, extra flags, a non-default profile), add a
playwright entry in REV0_MCP_CONFIG or the Settings MCP server list: a same-named entry
overrides the built-in default. See config/extra_mcp.example.json. The
shopping-research skill uses the browser_* tools to gather product data and renders a
ranked, clickable HTML card grid as a ticket artifact.
Token savers
Section titled “Token savers”Three independent switches cut what a run spends. All are off by default.
Bash output compression
Section titled “Bash output compression”Noisy commands (test runs, builds, find, git, logs) spend full tokens on repetitive
output. REV0_BASH_COMPRESS=1 enables a PostToolUse hook that shrinks what the model
reads from Bash results: it collapses repeated lines into a (xN) count, strips excess
whitespace, and keeps the head and tail of very large outputs while preserving known
test-runner failures. It works on the already-captured output and never changes what the
command did (exit codes and the interrupted flag are untouched).
scripts/measure_bash_compression.py reports the token delta on a fixture corpus.
A complementary, source-level reducer. When enabled, a PreToolUse Bash hook rewrites a
safe single command (for example git status) to its rtk
equivalent (rtk git status), so rtk filters that command’s output before it reaches
the model. Only simple commands whose program is in config/rtk.json’s allow-list are
rewritten; pipelines, redirects, compound commands, sudo, env, cd and unknown
programs pass through untouched, and rtk transparently runs any subcommand it does not
optimize, so exit codes never change. It pairs with the compressor above: rtk at the
source for known commands, the compressor as the safety net for the rest. rtk only
transforms shell output; it never proxies the API, so it cannot shrink a model’s context
window.
- Turn it on with rtk token reduction in
Settings > Automation > Board features (
rtk_enabled) or withREV0_RTK_ENABLED=1. Precedence: Settings, then the environment, thenconfig/rtk.jsonenabled, then off. - Install the binary once (it has no pip package):
uv run rev0 install-rtkfetches the pinned, checksum-verified prebuilt binary into<repo>/.rtk/bin(falling back tobreworcargo). Re-running is a no-op when the pinned version is present. Installing is separate from the toggle: flippingrtk_enablednever installs. - Tune the pinned
versionandsupported_commandsinconfig/rtk.json(path overridable withREV0_RTK_CONFIG).scripts/measure_rtk_savings.pyreports the token delta over a corpus of read-only commands so you can decide before enabling it broadly.
ponytail
Section titled “ponytail”A behavioural reducer. When enabled, the runner appends ponytail’s “lazy senior developer” rules to the agent’s system prompt: the YAGNI decision ladder (does it need to exist, reuse what is already here, stdlib, native feature, installed dependency, one line, minimum code), deletion over addition, the shortest correct diff. Where rtk trims a command’s output, ponytail shrinks what the agent builds in the first place. It touches only the system prompt.
- Turn it on in Settings > Agents > ponytail (
ponytail_enabled, overridable per board) or withREV0_PONYTAIL_ENABLED=1. Precedence: Settings, then the environment, thenconfig/ponytail.jsonenabled, then off. - Pick the intensity (
ponytail_level, orREV0_PONYTAIL_LEVEL):litenames the lazier option and lets the agent choose,fullenforces the ladder (default),ultrais a YAGNI extremist. - No install needed: the rules ship in
config/ponytail_skill.md, so the append works offline.uv run rev0 install-ponytailoptionally clones the updatable upstream plugin into<repo>/.ponytail, which the runner prefers when present. Override the config path withREV0_PONYTAIL_CONFIG.