Skip to main content

subfleet

A fleet of subs. Formerly ai-lanes, then carpool (renamed 2026-08-23; CARPOOL_* environment variables are still honoured).

subfleet runs agentic work across several Claude Code and Codex subscriptions without repeatedly replacing one login — the subs operate under the surface. Each subscription gets a lane, the router selects a lane with usable capacity, and the hardened runners can move to another lane when a provider reports a limit.

The Python package has no runtime dependencies outside the standard library. The shell runners expect Python 3.12 or newer; the Claude runner also uses jq and uuidgen. The default secret store is the macOS keychain, but a portable secret-store command can be configured.

Quick start

uv sync
mkdir -p ~/.config/subfleet
cp accounts.example.json ~/.config/subfleet/accounts.json
export PATH="$PWD/bin:$PATH"
subfleet status

Edit ~/.config/subfleet/accounts.json before enrolling or dispatching. The committed accounts.example.json contains only reserved example addresses and documents the supported public settings.

Lanes

Codex keeps one login per home directory:

  • ~/.codex is the desktop app's home. subfleet observes its account and live capacity, but never treats it as a dispatch lane.
  • ~/.codex-1, ~/.codex-2, and so on are dispatch lanes. They are discovered automatically unless codex_homes or SUBFLEET_CODEX_HOMES supplies an explicit list.
  • A numbered lane bound to the desktop app's current account is shadowed. It remains visible but receives a dispatch handicap, and the watchdog warns only when the shadow state changes.
  • A Codex account reporting the free plan is excluded from dispatch.

Log into a numbered lane or the separately observed app home with:

subfleet login codex 1
subfleet login codex app

The command starts the vendor login server in that home, opens its authorization URL, and arms a detached watcher. On completion, the watcher checks that numbered lanes contain distinct accounts, reports app shadows, refreshes the snapshot, and uses the configured notification hook. --no-open prints the URL; --no-watch skips the completion watcher.

Claude lanes are the addresses in accounts, mapped to secret-store items by enrolled. Create and store a setup token without placing it in argv or an environment variable:

claude setup-token | subfleet enroll user1@example.com

Enrollment makes a one-time validation request and accepts the authorization responses expected from an inference-only setup token. Routine status and dispatch never use stored setup tokens as quota-observation credentials. Instead, the Claude runner records transcript token totals in a private local ledger and learns cooldowns from actual hard-limit responses.

Commands

Command Purpose
subfleet status [--json] [--cached] Show account identity, quota, authentication, shadow, and health state. With no subcommand, status is the default.
subfleet capacity [--json] Normalize five-hour and weekly headroom across both providers.
subfleet pick codex Print the best dispatchable Codex home.
subfleet pick claude Print the best enrolled Claude address.
subfleet run Classify a task, select a provider and lane, and invoke a hardened runner.
subfleet codex Run hardened codex exec; -H is optional and omitted lanes are selected automatically.
subfleet claude Run hardened headless Claude Code with -A auto-selection or -a EMAIL pinning.
subfleet login codex N|app Perform the Codex re-login ritual for one numbered lane or the app home.
subfleet enroll EMAIL Read a Claude setup token from stdin and store it through the secret-store abstraction.
subfleet mirror Run one Claude desktop-session mirror pass; accepts --list, --dry-run, --prune, and the mirror's other options.
subfleet errors Show recently observed provider limit and authentication errors.
subfleet watch [--dry-run] Take one snapshot, evaluate health transitions, and send or print alerts.
subfleet brief Print a compact Markdown capacity section.
subfleet runs Inspect the durable prompt/output/error ledger; runs show ID displays one run.

Use subfleet COMMAND --help for monitor and router options. The pass-through runners intentionally retain their concise shell usage strings.

Dispatch

The router accepts prompt text or -p PROMPTFILE and can explain its decision:

subfleet run --why -C /path/to/project -o result.md "Fix the failing retry test"
subfleet run --dry-run -p task.md

Its transparent pattern rules classify prose and final-judgment work, reviews, mechanical sweeps, and general build work. It chooses a model family, consults the shared capacity view, records the decision, and can cross from Codex to Claude when the default family has no dispatchable lane. Explicit -H and -a options pin a resource. -m, -t, -s, -d, and -b provide model, task-class, sandbox, detached-run, and salvage-branch overrides.

The provider runners are also available directly:

subfleet codex -m MODEL_NAME -C "$PWD" -p task.md -o result.md
subfleet claude -A -m MODEL_NAME -C "$PWD" -p task.md -o result.md
subfleet claude -a user1@example.com -m MODEL_NAME -C "$PWD" -p task.md -o result.md

An unpinned Codex run auto-picks a home and re-picks after a mid-run usage limit. An auto-selected Claude run does the same after a hard limit; lanes with a missing stored token are excluded before launch. Both runners retry transient failures, record each attempt, and can snapshot dirty Git state to dedicated salvage refs without moving HEAD or the real index. Claude additionally records lane usage and writes a MODEL-DOWNGRADE marker when the transcript shows silent model substitution.

Adding this repository's bin directory before the vendor Codex binary also enables the bin/codex shim. It selects a lane for headless exec, e, and review calls when CODEX_HOME is unset. Set SUBFLEET_NO_AUTOPICK=1 to opt out; interactive commands and explicit homes pass through unchanged. subfleet resolves the real Codex executable without depending on scheduler PATH.

Monitoring and repair

subfleet watch is a single pass suitable for cron or another scheduler. It persists snapshots and transition state under ~/.local/state/subfleet by default. Alerts cover exhausted or unauthenticated lanes, free-plan accounts, new app shadows, fleet exhaustion, and mirror health without repeating an unchanged condition every pass.

The session mirror writes its per-pass result to the configured heartbeat sidecar. The watchdog tolerates a currently running pass, distinguishes a stale heartbeat from an in-flight run, and treats a run older than 30 minutes as hung. When configured, mirror_restart_cmd is included in the alert's recovery guidance.

For a Codex lane whose live quota request returns the narrow expired-token signature, the watchdog may ask the vendor CLI to refresh its own credentials and then re-probe. Repair is guarded by a renewable lock lease, bounded by a timeout, disabled during dry runs, and latched after definitive revocation until a new login changes the authentication file. subfleet never writes a Codex access token itself.

Configuration

The default configuration file is ~/.config/subfleet/accounts.json. Important keys are:

  • accounts and enrolled: the Claude roster and its secret item names.
  • codex_homes: null for numeric-home discovery, or an explicit list.
  • codex_app_home: the observed desktop-app home.
  • protected_account: an optional identity fallback used only when the app home cannot provide its current account.
  • secret_store_cmd: an argv prefix implementing get NAME, set NAME with the value on stdin, and del NAME. When unset, subfleet uses macOS security.
  • notify_cmd: an argv prefix receiving SUBJECT BODY; the complete message is also sent on stdin. When unset, alerts go to stderr.
  • mirror_heartbeat, mirror_job_label, and mirror_restart_cmd: optional mirror and scheduler integration.
  • login_browser_cmd: a browser argv prefix. A {url} placeholder is replaced; otherwise the URL is appended.
  • login_refresh_cmd: a snapshot-refresh argv command run after login.

Command settings may be JSON argv arrays or shell-like strings parsed into argv; they are never executed as shell expressions.

Common environment overrides are SUBFLEET_CONFIG_DIR, SUBFLEET_STATE_DIR, SUBFLEET_CODEX_HOMES (colon-separated on macOS/Linux), SUBFLEET_CODEX_APP_HOME, SUBFLEET_CODEX_BIN, SUBFLEET_CLAUDE_DIR, SUBFLEET_CLAUDE_JSON, SUBFLEET_SECRET_NAME_PREFIX, SUBFLEET_SECRET_STORE_CMD, SUBFLEET_NOTIFY_CMD, SUBFLEET_MIRROR_HEARTBEAT, SUBFLEET_MIRROR_JOB_LABEL, SUBFLEET_MIRROR_RESTART_CMD, SUBFLEET_LOGIN_BROWSER_CMD, SUBFLEET_LOGIN_REFRESH_CMD, and SUBFLEET_CODEX_GUARD=off for an explicit one-run guard bypass.

subfleet does not embed secrets or local account identifiers in repository files. Runtime ledgers are created in the configured state directory with private permissions; runner output is written only to the path you request.

Codex command guard

subfleet codex preflights a portable Codex PreToolUse hook before launch. The hook covers four generic local-machine and Git hazards: unscoped root searches, decrypted keychain dumps, stash mutation in shared worktrees, and new local branches made from a stale local main branch. See docs/guard.md for the exact policies, trust checks, and the explicit one-run bypass.

Development

uv run pytest -q

License

Apache-2.0. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

subfleet-0.0.1.tar.gz (152.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

subfleet-0.0.1-py3-none-any.whl (84.6 kB view details)

Uploaded Python 3

File details

Details for the file subfleet-0.0.1.tar.gz.

File metadata

  • Download URL: subfleet-0.0.1.tar.gz
  • Upload date:
  • Size: 152.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for subfleet-0.0.1.tar.gz
Algorithm Hash digest
SHA256 9b9420a9cffa27de6093c1e56ac3d2dd87a2a4f245c8d0235b10630c4680e37f
MD5 28562e6cc3050bc6b399308e1439223c
BLAKE2b-256 66cbef0aeeba8bb9ae32b205046213cf284352622269ad9ee6e188c196e8ff81

See more details on using hashes here.

File details

Details for the file subfleet-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: subfleet-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 84.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for subfleet-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b1c08d87a46563b157024aa324603012058caf1be83379325fdba62076ca5611
MD5 c0a9671d7d4c5ea96760137ca4d2b864
BLAKE2b-256 53e2959cf73e7092f34ad571fab0729388ad472be009f4823b533cc055f7b273

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page