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:
~/.codexis 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 unlesscodex_homesorSUBFLEET_CODEX_HOMESsupplies 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:
accountsandenrolled: the Claude roster and its secret item names.codex_homes:nullfor 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 implementingget NAME,set NAMEwith the value on stdin, anddel NAME. When unset, subfleet uses macOSsecurity.notify_cmd: an argv prefix receivingSUBJECT BODY; the complete message is also sent on stdin. When unset, alerts go to stderr.mirror_heartbeat,mirror_job_label, andmirror_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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9b9420a9cffa27de6093c1e56ac3d2dd87a2a4f245c8d0235b10630c4680e37f
|
|
| MD5 |
28562e6cc3050bc6b399308e1439223c
|
|
| BLAKE2b-256 |
66cbef0aeeba8bb9ae32b205046213cf284352622269ad9ee6e188c196e8ff81
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1c08d87a46563b157024aa324603012058caf1be83379325fdba62076ca5611
|
|
| MD5 |
c0a9671d7d4c5ea96760137ca4d2b864
|
|
| BLAKE2b-256 |
53e2959cf73e7092f34ad571fab0729388ad472be009f4823b533cc055f7b273
|