Project Info
Baton compiles the noisy, half-finished work of one AI agent into the smallest verified state another agent needs to continue. It transfers work between independent coding tools (Claude Code and Codex CLI) without re-explaining the task, and at no extra API cost.
Inspiration
Anyone who codes with AI agents has hit the same wall. You spend forty minutes with Claude Code on a hard bug. It finally has the context: the repo layout, the failing test, the approaches you already ruled out. Then it hits a usage limit, and you are starting over in a fresh Codex window, retyping the whole story from memory. The industry has spent two years making each agent smarter, with larger context windows and better reasoning. No one built the part that lets one agent pass the work to another. As the number of usable models grows and rate limits stay real, the problem stops being "is the model smart enough" and becomes "can I keep working when this one runs out." That gap, continuity, is what we set out to close. What It Does When an agent hits a usage limit, crashes, or stalls mid-task, Baton does four things: Freeze. It snapshots the workspace from facts, not narration: git diff, test exit codes, terminal output, and a regex code skeleton. Compress. It distills that into a small, schema-validated handoff packet, roughly 95 percent smaller than the raw session. The packet keeps the one thing a summary throws away: failure memory, the "do not re-run this migration blindly, the first attempt half-succeeded" knowledge. Switch. It launches a different agent (Claude Code or Codex CLI) in the same repository, working from that packet alone. Verify. It runs your real verification command, such as npm test, and reports the actual exit code and final diff. It does not claim success. It proves it or it does not. The developer never re-explains the task during the transfer. And Baton drives your already-authenticated local CLIs (claude -p, codex exec) rather than metered REST APIs, so a handoff adds nothing to your bill. How this differs from what already exists Most of the market has been competing on the model axis. Baton works on a different one, continuity, and that axis becomes more valuable as the set of available models keeps splitting. How We Built It The architecture is provider-neutral, with shared contracts as the only dependency boundary. Shared contracts (packages/shared). Runtime-validated Zod schemas (RelayEvent, HandoffPacket). One definition produces both the validator and the TypeScript type, so no layer can emit a malformed packet. Node and TypeScript server. A guarded session state machine, a generic process runner built on node:child_process that turns any CLI's lifecycle into typed events, provider adapters for Claude and Codex, the orchestrator that runs detect, freeze, distill, launch, and verify, and a WebSocket broadcaster for the live timeline. The compressor. It gathers evidence deterministically (git, regex skeleton, exit codes), then gives the language model exactly one job: distill. The output is schema-validated, and on any failure a deterministic fallback packet is built from the raw evidence, so compression is never a single point of failure. The verifier. It runs the stored command through the shell and treats the exit code as the only source of truth. Event store. Every event streams to Redis so the timeline survives a refresh, or to an in-memory store with the same interface. The engine never imports Redis; adapters emit into a sink and do not know who is listening. Front end. A React and Vite dashboard, plus an Electron desktop companion that docks to a screen edge and adds a native folder picker. Built with: TypeScript, Node.js, React, Vite, Electron, Redis, WebSocket, Zod, Git, Claude, Codex. Challenges We Ran Into Deciding what not to store. The git diff is re-derivable because the next agent reads the repo itself. So the packet had to carry only the parts that cannot be recovered: intent, decisions, and failure memory. Drawing that line took several rewrites. Headless agents that would not act. Run with -p or exec, real Claude and Codex would hang waiting for a stdin EOF, and would refuse to edit files because headless mode denies writes with no human to approve them. The agent would describe the correct fix and change nothing. Closing stdin and adding two permission flags (--permission-mode acceptEdits, --sandbox workspace-write) turned a frozen screen into an agent that actually edits the repo. Trusting evidence over claims. We repeatedly caught agents reporting success on red tests. That pushed the design toward an exit-code-only verifier and toward compressing facts instead of summaries. Regex instead of an AST, on purpose. The next agent reads the real code, so we only need to point at the surface, not parse it. A line-anchored regex skeleton was the right cost-for-precision trade, and resisting the heavier option was its own discipline. Provider neutrality as a constraint. Keeping the engine from importing Redis, an adapter, or the UI meant continually refusing convenient shortcuts. Accomplishments That We're Proud Of A handoff that crosses both a vendor boundary and a usage limit: Claude's session compressed into a portable packet, Codex resuming the same repository from it, and a passing test confirming the result. No added cost. Reusing local CLI auth means switching models is free, with no API meter and no surprise bill. Failure memory. The packet's pitfalls field is what makes the second agent start ahead of a cold session rather than from zero. A closed loop. Most handoff tools stop at "here is the context." Baton stops at a real exit code. A clean contract spine. Because Zod schemas are the single boundary, adding a new provider is just another adapter. What We Learned As models commoditize, the scarce resource is not a smarter agent but uninterrupted work across agents. The connective layer is the product. Self-reported progress is unreliable; executable evidence is not. Designing around that made the whole system more robust. The value of compression is in what you can safely discard. A good packet is small because the repository on disk is the source of truth. The unglamorous layer decides everything. Stdin handling, permission flags, and path resolution were the difference between a good idea and a working handoff. What's Next for Baton Hardened real multi-CLI runs with authenticated Claude and Codex, streaming each step live instead of a single JSON blob. A context firewall: deterministic redaction of secrets (API keys, tokens, .env assignments, private keys) before any evidence is distilled, stored, or shown. More providers behind the same neutral adapter, including Gemini and local models, plus controlled multi-hop handoffs. RelayBench: measured comparisons of task completion with and without a clean handoff. A hosted, sandboxed demo so anyone can watch a handoff happen without installing anything. Session persistence across restarts, so a frozen session can be resumed later, on another machine, with a different model.
Baton

Built at the UC Berkeley AI Hackathon, 2026.
Baton compiles noisy agent work into the smallest verified state another coding tool needs to continue.
When an AI coding agent hits a usage limit, crashes, or stalls mid-task, you normally have to re-explain everything to the next tool. Baton captures the unfinished work from factual evidence (git diff, test exit codes, terminal output), compiles a small portable handoff packet, launches a different agent in the same repository, and verifies whether it actually finished — the developer never re-explains the task.
Baton is not an editor or a Cursor clone. It transfers work between independent tools (Claude Code ⇄ Codex CLI) through a visible, provider-neutral manifest.

Claude Code hits a usage limit mid-fix → Baton compiles a verified handoff packet → Codex CLI resumes in the same repo → Verify runs the real tests and confirms the result.
Why Baton
Today, an AI coding agent is a single point of failure. The moment it stops — usage limit, crash, network blip, or a provider-side outage — the context dies with the session. The developer becomes the recovery mechanism: re-reading the diff, reconstructing what the agent was attempting, and re-prompting a fresh tool from scratch. That re-explanation tax is paid every time, and it grows with the size of the change.
Baton removes the human from the recovery loop. It treats agent work as
portable state, not a disposable chat session. The state is rebuilt from
evidence the machine can verify — git diff, test exit codes, terminal output —
rather than from an agent's self-report, which may be wrong or optimistic. That
verified packet is small enough to hand to any compatible tool, so work
survives the death of the agent that started it.
What works today
- Start Claude Code or Codex CLI against a local repository.
- Stream normalized process, terminal, file, and test events into the dashboard.
- Trigger a handoff manually or after a detected rate limit/context threshold.
- Rebuild state from Git, terminal evidence, and command exit codes.
- Distill that evidence into a small, runtime-validated handoff packet.
- Resume the other provider with the packet and repository already on disk.
- Run a user-selected verification command and decide pass/fail from its exit code.
- Persist event timelines and the latest packet in Redis when configured, with an in-memory implementation for local demos and tests.
The bundled demo uses deterministic fake agents so the complete flow is
repeatable without provider accounts. Real mode uses locally installed and
authenticated claude and codex CLIs.
Trust boundary
Baton's server binds to 127.0.0.1, keeps provider credentials in memory, and
does not require a hosted Baton service. Real agent runs still send prompts and
repository context to the provider selected by the user. The current Distiller
can include Git diffs and failure output in that provider request, so Baton
should not be described as keeping all code on-device.
Secret redaction, repository policies, signed audit logs, and self-hosted team controls are roadmap work, not current guarantees.
Current limitations
- Only Claude Code and Codex CLI have first-party adapters.
- Rate-limit and context-pressure detection exist; general provider-health and arbitrary-stall detection do not.
- Automatic handoffs are intentionally bounded to avoid provider ping-pong.
- Verification is one command and one exit-code verdict.
- Redis preserves events and packets, not the complete live process/session state.
Quickstart
npm install
npm run demo
Open the printed dashboard URL (http://127.0.0.1:4173/?api=…&ws=…) and click
Start Baton. The demo runs deterministic fake agents end-to-end — no provider
CLI or auth required. Fake Claude reports a delayed usage limit, Baton
automatically hands the task to fake Codex, and Verify runs the real fixture
tests.
If those ports are already occupied, choose explicit alternatives:
PORT=4001 WEB_PORT=4174 npm run demo
Run the desktop app against the real subscription-authenticated CLIs:
claude # complete Claude sign-in once, then exit
codex login # complete Codex/ChatGPT sign-in once
npm run desktop:real # leave API-key fields blank
Docked sidebar (terminal companion)
Pin the rail beside your real terminal as a frameless desktop window:
npm run demo # in one shell (server + UI)
npm run sidebar # in another — opens the rail-only companion
Or open the rail-only view in any browser: http://127.0.0.1:4173/?rail=1.
Desktop companion (Electron)
A native window that snaps to a screen edge — the "magnet" companion — and adds a native folder picker for the workspace:
npm run desktop # one-command safe demo; docks right
npm run desktop:real # real locally authenticated CLIs
RELAY_DOCK=left npm run desktop
RELAY_DOCK=float npm run desktop
RELAY_ONTOP=1 npm run desktop # optional floating/always-on-top mode
The command starts the server, UI, and Electron shell together; closing Electron stops the local stack. Inside the desktop app the Workspace field gains a Browse… button (native OS folder dialog).
The demo flow
- An agent (Claude) starts fixing a real bug in
demo-repo/— theusers.agemigration runsALTER TABLEunconditionally, so the focused test fails. - The agent hits a usage limit with the test still red.
- Baton freezes the workspace, distills a validated handoff packet, and launches the other agent (Codex) in the same repo from that packet alone.
- Codex finishes the task; click Verify and Baton runs the real verification command, showing the exit code and verdict.
The user never re-explains the task during the transfer.
Screens
| Ready | Handoff | Verified |
|---|---|---|
![]() | ![]() | ![]() |
Architecture
┌─────────────────────────────────────────────────────────────┐
│ React / Vite dashboard (ui/) │
│ live terminal + Baton rail ◀── WebSocket events │
└───────────────┬─────────────────────────────────────────────┘
│ HTTP (/api) + WS (/ws/sessions/:id)
┌───────────────▼─────────────────────────────────────────────┐
│ Node + TypeScript server (apps/server/src/) │
│ ┌────────────┐ ┌───────────┐ ┌────────────┐ ┌────────────┐ │
│ │ session │ │ process │ │ orchestr. │ │ broadcaster│ │
│ │ manager │ │ runner │ │ + handoff │ │ (WS) │ │
│ └────────────┘ └───────────┘ └─────┬──────┘ └────────────┘ │
│ ┌────────────┐ ┌───────────┐ │ ┌──────────────────┐ │
│ │ adapters │ │ verifier │ └─▶│ event store │ │
│ │ claude/cdx │ │ │ │ Redis | in-memory│ │
│ └─────┬──────┘ └───────────┘ └──────────────────┘ │
└────────┼─────────────────────────────────────────────────────┘
▼
Local Git repository (the workspace the agents operate in)
The browser requests actions; the server controls processes and secrets. Evidence flows from the repo and command exit codes — the repository and executable evidence outrank agent summaries.
Distiller pipeline
repository + runtime
│
▼
Evidence Collector ──► EvidenceBundle (Zod)
│ │
│ ├─ goal + acceptance criteria
│ ├─ git branch/status/diff
│ ├─ changed files + commands
│ └─ latest failure + terminal excerpt
▼
Prompt Assembler ──► Claude or Codex compression backend
│
▼
DistilledClaims (Zod)
│
EvidenceBundle + session metadata
└─────────────┤
▼
deterministic packet builder
│
▼
HandoffPacket (Zod)
│
Redis/in-memory store ──► next agent
The model supplies only reasoning that cannot be recovered directly from disk: the current summary, decisions, constraints, next actions, pitfalls, and focus files. Baton fills changed files, command exit codes, provider identities, and the verification command from deterministic evidence. If model distillation fails or returns invalid JSON, Baton emits a deterministic fallback packet instead of abandoning the transfer.
The local control server binds to loopback only (127.0.0.1) and accepts
browser/WebSocket traffic from the configured dashboard origin.
Repository map
packages/shared/ Runtime-validated contracts (RelayEvent, HandoffPacket, …)
apps/server/src/ HTTP, sessions, WebSockets, process runner, adapters, store
ui/src/ Terminal companion dashboard + live event projection
demo-repo/ Deterministic migration bug — the handoff target
tests/ Engine + cross-layer contract tests
Shared schemas are the dependency boundary: every layer may import
packages/shared, but contracts never import an application. Adapters emit
RelayEvents through a RelayEventSink; they don't know whether events are
broadcast, persisted, or both.
Verification
npm test # engine + server suites
npm run typecheck
npm run ui:build
Redis is optional — set REDIS_URL for durable, refresh-surviving timelines;
without it, an in-memory store with the same interface is used.
Built with
TypeScript · Node.js · React · Vite · Redis · WebSocket · Zod · Claude · Codex
Roadmap
Near term
- Harden and benchmark authenticated
claude+codexruns - Restore resumable session state across Baton server restarts
- A reproducible benchmark with a measured no-Baton baseline for comparison
- Controlled multi-hop handoffs (A → B → C, each transfer verified)
- Signed desktop packaging and a user-configurable dock layout
Provider resilience
- Health-aware routing: detect rate limits / outages and fail over before a task stalls, not after.
- Pluggable adapters for more agents (additional CLIs and IDE agents) behind the same provider-neutral contract.
- Automatic retry-and-escalate: try a cheaper model, fall back to a stronger one only when verification fails.
Team & enterprise
- Shared handoff packets so a transfer can move between developers, not just between tools — pick up a teammate's in-flight agent work.
- Centralized, signed audit log of every handoff and verification verdict for compliance and review.
- Policy controls: allowed providers, data-residency boundaries, and per-repo verification commands enforced by the orchestrator.
- Self-hosted / VPC deployment with SSO, so the control plane stays inside the enterprise perimeter.
Verification
- Richer verdicts beyond a single exit code (per-test results, coverage deltas, lint/type gates) attached to each packet.
Credits
Built at the UC Berkeley AI Hackathon, 2026, by:
License
MIT © 2026 Syed Mohammad Husain and Baton contributors.
Analysis
View
Metric
- 59
- 18
- 13
- 13
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CSSIn code
- HTMLIn code
- JavaScriptIn code
- ReactIn code
- TypeScriptIn code
- Node.jsClaimed
- RedisClaimed
5 of 7 appear in the indexed code. 2 claimed on Devpost could not be matched to code, which may simply mean the tool leaves no trace in the repository.
AI coding agents
- Claude CodeCommits
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
408 KB
Source files
88
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
Myst1C13/Baton
110 files · 1.1 MB · @ 39e1e55
Structure
Interface
11 files · 10%Screens, components and styles rendered to the user.
API & routing
26 files · 24%Request entry points: routes, handlers and controllers.
Application logic
28 files · 25%Domain rules, services and shared utilities.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- TypeScript85%
- Markdown10%
- CSS4%
- JavaScript0%
- YAML0%
- HTML0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
package.json
npm · 15- ioredis
- react
- react-dom
- ws
- zod
- +10 more
apps/server/package.json
npm · 7- ioredis
- zod
- +5 more
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.


