TestRelic AI
Go to App
CLI

Modes & engines

The CLI has two orthogonal axes — Mode (the data boundary, Cloud vs Local) and Engine (which agent backend runs a turn) — plus permission modes. They compose freely.

The CLI has two orthogonal axes. Mode controls the data boundary; Engine controls which agent backend runs a turn. They are independent and compose — any mode works with any engine.

Mode — the data boundary

ModeWhat it means
Cloud (default)The standard experience: queries and results flow to and from TestRelic Cloud.
LocalNothing is uploaded. Every mutation is approval-gated, and cloud memory is read-only.

Switch modes either way:

testrelic --mode local

Or press Shift+Tab in the interactive UI to toggle the mode for the current session.

When to use Local mode

Local mode is for working against sensitive repos or in environments where you don't want anything written back to the cloud. You can still read cloud memory and context; you just can't change it without an explicit approval.

In Studio, Local mode is per chat

Studio has no app-wide mode switch. Every Studio chat runs in Cloud mode, and Local mode is a Skill you turn on for one chat: in a Code chat, open the composer's + menu and pick Skills → Local mode. See Workspace. The terminal CLI is unchanged: Shift+Tab and --mode local still switch modes there.

Engine — which agent backend runs a turn

The engine decides which agent backend actually executes a turn:

EngineSelector
CloudAgent--engine cloud
ClaudeCode--engine claude-code (alias claude)
Codex--engine codex
Cursor--engine cursor (alias cursor-agent)
Ollama--engine ollama
(auto-select)--engine auto
testrelic --engine claude-code

Or open the picker in the interactive UI:

❯ /engine

CloudAgent is the default (auto resolves to it) and needs no local install. ClaudeCode, Codex, Cursor, and Ollama are local engines — always opt-in, and each runs on your own auth or model, never silently substituted for the cloud agent. Claude Code drives your installed claude CLI headless; Codex drives codex exec; Cursor drives its CLI, cursor-agent (or agent, the name Cursor's installer now leads with); Ollama talks directly to a local POST /api/chat (default llama3.1 @ localhost:11434, override with OLLAMA_MODEL / OLLAMA_HOST or config ollamaModel). /engine shows each local engine's install status; if the CLI it needs is missing or unauthenticated, the turn falls back to CloudAgent.

To install Cursor's CLI, run irm 'https://cursor.com/install?win32=true' | iex in PowerShell on Windows, or curl https://cursor.com/install -fsS | bash on macOS and Linux (and inside WSL), then cursor-agent login. If it's installed somewhere TestRelic doesn't look, set TESTRELIC_CURSOR_BIN to its path.

Terminalshop-e2e · main

$ tr

> /engine

Engine
✻ TestRelic CloudTestRelic cloud agent · default, no deps
✳ Claude Codeyour local Claude Code · installed
✦ Codexyour local OpenAI Codex · installed
◇ Ollamayour local Ollama model · not installed

engine: Claude Code — your local Claude Code (runs on your own auth)

~/shop-e2e ·✳ Claude Code · ◇ CLOUDenter send · @ context · ! shell · shift+tab → mode · /commands

> @tests/checkout.spec.ts why does this keep flaking on CI?

✻ TestRelic

⏺ 3 tools · ctrl+o

The last 6 CI runs fail on the same step — waiting on [data-testid="place-order"]before the cart total re-renders. It's a race with the debounced price recalculation, not a selector problem.

I can add a wait on the total text settling before the click. Want me to open a fix?

> /engine codex

engine: Codex — your local OpenAI Codex (runs on your own auth)

> same fix, now open a PR

✻ TestRelic

⏺ 5 tools · ctrl+o

Opened fix/checkout-total-race — waits for the cart total to stop mutating before the place-order click, same MCP Playwright server Claude Code just used. PR #482 is up for review.

~/shop-e2e ·✦ Codex · ◇ CLOUDenter send · @ context · ! shell · shift+tab → mode · /commands

The turn header always reads ✻ TestRelic, no matter which engine is running underneath — switching engines with /engine changes who executes the turn (and the status chip below the composer), not the identity you're talking to. The same conversation, the same MCP tools, a different backend.

MCP tools follow you across every engine

Whichever engine you pick, it gets the same MCP server composition — your configured harness servers (Playwright/Appium/Maestro), any user-added servers, scoped entries, and the injected testrelic server — not a cut-down set. Each engine receives it through the only channel it actually has:

EngineHow it receives MCP servers
ClaudeCodeInline --mcp-config JSON, with an allowlist covering every merged server.
Codex-c mcp_servers.<name>.{command,args,env} TOML dotted-path overrides.
CursorMirrored into .cursor/mcp.json (Cursor's only MCP channel) at the root of the workspace's git repository, where Cursor reads it, so a workspace opened on a package folder still gets its servers; merge-preserving anything already there. If that repository is your home folder, nothing is written and the turn says why. --approve-mcps is used for headless approval when the installed cursor-agent supports it.
OllamaThe session's MCP host rides directly into TestRelic's own tool loop — host tools are advertised and dispatched the same way as the Cloud engine's client tools. A model that can't take a tools array degrades to a tool-less chat with an in-chat note, rather than failing the turn.

Cross-app confinement is engine-agnostic: it lives in the server's own command (tr mcp app-proxy --app <slug>), not in engine-specific config, so a cross-app call is refused in plain English no matter which engine spawned the entry. The testrelic MCP token is never written into a repo file — Cursor's .cursor/mcp.json entries that need it are fronted by the tr mcp app-proxy relay, which resolves the token from ~/.testrelic/token at spawn time.

Tool rules hold on every engine

Codex and Cursor take no tool policy of their own, so Studio's per-tool Auto, Ask and Off rules reach them through the same tr mcp app-proxy relay: a tool set to Off is left out of the server's tool list and refused if called anyway, and a tool set to Ask is refused with a reason, because a headless turn has no one to ask. Claude Code applies the same rules itself. This holds in Studio, in tr -p and in the terminal UI, and for remote MCP servers too. Local mode's data boundary still rests on the MCP capability gate (read-only caps).

Permission mode

Independently of mode and engine, choose how the agent asks before acting:

testrelic --permission-mode plan|default|acceptEdits|bypassPermissions
ValueBehavior
planPlan the work without making changes.
defaultPrompt for confirmation on each gated action.
acceptEditsAuto-accept edits while still gating other actions.
bypassPermissionsRun without confirmation prompts.

Each local engine maps this onto its own controls: Claude Code disallows its interactive-only tools so a headless turn never stalls on them; Codex maps to its sandbox flags (plan = read-only, otherwise full access); Cursor maps to --mode plan (read-only) for plan, adding --trust when the installed Cursor supports it so a plan turn runs in a folder Cursor hasn't trusted yet, and --force (the turn has already been approved) otherwise. Ollama runs TestRelic's own built-in tools, which stay gated by Local mode's standard write/delete/run approval regardless of --permission-mode.

How they compose

Mode and engine are set separately and combine freely — for example, Local mode with the ClaudeCode engine keeps every mutation approval-gated and nothing uploaded, while running the turn on Claude Code. Pick the data boundary you need with --mode, the backend you want with --engine, and the confirmation behavior with --permission-mode.

Next steps

→ Authentication · MCP host

Was this page helpful?

On this page