New
Apps 195Makers 195This week 195
Promote your app−30%
Leg screenshot 1
2views in
the last 30 days

Leg

Usage-limit monitor and automatic handoff for Claude Code, Codex, agy and Grok. leg claude runs the

Built with Claude/Claude Code/Codex/Antigravity

by ucsandman-3 · from USUnited States · added Oct 29, 2026
no ratings0 comments
Open app Code

Leg

Type leg claude, leg codex, leg agy or leg grok instead of the bare command. You get the same interactive agent; Leg opens a board next to it, watches the usage limit, keeps a handoff bundle current, and when the limit hits it starts the next agent in the same terminal from that bundle.

The Leg board mid-handoff: claude's terminal row changes to "handing off" and reads "handing off to codex, 5h limit reached", while the codex row above it shows what it landed on main

Claude hits the five-hour wall. The terminal reads handing off to codex, and codex carries on there. Nothing is retyped. (the full 53-second run)

The Leg board at 1280px: a headline naming the terminal that has waited on you longest; under it a capacity strip with claude at 63 percent of its fable week, codex back on Saturday, agy with no figure and grok with no reading, and a button that opens the login panels; then four terminal rows, each with its status, repo and branch, uncommitted and unpushed counts, agent and model, the prompt, the one thing worth knowing and its buttons; then the one-line field for starting a background task, joined to the panel; then counts for finished terminals, what landed, conversations and finished cards

You keep using your coding agents exactly as you do today, in any terminal, from your own config directory: Leg adds its hooks in a separate per-session settings file. Client approval and trust behavior is preserved by default. Permission bypass requires explicit opt-in. Client config writes require the separate folder-trust opt-in or portable harness. leg claude --model opus is claude --model opus with four things running alongside it:

  1. A board. Opened once in your browser, reused after that. Every Leg session in every terminal is a row on it, and the row's register reads status, repo on branch, uncommitted and unpushed counts, agent and model, and how long it has been quiet: waiting on you leg on main dirty 3 ahead 2 claude/fable. Under that come the prompt, the one thing worth knowing, the files it is touching and the usage bucket that will stop it. Capacity is one strip at the top rather than a region, with the login panels and their gauges behind Capacity and models. Two sessions editing the same file in one repo are flagged on both rows, and a second session in a checkout that already has one gets its own worktree and a Land button instead of writing over the first.
  2. Usage tracking per agent and account, from what each CLI already exposes: Claude Code's usage endpoint and its StopFailure hook, Codex's read-only app-server rate-limit read, agy's log, and Grok's billing proxy endpoint.
  3. A context handoff bundle (context-handoff-bundle) refreshed as the session goes, so the work is always ready to hand off.
  4. The handoff itself. Near the limit you get a warning. At the limit Leg saves the bundle, stops the agent, and starts the next option in the same terminal from that bundle. The options are a ladder of rungs, and a rung is an agent, a login and a model: the default is claude/fable, claude/opus, claude/sonnet, then each remaining installed agent. A Fable limit walls Fable and not the login, so the first move is usually to another model on the same subscription, and for claude that move is claude --resume <id> --model opus, which keeps the conversation instead of replaying the bundle. Only when every claude rung is out does it move to another CLI. Settings holds the ladder for new terminals, leg ladder edits it from a shell, and Details on a row edits the copy that terminal is running. Nothing is retyped. When every rung is out, Leg tells you which resets first and when, waits for that reset with a countdown, and starts that agent from the bundle.

Subscription logins only: Leg strips ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL, ANTHROPIC_CUSTOM_HEADERS, OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_API_BASE, GEMINI_API_KEY, GOOGLE_API_KEY, GOOGLE_GEMINI_BASE_URL, GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_GENAI_USE_ENTERPRISE, GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_LOCATION, GOOGLE_APPLICATION_CREDENTIALS, GROK_API_KEY, XAI_API_KEY, CLAUDECODE, CLAUDE_CODE_*, CLAUDE_EFFORT, and CLAUDE_PLUGIN_DATA before any agent starts. It then sets CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0 for a detached Claude print session. Leg's hooks ride in a separate per-session --settings file. Automatic folder-trust writes are off by default; LEG_TRUST=auto opts into the client config changes below. The optional portable harness can also write client configuration, only after leg harness enable. leg uninstall removes only ~/.leg; it does not remove existing client trust answers.

The folder-trust answer

Each agent CLI asks once, the first time it runs in a directory, whether you trust that folder, and Claude Code asks a second question when a CLAUDE.md above the repo imports a file from outside it. These prompts remain in place by default, including during handoffs. An unattended handoff may wait for you.

Set LEG_TRUST=auto only if you want Leg to record trust before agent launches and handoffs. This is independent of auto-approve mode and authorizes these client config writes, including approval of external CLAUDE.md imports:

agent file what is written
claude ~/.claude.json (or $CLAUDE_CONFIG_DIR/.claude.json) projects["<repo>"].hasTrustDialogAccepted: true
claude the same entry, only when such an import exists hasClaudeMdExternalIncludesApproved, hasClaudeMdExternalIncludesWarningShown
codex ~/.codex/config.toml [projects."<repo>"] trust_level = "trusted"
agy ~/.gemini/antigravity-cli/settings.json trustedWorkspaces: ["<repo>", "<worktree>"]
agy ~/.gemini/config/projects/default-cli-project.json writable Git folder resources
agy existing ~/.gemini/trustedFolders.json TRUST_FOLDER entries

For Claude Code this is the documented remedy: its permissions guide says to set projects["<path>"].hasTrustDialogAccepted to true in ~/.claude.json, where <path> is the repository root.

Claude and Codex trust updates require an existing config file. agy can create its settings or project file when the corresponding config directory already exists. Existing trust decisions are retained. When Leg approves an external CLAUDE.md import it prints the full path of every file it approved, to the terminal and to the session timeline on the board, so the approval is on the record rather than invisible.

LEG_TRUST=never disables future trust writes; it does not revoke trust already recorded. Unset, empty and unrecognized values also leave automatic trust off. The legacy BATON_TRUST=auto opt-in remains supported when LEG_TRUST is unset.

Contents

60-second run

Prerequisites: Node 22 or newer, git, Python 3 with pip, and at least one logged-in agent CLI (claude, codex, agy or grok).

npm install -g @ucsandman/legcli
pip install -U context-handoff-bundle
cd <any repo>
leg claude

npm install -g leg-agents is the same release: it pins this version of @ucsandman/legcli and exposes the same leg binary.

That is the whole setup. The first leg <agent> starts the board on http://127.0.0.1:4747 and opens it; later sessions reuse it. Anything after the agent name passes straight through (leg codex -m gpt-5.3-codex-spark, leg claude --resume). The agent's own prompt and permission flags pass through unchanged. Leg adds no permission bypass by default; --auto-approve opts in and --no-auto-approve overrides a saved opt-in for that terminal. Leg's hooks ride in a separate per-session --settings file. Folder-trust and portable-harness writes each require their own opt-in.

Leg is commercial, source-available software, and the source is on GitHub: every .mjs file that runs is in the package you just installed, at $(npm root -g)/legcli/src, and the license lets you read it and modify your own copy. There is nothing compiled, minified or bundled to see through.

What Leg reads from each agent

Nothing is guessed from screen scraping. Each tap was read from the CLI's source or documentation and then checked on a real machine (2026-09-11, Claude Code 2.1.268, codex-cli 0.153.4, agy 1.2.0); the rightmost column says which.

agent usage percentages the wall (limit hit) how Leg attaches status
claude GET api.anthropic.com/api/oauth/usage with the login Claude Code stored, the same data as /usage and the built-in status line (five_hour, seven_day, utilization, resets_at); polled every 60 s StopFailure hook with error: rate_limit (docs) one extra settings file per session via --settings, carrying only Leg's own hooks; autoContinueAtUsageLimit is set to false because Leg owns the handoff observed live
codex read-only account/rateLimits/read through the app-server, polled every 60 s by the board and active attach; windows are identified by duration (300 minutes = 5h, 10080 = 7d) task_complete.error.codex_error_info: usage_limit_exceeded, message "You've hit your usage limit … try again at …" (codex-rs/protocol/src/error.rs) no model turn and no hook are injected; the board reads the CLI backend and records only returned windows verified by source and regression tests
agy none exposed (agy's own status line fetches a quota summary that is written nowhere) RESOURCE_EXHAUSTED, "it resets in …", "out of quota" in the log --log-file per session; ~/.gemini/antigravity-cli/history.jsonl gives the prompts and conversation id observed live (a real RESOURCE_EXHAUSTED with its reset was read from the log on 2026-09-11)
grok GET cli-chat-proxy.grok.com/v1/billing?format=credits and GET cli-chat-proxy.grok.com/v1/user?include=subscription with OAuth token from ~/.grok/auth.json (creditUsagePercent, currentPeriod weekly reset); polled every 60 s -32003 rate limit error, "You've hit the rate limit for your plan. Try again later.", "Rate limited (429)", StopFailureKind::RateLimit (xai-org/grok-build) --debug-file grok.log per session; ~/.grok/sessions/<encoded-cwd>/prompt_history.jsonl gives prompts and session id verified by source and proxy endpoint

Why not Claude Code's status line JSON (rate_limits.five_hour.used_percentage): on 2.1.268 the custom statusLine Leg passes through --settings did not run, so the endpoint poll is the source. Leg still writes a statusLine entry that records the same fields, so the moment a build honours it the poll becomes a fallback.

For Codex, Leg does not infer availability from a lower percentage: only an explicit available answer from the backend clears an earlier wall. The board labels each bar as <n>% used and marks an old reading as stale rather than presenting it as current.

How a handoff works

  1. Warning. At 85 % of any window (LEG_WARN_PCT) the session card turns amber, the event log names the next option, and the terminal bell rings once.
  2. Limit. claude: the StopFailure hook fires with rate_limit. codex: the rollout reports usage_limit_exceeded. agy: the log says RESOURCE_EXHAUSTED. The account is marked walled until the reset the CLI reported (or the soonest known window reset).
  3. Bundle. Leg writes structured notes (task, the last messages from the transcript, git diff --stat, dirty files, files edited this session, recent commits, why it stopped) and runs context-handoff-bundle save --repo-local with one slug per session, updated in place (--update <slug>) at every checkpoint, about every two minutes while the session is active, and at every warning, limit and hand-off. If the session maintained .leg/SYNTHESIS-<session-id>.md, Leg inlines it into the resume file as a ## Synthesis section ahead of the raw dump.
  4. Switch. The agent process is stopped and the terminal is restored. Two claude destinations keep the conversation itself instead of the bundle: a weaker model on the same login (claude --resume <id> --model <alias>), and another claude login you added with leg accounts add, which sees the same transcript through the projects junction the account carries (claude --resume <id> under that login's CLAUDE_CONFIG_DIR). A weekly or Fable wall on one login then continues on the other with the conversation it already had, and the timeline says kept the conversation. Every other rung starts in the same terminal with a short pointer prompt: read .leg/RESUME-<session-id>.md (the context-handoff-bundle load output, the ## Synthesis section if present, and the reason for the switch), check git status and git diff, continue, do not ask the human to restate the task. The pointer prompt directs the next agent to read Synthesis first, treat ruled-out approaches as settled, and start from the top-ranked next step. The same text is copied to .leg/RESUME.md, the file people open by habit, and both are stamped with the commit and the live terminals they describe. claude "<prompt>", codex "<prompt>" and agy -i "<prompt>" all open the normal interactive session with that first turn.
  5. The ladder. A rung is an agent, a login and a model, and Leg walks from rung 1 every time. Other models on the same login come first, then other accounts of the same agent, then every other agent in the saved order, each tried once. It is a priority list, not a rotation: put agy at the bottom and agy is the last rung from a Claude terminal and from a Codex terminal alike. The board prints the exact sequence with the rung running now marked, plus the first rung eligible from current install and limit state. Use Change the ladder in a terminal's expansion to change that terminal, leg ladder to do it from a shell, or Settings to set the default copied by new terminals. A rung whose CLI is missing, whose wall has not reset, or that shares the window that is already out, is skipped with its reason.
  6. All out. The terminal prints each option with its reset time, soonest first, then stays open with a countdown to the first reset and starts that agent from the bundle when it arrives. The row says waiting for <agent> at <time>. Ctrl-C (or End on the row) quits with exit 3 instead.

You can force a handoff any time: the Hand off now button on the row, or leg sessions handoff <id>. Verified on this machine: leg claude opened the real Claude Code TUI with Leg's hooks firing into the session log, the usage poll recorded 36 % of the 5h window and 74 % of the 7d window, the warning fired at 96 % of the 7d window and named codex as the next option, and a limit saved the bundle, stopped claude and started codex in the same terminal with the pointer prompt. A real StopFailure arrived on 2026-09-11 and is kept at fixtures/live/claude/limit-rate_limit.json; to drive the path on demand, leg sessions simulate-limit <id> sends the same StopFailure rate_limit payload Claude Code would send through Leg's hook: verified end to end on a haiku session, the hook set the limit, the runner saved the bundle, stopped claude and started codex, which read .leg/RESUME.md on its first turn. The simulated wall clears after two minutes and is never kept as evidence. The first real StopFailure was saved that way, with secrets scrubbed, at fixtures/live/claude/limit-rate_limit.json, and the claude docs row flipped to observed-live (node scripts/live-limits.mjs). The same capture is wired for codex usage_limit_exceeded and agy RESOURCE_EXHAUSTED; no payload for either has been kept yet.

Terminals started by this version can change their ladder while they run: Settings holds the default for new terminals, and Details on a row edits the copy that terminal is running. An older terminal stays on the order it started with; its row says a restart is needed and can save the desired default for the next launch. A normal agent exit ends the terminal. It does not trigger a handoff.

The working environment travels too (optional)

With the portable harness enabled (leg harness enable, off by default), the hand-off also prepares the destination's environment before it starts: the source agent's global rules, identity, hooks, skills, subagents, slash commands, MCP servers and permissions, rendered into the destination's own files as far as it can represent them. The terminal then reads, for instance, codex harness partial · 8/8 components, 3 dropped · 1 file(s) written, and the terminal's details list what was dropped and why. The source is fingerprinted so an unchanged environment costs a few stat calls; a policy (warn, sync, strict) says whether a hand-off may write, and strict refuses a destination it cannot make safe. Credentials never move and which login runs stays the account layer's decision.

Two sessions in one repo

Two agents in one working tree write over each other's files. So when you start leg codex in a checkout where leg claude is already live, the new session gets its own git worktree, <repo>/.leg-worktrees/<session-id> on branch leg/<session-id>, cut from the branch the checkout has out, and the terminal prints one line saying where it is. The agent starts there; the card, the usage tracking and the handoff work the same. --no-worktree shares the checkout on purpose (Leg takes the flag out; the agent never sees it).

The card of a session with its own worktree has a Land button. It sends the branch through the merge queue: whatever the agent left uncommitted is committed on the branch, the branch is rebased onto its base, the repo's test command runs (package.json test, pytest, or none with a warning), and the base is fast-forwarded, never merged. When a step fails nothing lands and the card says why: rebase-conflict with the files, tests-red with the end of the output, dirty-trunk when the checkout has local changes the landing would overwrite. Local changes it would not touch are left alone. The landed-on-trunk list says which terminal landed each commit. Remove safely prunes a finished session only when its worktree is clean and its branch is already on the base. Remove record is a separate visible button with a confirmation: it removes only Leg's saved s

Description taken from the repository README.

Ratings

–
0 ratings
5 0
4 0
3 0
2 0
1 0

Rate this app

Sign in to rate

Comments 0

Sign in to comment

No comments yet.

Related apps

#agent-harness · #codex · #coding-agents