cyberine
UsageRun recipes

Retiring a worker — RETIRED_WORKERS

A worker whose account is unfunded or ineligible is not the same as a worker with no credential, and Cyberine used to have no way to say so. An out-of-balance account still holds a VALID key, so every availability probe passed, the worker was registered, dispatched, and only then failed on the provider's billing error — burning a dispatch slot on every run, indefinitely. RETIRED_WORKERS in src/core/workerProfiles.ts is the operator's recorded answer to that.

Retired (mirrors RETIRED_WORKERS; the source is the authority):

WorkerProviderWhy
loop-kimi-build, opencode-kimiMoonshot / Kimiaccount out of balance
loop-minimax-build, loop-minimax-direct, mmx-text-buildMiniMax402 insufficient balance (1008)
gemini, loop-gemini-buildGooglefree-tier client revoked (IneligibleTierError), no funded paid tier
loop-muse-build (2026-09-05)Meta Model API402 billing_not_configured — key valid, no payment method
opencode2-deepseek (2026-09-06)DeepSeek (via opencode2)account out of balance — 402 Insufficient Balance
opencode-deepseek, opencode (default-compare planner) (2026-09-07)DeepSeek (via opencode)operator is dropping the opencode binaries; cyberine run replaces opencode as the one-command edit tool (ks4sf)

The gate has THREE independent entry points, because no single one covers the fleet: availableBuildWorkerIds() builds the candidate id list from scratch, routeTask() ranks candidates through sortedAvailable(), and buildDefaultAdapters() filters the assembled adapter list just before returning. cyberine doctor reports a retired worker as [WARN] <id>: RETIRED <date> — <reason> instead of the false [PASS] installed, logged in it used to print, and a provider whose workers are all retired says so on its own line while still reporting the key as present — those are two different facts and it now states both.

Bringing one back is deleting its entry from RETIRED_WORKERS. Nothing else is removed: the WORKER_PROFILES entry, the adapter, the model-catalog rows and the pricing rows all stay, and selftest:retired-workers asserts that reversibility explicitly so a future "cleanup" cannot quietly delete the profiles and make the decision one-way. Two module-load guards back it up: a retired id may not appear in CHEAP_BUILD_FLEET (it would be dispatched by cyberine run --cheap and fail on billing), and every id in RETIRED_WORKERS must be a real worker, so a typo cannot silently retire nothing.

npm run selftest:retired-workers   # offline; asserts all three gates + the reversibility contract
cyberine doctor                    # shows each retired worker and why

Known limitation / deferred work: retirement is a source-code constant, not runtime config — there is no cyberine fleet retire <id> command, and changing it needs an edit plus a restart. The provider-status line maps providers to their workers by substring with a small alias table (moonshot -> kimi, google -> gemini), because WORKER_PROFILES declares no provider-to-worker edge; that mapping is cosmetic (nothing dispatches off it) but a future worker whose id does not contain its provider name would be missed there. Retirement also does not touch fleet.json — an explicit CYBERINE_BUILD_FLEET naming a retired worker still drops it, but the config file's own validation will not warn you that the entry is now inert.