Skip to content

Repository files navigation

baton icon

baton

Pass context between coding agents like a baton.

English | 简体中文

baton is a terminal-native workspace for coding agents, built around durable, harness-independent sessions and inspired by tutti. Today, it lets you use Claude Code and Codex in one TUI and switch between them without carrying context. Because BatonSession is owned by baton rather than any harness, the same foundation can grow from agent handoffs into multi-agent collaboration and orchestration. Claude Code and Codex are the first bundled harnesses, not a closed support list.

Harness-native sessions are resume optimizations; BatonSession history remains available even when a native session cannot be resumed.

Philosophy

The most common shape of multi-agent work today is a human acting as a context courier: copying one agent's output to another, re-explaining background, hand-writing handoff documents. baton wants context to be an asset the user owns, not a by-product locked inside a single tool.

Two fundamentals are in place today:

  • Context portability: a BatonSession is a durable, unified history owned by the user that outlives any single harness. Switching agents requires no context carrying; harness-native sessions only accelerate resume and are never a prerequisite for the history to survive.
  • Native experience: baton preserves each agent's own input, completion, streaming, tool-call, and approval experience as much as possible, adding only a few commands of its own (such as /codex and /claude).

The Plugin runtime adds a third principle:

  • Layered loops: baton core stays domain-neutral and owns the shared input, context, permission, and harness-routing path. Baton Plugins own long-running domain loops and currently propose the next Harness input for the user to confirm, edit, or discard. Harnesses remain intelligent execution providers; Harness Plugins such as devloop constrain the smaller development loop inside a Harness.

On top of these, three product directions remain on the roadmap. The Plugin runtime now provides the Resource/Controller foundation for long-running loops, but these end-to-end experiences are not complete yet:

  • Multi-harness collaboration: from relaying within one session toward dispatching the same task to multiple harnesses in parallel, with results merged back into one unified history. The near-term path is draft sessions — when a new idea strikes mid-task, fork a draft session (optionally on a different harness) to explore in parallel without interrupting the mainline.
  • Context intake: the mainline is not a raw transcript of everything but the canonical history the user endorses. After a draft session produces results, the user decides whether to merge its conclusions into the mainline or discard them; discarding is not deletion — drafts stay durable and referenceable.
  • Event-driven long-running loops: listen to external events such as pushed commits or merged PRs and wake the corresponding session to continue its work, so agents are no longer confined to an interactive terminal.

Architecture at a glance

Start with the stable kernel: baton is one bidirectional pipeline. chat-tui carries intent/render only, the controller owns the Input lifecycle + the driven-turn queue, adapters translate each harness's wire to a single normalized event stream, and session.jsonl persists it. The event stream is the sole source of truth; the UI is a projection.

baton kernel: one bidirectional pipeline

v2 keeps that pipeline and layers long-running domain loops around it. baton core remains domain-neutral and owns shared control; Baton Plugins reconcile domain Resources and propose work; Harnesses provide intelligent execution, while Harness Plugins constrain the smaller loop inside a Harness. Today, proposed work returns to the same Input, context, permission, and routing path for the user to approve, edit, or discard.

Baton, Plugin, and Harness relationship

See docs/kernel.md for the stable kernel — core concepts, invariants, the v1 pipeline, and the harness extension contract. See docs/plugin.md for the v2 Plugin runtime and docs/loop-engineering.md for the layered loop model.

Features

  • Use Claude Code and Codex from the same terminal interface
  • Switch directly with /codex or /claude, and configure its model and reasoning effort separately
  • Open a previous BatonSession with /sessions, or start a clean one with /new
  • Continue the latest session in a project with baton -c, or open one by ID with baton -s <id>
  • Search grouped @ context from built-in Session and Plugin ContextProviders, then inject it into the current turn
  • Record messages, thoughts, tool calls, file changes, plans, and token usage in a unified format
  • Preserve harness startup interactions such as Codex hook trust, reusing unchanged trusted definitions with a visible notice
  • Append events to a local session.jsonl for state reconstruction and future references
  • Reuse local Claude Code and Codex credentials without storing them in baton
  • Use a headless REPL to debug agent integrations
  • Register local or Git Plugin Marketplaces and install immutable Plugin Packages
  • Run session-scoped Plugin Controllers over durable Resources, with Resource/cron Sources, requeue wakeups, Board projections, and user-approved Proposals

Installation & configuration

Install baton with npm. You also need at least one supported agent installed and authenticated (Codex CLI / Claude Code).

npm install -g @compforge/baton

Or run it once without a global install:

npx @compforge/baton

On first run, baton creates ~/.baton/config.yaml:

defaultAgent: codex
codexCommand:
  - codex
  - app-server
mentionBudgetChars: 4096
showThoughts: true

See config.yaml.example for all available options and usage notes.

Codex approvals follow Codex's own configuration by default — your ~/.codex/config.toml, profiles and any enterprise policy all apply, and Codex itself defaults to reviewing with you. Set codexApprovalReviewer: auto_review to delegate to its risk reviewer instead; Baton keeps that delegation visible in Harness Status and records each automatic decision beside its target tool.

If Claude Code uses a custom executable, set claudeExecutable in the configuration or override it temporarily with an environment variable (BATON_CLAUDE_BIN=/path/to/claude baton). Configuration precedence: environment variables > config.yaml > defaults.

Usage

Start the TUI and type a prompt to send it.

/claude or /cc       Switch to Claude Code
/codex or /cx        Switch to Codex
/cc <message>        Switch to Claude Code and send the message immediately
/cx <message>        Switch to Codex and send the message immediately
/cla <message>       Unique harness-name prefixes work too
/model               Open the model picker for the active harness
/model <id>          Select the model used by subsequent turns
/effort              Open the reasoning-effort picker for the active harness
/effort <level>      Select the reasoning effort used by subsequent turns
/compact             Ask the active harness to compact its context
/status              Show the active harness/model context usage and session information
/sessions            Open the BatonSession picker
/new                 Start a new BatonSession in the current project
@                      Search grouped Session and Plugin context
Tab                   Complete a command or reference
Esc                   Interrupt the current turn
/exit                 Exit

Ambiguous prefixes such as /c <message> are not sent to a harness; baton reports the matching harnesses in the transcript.

Common CLI commands:

baton                              # Start the TUI
baton --cwd /path/to/project       # Start in a specific project directory
baton -c                           # Continue the latest session in this directory
baton -s bs_01...                  # Open a specific BatonSession
baton repl --agent codex           # Start the headless REPL with Codex (alias: cx)
baton repl --agent claude          # Start the headless REPL with Claude (alias: cc)
baton sessions                     # List sessions available for reference
baton plugins marketplace add ./reqloop
baton plugins available
baton plugins install qiankun/requirement-loop
baton plugins list
baton help                         # Show full help

Reference an ID returned by baton sessions in your prompt:

@bs_01... Implement this feature based on Claude's earlier analysis

baton reads the referenced session's compact summary and passes it to the active harness as context.

Data storage

baton stores its data in ~/.baton/ by default:

~/.baton/
├── config.yaml
├── plugins/
│   ├── marketplaces.json
│   ├── marketplaces/<marketplace-name>/
│   └── packages/<encoded-plugin-id>/<version>/
└── projects/<project-key>/
    ├── project.json
    └── sessions/<session-id>/
        ├── meta.json
        ├── session.jsonl
        └── plugins/<plugin-instance-id>/
            ├── resources/
            └── proposals/

Projects group sessions by working directory using a readable, collision-resistant key; project.json retains the original cwd. Plugin runtime data belongs to its BatonSession. session.jsonl is the durable logical history used for rendering, recovery, harness handoff, and cross-session references. Claude Code and Codex still manage their private native sessions; baton stores their IDs only to accelerate resume and never modifies their native session files.

License

Apache-2.0

About

A terminal-native workspace for coding agents, built on durable sessions.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages