Skip to content

About

Don't stop by an agent limit

Topics

Resources

Stars

10 stars

Watchers

0 watching

Forks

Repository files navigation

agent-baton

Don't lose your work when an AI coding agent hits its quota.

baton monitors usage for Claude Code and Codex, warns you before the threshold, and writes a rich Markdown handoff — with git evidence — so the next agent picks up exactly where you left off.

npm npm downloads license node Platform: macOS Platform: Linux Platform: WSL PRs Welcome

asciicast


The problem

You're deep in a task — three files modified, a bug half-fixed. Claude or Codex hits its hourly usage limit. You either:

  • Lose context and start explaining from scratch in a new session.
  • Manually copy-paste diffs and notes into the next agent.

Baton fixes that. It intercepts at the threshold, gives you a choice, and writes a structured handoff that the next agent can read cold.


Table of Contents


Install

npm install -g @codeprakhar25/agent-baton

Requirements: Node.js 18+


Quick Start

# 1. Initialize once per project
cd ~/your-project
baton init

# 2. Work normally — baton hooks into Claude automatically
#    For Codex, use the baton wrapper
baton codex "continue the auth refactor"

# 3. When baton warns you, choose: continue or hand off
#    Then pick up in the next agent
baton pickup --to codex

Every handoff is written to ~/.local/state/agent-baton/projects/<slug>/handoffs/ and never touches your repo.


How It Works

Baton has two integration paths:

Claude Code — baton init installs global hooks into ~/.claude/settings.json. On SessionStart, UserPromptSubmit, and PreToolUse, baton guard reads cached usage with a three-tier TTL:

Usage range Cache TTL
Below 50% 15 min
50% → warning band 5 min
Warning band → limit none (always fresh)

Within a Claude session, Baton asks at most once in the warning band and once at the hard threshold. If you choose to continue in Claude, later prompt-submit and tool hooks stay quiet until the next Claude session resets the notification state.

Codex — baton codex wraps the codex binary. Usage is checked before launch. If you're over the threshold, Baton asks whether to continue, write a handoff, or run baton pickup.

baton guard / baton codex
          │
          ▼
    fetch usage (cached)
          │
     over threshold?
     ┌────┴────┐
    no         yes
     │          │
  allow     ask user
  work       │      │
          continue  handoff
                     │
              agent writes Markdown
              + Baton appends git evidence
                     │
              write HANDOFF-latest.md
                     │
              baton pickup --to <agent>

Handoff format

Each handoff is a Markdown file with:

  • Agent-authored task summary, progress, decisions, remaining work, and next step
  • Baton metadata and source handoff path
  • Git branch, status, diff stat, and last commits
  • Full uncommitted diff appended as evidence (truncated at handoff_extraction.max_diff_chars)
  • Instructions for the next agent

Git state is the durable source of truth — if transcript extraction is incomplete, the diff tells the full story.

~/.local/state/agent-baton/projects/<project-slug>-<hash>/
  handoffs/
    HANDOFF-latest.md      ← always the most recent
    HANDOFF-<timestamp>.md ← timestamped copy
  usage-cache.json
  pending-transfer.json

Supported Agents

Agent Integration Detection
Claude Code SessionStart, UserPromptSubmit, PreToolUse hooks OAuth token → Claude usage API
Codex baton codex wrapper ~/.codex/sessions/**/rollout-*.jsonl token_count.rate_limits events
Cursor Transcript fallback Hard-limit error text in transcripts
Gemini CLI Transcript fallback Hard-limit error text in transcripts

Claude and Codex have proactive detection — Baton knows you're near the limit before it's hit. Cursor and Gemini rely on hard-limit text appearing in transcripts.


Commands

Command Description
baton init Install global config and Claude hooks for the current project
baton usage --from <agent> Print current usage-limit status
baton guard --from claude --hook Claude hook driver (called automatically)
baton codex [-- <args>] [prompt] Launch Codex with usage preflight
baton handoff --from <agent> Manually capture task state and write a handoff
baton handoff --from <agent> --file <path> Register a Markdown handoff written by the agent
baton pickup [--to <agent>] Launch next agent with the handoff
# Check usage
baton usage --from claude
baton usage --from claude --json       # machine-readable
baton usage --from claude --refresh    # skip cache

# Codex wrapper
baton codex                            # bare launch with preflight
baton codex "finish the login flow"    # with initial prompt
baton codex -- --model o4-mini        # pass codex flags

# Handoff
baton handoff --from codex
baton handoff --from claude --reason rate-limit
baton handoff --from claude --reason rate-limit --file /tmp/baton-handoff.md
baton handoff --from claude --launch   # write + immediately run pickup

# Pickup
baton pickup                           # choose agent interactively
baton pickup --to claude
baton pickup --to codex

Configuration

Global config lives at ~/.config/agent-baton/config.json. Per-project overrides (never committed) at .baton/config.json. baton init adds .baton/ to .gitignore automatically.

{
  "agents": {
    "cursor":  { "enabled": true, "priority": 1 },
    "claude":  { "enabled": true, "priority": 2 },
    "codex":   { "enabled": true, "priority": 3 },
    "gemini":  { "enabled": true, "priority": 4 }
  },
  "limits": {
    "mode": "ask",
    "handoff_percent": 95,
    "warning_buffer_percent": 5,
    "auto_handoff_on_hard_limit": true,
    "windows": {
      "claude": {
        "five_hour": { "enabled": true, "handoff_percent": 95 },
        "weekly":    { "enabled": true, "handoff_percent": 98 },
        "extra":     { "enabled": true, "handoff_percent": 95 }
      },
      "codex": {
        "five_hour": { "enabled": true, "handoff_percent": 95 },
        "weekly":    { "enabled": true, "handoff_percent": 95 },
        "unknown":   { "enabled": true, "handoff_percent": 95 }
      }
    }
  },
  "usage_cache": {
    "safe_ttl_ms": 900000,
    "approach_percent": 50,
    "approach_ttl_ms": 300000,
    "near_limit_ttl_ms": 0,
    "near_limit_percent": 75,
    "pretool_ttl_ms": 60000,
    "notify_cooldown_ms": 900000
  },
  "usage_sources": {
    "claude": {
      "oauth_credentials_path": "~/.claude/.credentials.json"
    }
  },
  "handoff_extraction": {
    "max_transcript_lines": 100,
    "include_git_diff": true,
    "max_diff_chars": 8000,
    "scan_secrets": true
  }
}

Key options:

Key Default Description
limits.mode "ask" ask — prompt before acting; auto_handoff — write immediately; warn_only — log only
limits.handoff_percent 95 Hard threshold
limits.warning_buffer_percent 5 Warning band starts this many points below handoff_percent (default: warns at 90%)
limits.auto_handoff_on_hard_limit true Auto-write handoff when hard-limit text appears
usage_cache.safe_ttl_ms 900000 Cache TTL below approach_percent (15 min)
usage_cache.approach_percent 50 Usage % where 5-min approach TTL kicks in
usage_cache.approach_ttl_ms 300000 Cache TTL from approach_percent to warning band (5 min)
usage_cache.near_limit_ttl_ms 0 Cache TTL inside warning band; 0 = always fresh
usage_cache.pretool_ttl_ms 60000 Min interval between fresh API fetches on PreToolUse
usage_cache.notify_cooldown_ms 900000 Legacy setting; Claude prompts are now limited by per-session notification state
handoff_extraction.max_diff_chars 8000 Per-file diff truncation cap

Environment overrides: AGENT_BATON_CONFIG_HOME, AGENT_BATON_STATE_HOME, XDG_CONFIG_HOME, XDG_STATE_HOME.


Troubleshooting

No Codex usage found Start or continue a Codex session so it emits token_count.rate_limits events into its rollout JSONL. Baton reads from ~/.codex/sessions/**/rollout-*.jsonl.

Claude usage unavailable Ensure Claude Code is OAuth-authenticated and ~/.claude/.credentials.json exists. Run baton usage --from claude --refresh to force a fresh fetch.

Pickup says agent missing The target CLI is not on PATH. Install it or check your shell config.

Hooks not firing Re-run baton init. Check that ~/.claude/settings.json contains Baton guard hooks under hooks. Codex hooks live in ~/.codex/hooks.json.


Current Limits

  • Context-window fullness is not monitored — Baton only handles usage-limit signals.
  • Cursor and Gemini CLI have partial support — proactive detection requires hard-limit text to appear in transcripts.
  • There is no automatic agent exit. Baton warns, writes the handoff, then you exit the current agent and run baton pickup manually.

License

MIT — see LICENSE.

About

Don't stop by an agent limit

Topics

Resources

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages