@velum-labs/routekit
v1.0.25
Published
RouteKit CLI for configuring, serving, and using model gateways.
Maintainers
Readme
@velum-labs/routekit
packages/cli publishes the independent @velum-labs/routekit npm package
and its routekit executable. It configures and serves model routes directly;
it does not start auxiliary sidecars or download local models.
Install
curl -fsSL https://github.com/velum-labs/routekit/releases/download/routekit-latest/install.sh | sh
routekit setup
routekit codexOr, with Node.js 22 or newer already on PATH: npm install -g @velum-labs/routekit.
Upgrade later with routekit self-update.
Self-update proves which installation owns the running executable before it mutates anything. It updates public-installer, npm, pnpm, Yarn Classic, Bun, and Volta installations on macOS and Linux. Homebrew, apt/dpkg, rpm/dnf, pacman, Snap, and Nix installations receive manager-specific guidance instead. Local, linked, ephemeral, ambiguous, and unknown installations are never overwritten.
routekit setup is the interactive multi-route wizard. It reads existing API
credentials from the environment, performs live discovery before writing a
fresh config, enrolls selected subscriptions, and selects a live default
model. Use routekit config init --provider <provider> or
routekit config init --empty for deterministic automation.
The singleton daemon loads ~/.config/routekit/router.yaml; replace that
canonical document from a project file explicitly with
routekit config import --from .routekit/router.yaml. Import validates and
atomically replaces the complete document; it does not merge configuration.
Embedded callers can supply one explicit complete config document.
ROUTEKIT_HOME relocates runtime state.
Local checkout development
Contributors can install a separate global routekit-dev command that always
runs their local checkout instead of the published npm package:
corepack pnpm install --frozen-lockfile
corepack pnpm dev:link-routekit
routekit-dev --versionIf the current shell previously resolved routekit-dev from another checkout,
run rehash in zsh or hash -r in bash after linking.
Run it from any project repo:
cd your-project
routekit-dev doctor
routekit-dev codexThe dev command rebuilds packages/cli before launch, preserves the
caller's working directory, uses the repository-pinned pnpm version throughout
the Turbo build, and does not replace the normal routekit binary. Set
ROUTEKIT_DEV_SKIP_BUILD=1 after a successful build for a faster local check.
Command ownership
| Command | RouteKit responsibility |
| --- | --- |
| setup | Interactively configure and verify selected API and subscription routes. |
| start, status, stop | Start, inspect, and gracefully stop RouteKit through its singleton daemon. |
| codex, claude | Ask the daemon to prepare a launch, then run the supported coding tool locally against the singleton gateway. Native arguments after -- remain owned by the native client. |
| codex install, codex uninstall | Add or remove one RouteKit-owned Codex provider/profile and its dedicated gateway token. |
| claude install, claude uninstall | Add or remove RouteKit-owned Claude Code gateway settings and a dedicated gateway token while preserving user configuration. |
| providers add, remove, status | Manage explicit providers and run live discovery without printing credentials. |
| models list | Discover and list the live namespaced model catalog. |
| models info <provider/model> | Explain the effective provider and native model, account class, billing mode, default status, capabilities, and reasoning metadata without printing credentials. |
| accounts login | Enroll a supported subscription kind (claude-code or codex), import the credential, and enable the matching provider. --no-browser prefers a device-code / copyable-URL flow for headless hosts. |
| accounts add, remove, list, status | Import the current official CLI login or manage enrolled subscription accounts. |
| usage | Show subscription rate limits, credits, banked Codex resets, and reset windows from the running daemon. |
| usage redeem | Redeem a banked Codex rate-limit reset for an enrolled account (--provider codex --label <name>). |
| config path, show, init, edit, import | Manage the daemon's canonical global router config with revision-checked writes. |
| doctor | Check router configuration, referenced credential variables, and installed coding-agent binaries. |
| self-update | Update through the verified installer or package-manager context that owns the running CLI, then verify the fresh executable, manifest, and owner context. |
| telemetry status, on, off | Control RouteKit's anonymous, opt-in product telemetry. |
| completion <bash\|zsh\|fish> | Print shell completion setup. |
| version, --version | Print the @velum-labs/routekit version. |
Global options are --json, --no-input, --yes, and --quiet.
Daemon-backed commands use the canonical ~/.config/routekit/router.yaml;
embedded and diagnostic execution can select an explicit config.
routekit usage asks the daemon-owned account pools directly.
Provider activation, live model catalogs, account relays, and registry-defined
credential environment variables are RouteKit-owned.
The first-launch subscription kinds are claude-code and codex; the Claude
Code launcher command remains routekit claude [provider/model].
Persistent native-client integration
routekit codex install
routekit claude installThe installer writes only RouteKit-owned additions to the user's real Codex or
Claude configuration. Codex receives one additive routekit profile, never a
default model change; launch it with codex --profile routekit and choose from
the RouteKit-backed model picker. Claude receives RouteKit-managed native
availableModels entries derived from the gateway catalog, so its normal
/model picker lists the policy-allowed routes without synthetic claude-*
models. The command issues a dedicated data token and stores it in macOS
Keychain (or a private 0600 RouteKit secret file elsewhere). Codex and Claude
retrieve it on demand through native credential helpers, so terminal, IDE, and
GUI launches need no shell configuration. Claude's --bare mode intentionally ignores
normal user settings, including apiKeyHelper; use a normal launch or pass its
settings file explicitly. Reinstalling the same target keeps the token;
--rotate-token replaces it. Uninstall revokes the tracked dedicated token.
Native clients own transcripts, history, resume, and deletion; RouteKit does
not track native sessions.
Pool policy uses the same provider map as API-key sources:
providers:
claude-code:
strategy: capacity_weighted
switchThreshold: 0.9
codex:
strategy: capacity_weighted
switchThreshold: 0.9
defaultModel: codex/gpt-5.6-solThe one enrollment path is routekit accounts login <kind>. The supported
claude-code and codex kinds run the official provider CLI in a private
temporary profile, atomically import the resulting credential, and remove the
temporary profile without changing the user's normal login (accounts add is
the explicit current-login import path). --no-browser prefers a device-code /
copyable-URL flow so a headless host only needs a browser on some other device.
API providers infer their key and optional base URL from registry-defined environment variables. Subscription providers discover the union of models offered by healthy enrolled accounts and keep per-account quota, refresh, cooldown, and model eligibility state. An explicitly requested unknown or unnamespaced model is rejected rather than routed to the default.
routekit models info <provider/model> is the machine-verifiable route and
billing explanation surface. Its JSON fields are id, provider,
nativeModel, accountClass, billingMode, default, capabilities, and
reasoning; unavailable reasoning metadata is reported as null. API-key
routes report api-key / metered-api, managed subscription routes report
subscription / subscription, and retained proxy routes report proxy /
upstream-managed.
First-launch support contract
RouteKit's public first-launch set is:
- API providers: OpenAI, Anthropic, and OpenRouter;
- subscriptions: Codex and Claude Code; and
- harnesses: Codex CLI
0.146.0and Claude Code2.1.216or2.1.220.
Read the per-route credential, billing, egress, failover, and limitation disclosures and the exact client compatibility contract before enabling a route. Unlisted client versions are unqualified, not necessarily incompatible. OpenRouter is an aggregator; API-key and subscription routes have different billing and quota boundaries.
Public support remains conditional on L06 qualification. Additional internal providers, connectors, and tool integrations are not first-launch UX, are not qualified, and are not a support contract.
Singleton daemon
Every product command is a thin client of one daemon per ROUTEKIT_HOME.
The daemon owns:
- a private, random-token-authenticated
control.v2listener on loopback; - one stable OpenAI-compatible gateway listener;
- the canonical config, provider discovery/cache, subscription account pools, usage, and telemetry state; and
- transactional router generations. Config/account changes build and validate a replacement router first, atomically switch new traffic, then drain the old generation so active LLM streams finish.
accounts login and accounts add use one accounts.enrollActivate control
mutation. OAuth capture is isolated from daemon-owned stores; the daemon keeps
a private rollback vault while it commits account files, provider config,
account/config revisions, and the router generation. An error restores prior
state, and startup rolls back any prepared transaction before loading config.
Committed retries are no-ops. Status and doctor report sanitized recovery and
account/provider consistency without returning transaction credentials.
Help, version, completion, terminal rendering, OAuth/editor interaction, and
the final coding-tool process remain local. Interactive results are committed
back through authenticated RPC, so the daemon remains the sole RouteKit state
writer. Project .routekit/router.yaml files are SDK/embedded-router inputs,
not standalone daemon scopes. To use one as the singleton configuration,
explicitly replace its canonical document:
routekit config import --from .routekit/router.yamlThe first product command race-safely ensures the singleton exists. Where a systemd user manager or launchd is available it installs/starts the persistent unit; unsupported container/WSL environments use the documented detached fallback. Users do not need to select foreground, detached, or supervised operation. The public lifecycle is:
routekit start
routekit status
routekit stopstart is idempotent and uses the same daemon bootstrap as every product
command. It writes routekit-daemon.service / the launchd agent when an OS
supervisor is available (with lingering on Linux so it survives logout and
reboot), starts it, and verifies authenticated control health before printing
the data URL.
Supervised installs capture an explicit provider environment. Direct API providers use their registry-defined credential variable and pin either the custom base URL supplied at install time or the registry default. Native-client credentials and endpoint overrides for subscription providers such as Codex and Claude Code are removed before daemon startup; those providers authenticate through RouteKit-managed account files instead. RouteKit does not modify the launchd GUI domain or systemd manager environment.
On systemd, captured values are stored in private
~/.routekit/env/daemon.env (mode 0600); launchd stores them in its private
agent plist. routekit daemon restart rolls the request-serving worker inside
the existing service process, and daemon reload reloads router/account state,
so neither command refreshes
provider environment. After changing a provider key or base URL, run
routekit daemon service install to recapture the contract. Existing services
created before this isolation contract also need one reinstall after upgrade;
routekit doctor warns when it detects one. The gateway bearer is generated
into ~/.routekit/secrets/data-token (0600) and never appears in status, logs,
or process arguments; routekit daemon auth show reveals it only when
explicitly requested for an external HTTP client. Where no init supervisor
exists (containers, some WSL setups), start falls back to a detached daemon.
Advanced lifecycle operations
routekit daemon reload
routekit daemon restart
routekit daemon upgrade
routekit daemon logs -f
routekit daemon service install
routekit daemon service status
routekit daemon service uninstallThe hidden daemon command group is available for repair and diagnostics.
daemon service install rewrites a moved
systemd/launchd unit. The only foreground entrypoint is the internal
daemon run, which supervisors and the detached spawner execute; it is not a
user workflow.
Lifecycle command boundary
Use routekit start, routekit status, and routekit stop for normal
operation. routekit daemon service install is reserved for unit repair,
inspection, removal, or recapturing provider environment. External clients read
the gateway URL from routekit status and the data token from
routekit daemon auth show.
Import project configuration with
routekit config import --from .routekit/router.yaml; the singleton never
silently adopts a project overlay.
Graceful shutdown and rolling upgrades
routekit stop is a full drain: /health flips to 503, new requests are
rejected, and in-flight requests (long-lived LLM streams) get up to the drain
grace (default 30s; --drain-grace <seconds> or ROUTEKIT_DRAIN_GRACE) before
the listener is severed.
routekit daemon restart and routekit daemon upgrade use a stable cluster
primary and roll one active worker. The data URL, public port, control port, and
host PID remain unchanged. The candidate loads and validates state on the same
shared ports, commits atomically, and only then retires the previous worker.
Requests already admitted by the previous worker may finish during the drain
grace; new connections reach the committed worker without an intentional
ECONNREFUSED or 503 interval. Candidate startup, synchronization, version, or
readiness failure leaves the previous worker active.
After installing a new @velum-labs/routekit, the next product command negotiates
the package/protocol version and gracefully restarts an older daemon before
retrying. The explicit form is:
routekit daemon upgraderolls the worker to the installed CLI entrypoint. upgrade --force performs the
same roll without version skew. systemd and launchd keep the supervised primary
running throughout.
The zero-downtime guarantee does not cover routekit stop, machine reboot,
host-process crash, manual supervisor restart/bootout, listener/Portless/owner
token path changes, or an incompatible host-protocol upgrade. Those operations
require a hard lifecycle transition and may restart the listener.
