Terminal coding agent

JACA

PydanticAI backend, first-party Go TUI, JSON-over-stdio between them. Strict runtime, thin renderer, sessions that survive reboots.

01

Install

JACA ships as a Python-first tool with a bundled Go binary. The fastest path is uv — one command drops five executables on your PATH (jaca, jaca-go, jaca-read-only-worker, and two underlying entrypoints).

$uv tool install just-another-coding-agent

Run on macOS, Linux, or Windows via WSL2. Native Windows is not recommended yet — installs are rough at this point. If you're on Windows, use WSL2.

Needs uv on your machine first — grab it from docs.astral.sh/uv (one-liner for Linux, macOS, and Windows).

Wheels bundle the Go binaries, so no Node and no Go toolchain on your end. Once installed, jaca is on your PATH — run it from any directory.

02

First run

On first launch JACA opens a centered provider chooser — ChatGPT subscription, OpenAI API key, or Anthropic API key — each labeled with its setup state. Pick a lane, finish the OAuth round-trip in your browser, and the model is set. Secrets land in the OS keychain by default, with ~/.jaca/auth.json as fallback. Nothing about the auth moment is captured in the transcript.

The low-friction lane is the point: if you already pay for ChatGPT, you can authenticate in-browser and start using JACA without first provisioning API credentials just to try the agent.

03

Architecture

One binary, two processes. The Go TUI renders; the Python runtime owns meaning. They talk JSON-over-stdio — the same transport JACA uses in headless mode (e.g. jaca --headless --model openai-responses:gpt-5.4), which means the TUI is just another RPC client.

GO TUI Bubble Tea status · transcript · prompt JSON-OVER-STDIO one contract, both ways PYTHON RUNTIME PydanticAI model · tools · sessions renderer meaning
04

Steering, mid-run

A run is a pipeline, not a turn. While tools are executing, you can queue the next instruction without waiting. Enter stages a steering message for the next tool phase; Tab queues a follow-up for end of turn; Esc interrupts the current step and promotes queued steering. The composer shows you exactly what is pending — in the clip below, two queued messages stack on top of a running pytest: ↳ run go tests as well after the current phase, and ↳ explain compaction w.r.t this repo at end of turn.

tab
while streaming, queue a follow-up for end of turn; otherwise commit slash suggestions
enter
queue the next steering message for after the current tool phase
esc
interrupt the active run; backend promotes any queued steering
ctrl-c
first press — safe. second press — quit.
/login
connect ChatGPT subscription or set up an API key
/model <catalog-id>
switch model — e.g. openai-responses:gpt-5.4
/session
show current session id, name, fork parent
/name <text>
set or rename the active session
/trace off|local|logfire
observability mode
05

Tool contract

Every tool declares its concurrency class at registration. The registry enforces it; the runtime has no heuristics. Read-only tools run in parallel, everything that mutates state runs one at a time.

Parallel
  • read
  • grep
  • find
  • ls
may run concurrently
Sequential
  • write
  • edit
  • shell
  • subagent
one at a time
06

Sessions

Sessions are append-only and scoped to a workspace. Resume one with jaca resume <id-or-name>, or run bare jaca resume for an interactive picker. Forking is a first-class operation: jaca fork <id> --name <new> branches the conversation without mutating the parent, and the lineage stays attached.

turn 1 → now auth-fix active auth-fix-rebase jaca fork auth-fix-spike jaca fork

Stored at ~/.jaca/sessions/. When a resumed session gets close to the active model limit, JACA compacts before the next run: it keeps a bounded recent user-message tail, appends one assistant-style summary message, then replays that replacement history plus later native messages. The append-only session file stays intact for resume and forensics. See compaction architecture .

07

Proof

agent journey / dashboard

Open the evaluation dashboard

The full run-by-run record behind the submission: slice history, sampled scanfield, and the task matrix that produced the score.

Before the Go worker landed, Terminal-Bench containers were still paying subprocess startup on every read, grep, find, and ls call, so timeout pressure showed up as a real Harbor failure bucket rather than edge noise. The deltas below are from the first broad post-worker GLM-5 high A/B/C window.

47.4%
Terminal-Bench 2 submission

Public submission running GLM-5. 15 jobs, 445 trials, 89 unique tasks, minimum 5 trials per task, validated end-to-end.

+16 / −23 / −18
Terminal-Bench 2.0 post-deploy

Weighted mean up 16%, total errors down 23%, AgentTimeoutError down 18% in the first broad GLM-5 high A/B/C window after the Go worker shipped into the benchmark path.

1,300×
Read-only tool speedup

Replacing subprocess-per-call with a long-lived Go worker for read / grep / find / ls. Rust variant measured ~600×. Go won on repo fit.

See also: Terminal-Bench 2 submission ↗ · Go worker write-up