Skip to content

Repository files navigation

 ██████  ███    ███ ██████         ██████   ██████  ██    ██ ████████ ███████
██    ██ ████  ████ ██   ██        ██   ██ ██    ██ ██    ██    ██    ██
██    ██ ██ ████ ██ ██████  ██████ ██████  ██    ██ ██    ██    ██    █████
██    ██ ██  ██  ██ ██             ██   ██ ██    ██ ██    ██    ██    ██
 ██████  ██      ██ ██             ██   ██  ██████   ██████     ██    ███████

────────────────────────────────────────────────────────────────────────────
 routing plan compiler for Oh My Pi   ::   discover → gate → rank → compile
────────────────────────────────────────────────────────────────────────────

Keep the task moving when a provider stops.
Discover equivalent models, rank available providers, and compile safe fallback chains for Oh My Pi.

MIT License Node.js 22 or newer Zero runtime dependencies CI status CodeQL status Proof of concept

Problem · Quick start · How it works · Policy · Reference · Safety


Terminal recording: omp-route explain ranks three providers into one fallback chain

 ⌗  Same transcript as copyable text
$ omp-route explain cctq-claude/claude-fable-5 --prefer cursor,cctq-claude,openrouter

Generated 1 fallback route.

source: cctq-claude/claude-fable-5 (claude-fable@5)
  1. cursor/claude-fable-5 — preference #1, 100% quota remaining
  2. openrouter/anthropic/claude-fable-5 — preference #3, quota unknown
  3. glm-fireworks/anthropic/claude-fable-5 — quota unknown

Recorded against a stub OMP that speaks the same JSON contract as the real CLI; regenerate the animation with node tools/make-demo-svg.mjs.

Note

OMP owns execution. omp-route only decides the order. It is not a proxy and never sits between OMP and a model provider.


01 · The problem

Oh My Pi already knows how to retry requests, cool down unhealthy providers, and follow retry.fallbackChains. What it cannot infer is that differently named selectors may represent the same model:

        cctq-claude/claude-fable-5   ┐
        cursor/claude-fable-5-high   ├──  one model · three names · zero linkage
 openrouter/anthropic/claude-fable-5 ┘

Without a chain, an exhausted provider still leaves you switching models by hand. omp-route supplies the missing planning layer.

Manual setupWith omp-route
Find matching models provider by providerRead the catalog directly from OMP
Compare provider-specific model IDsGroup conservative canonical equivalents
Hand-author every fallback chainGenerate a chain for every selectable variant
Reorder providers as quota changesRank from redacted usage data at launch
Modify the main OMP configurationWrite a separate, reversible overlay

02 · Quick start

Requirements

Runtime Node.js 22 or newer
Peer CLI OMP installed and available as omp
Network none — planning happens entirely on your machine

Install from GitHub

omp-route is not published to the npm registry. Install it directly from this repository:

$ npm install --global github:Nigmat-future/omp-route
$ omp-route --help

Or clone and run it locally:

$ git clone https://github.com/Nigmat-future/omp-route.git
$ cd omp-route
$ node bin/omp-route.js --help

Build your first route

$ # [1] inspect high-confidence cross-provider groups
$ omp-route scan fable

$ # [2] preview the exact fallback chains
$ omp-route plan --match fable --prefer cursor,cctq-claude,openrouter

$ # [3] see why each candidate received its position
$ omp-route explain cctq-claude/claude-fable-5 \
      --prefer cursor,cctq-claude,openrouter

$ # [4] compile the overlay and launch OMP with your original arguments
$ omp-route run --match fable \
      --prefer cursor,cctq-claude,openrouter \
      -- --model fable

Step [4] writes ~/.omp-route/routes.generated.yml, then hands control over:

$ omp --config ~/.omp-route/routes.generated.yml --model fable

Your existing OMP configuration is not edited.

03 · How it works

flowchart LR
    A["omp models --json"] --> C
    B["omp usage --json --redact"] --> C
    C(["canonicalize"]) --> D(["capability gates"])
    D --> E(["rank by tier + preference"])
    E --> F["fallbackChains overlay"]
    F --> G(["omp --config ..."])

    classDef src fill:#0D1117,stroke:#00E5FF,stroke-width:1.5px,color:#E6EDF3
    classDef step fill:#0D1117,stroke:#A78BFA,stroke-width:1.5px,color:#E6EDF3
    classDef out fill:#0D1117,stroke:#00E676,stroke-width:1.5px,color:#E6EDF3
    classDef exec fill:#0D1117,stroke:#F5A524,stroke-width:1.5px,color:#E6EDF3

    class A,B src
    class C,D,E step
    class F out
    class G exec
Loading

The planner runs once, immediately before OMP starts:

# Stage What happens
1 Discover Read OMP's public model catalog and best-effort, redacted usage report
2 Canonicalize Normalize known provider-specific selectors without collapsing ambiguous versions
3 Gate Reject candidates that lose required reasoning support, context length, or input modalities
4 Rank Prefer usable quota tiers, then your provider preference within each tier
5 Compile Emit an explicit chain for every selectable model in every cross-provider group
6 Delegate Launch OMP and leave retries, cooldowns, and fallback reversion to its runtime

Tip

If usage reporting is unavailable, planning continues from compatibility and --prefer instead of failing the task.

04 · Routing policy

The policy is intentionally conservative. A missed route is safer than silently replacing a model with the wrong one.

availability ladder
┌─ tier 1 ─ known quota > 5% ──────────────► preferred
├─ tier 2 ─ quota unknown ─────────────────►
├─ tier 3 ─ positive quota ≤ 5% ───────────►
└─ tier 4 ─ exhausted ─────────────────────► last resort
   └─ within a tier:  --prefer order  →  remaining quota  →  provider name
Stage Decision rule
Identity Claude family and version are normalized explicitly; generic models require the same final model ID
Ambiguity latest aliases, batch-only variants, conflicting identities, and missing IDs are excluded
Versioning Fable 5 and Fable 5.1 remain separate canonical groups
Capability A fallback must preserve reasoning support, context window, and every required input modality
Profile Matching thinking profiles are preferred; configurable profiles are forwarded as selector suffixes
Availability Known quota above 5% → unknown quota → low positive quota at 5% or below → exhausted
Preference Inside one availability tier, --prefer order wins, followed by remaining quota and provider name
Disabled credentials Removed from fallback candidates entirely

05 · Generated overlay

The .yml file uses JSON syntax, which is valid YAML and unambiguous to serialize:

{
  "retry": {
    "enabled": true,
    "modelFallback": true,
    "fallbackRevertPolicy": "cooldown-expiry",
    "fallbackChains": {
      "cctq-claude/claude-fable-5": [
        "cursor/claude-fable-5-high",
        "openrouter/anthropic/claude-fable-5"
      ]
    }
  }
}

Only retry settings are included in the overlay. Unrelated OMP settings remain untouched.

06 · Command reference

Command Purpose
omp-route scan [query] List routable canonical groups spanning multiple providers
omp-route plan [options] Preview all generated chains without writing a file
omp-route explain [query] [options] Show ordering reasons for matching routes
omp-route run [options] -- [OMP_ARGS...] Write the overlay and launch OMP with forwarded arguments
Option Applies to Description
--match <query> plan explain run Limit discovery to matching canonical keys, selectors, or model names
--prefer <a,b,...> plan explain run Set provider priority within the same availability tier
--profile <name> plan explain run Preferred thinking profile when a source has no explicit profile; default is high
--json scan plan explain Print machine-readable output
--all run Allow an unscoped overlay even when it exceeds the automatic route guard
-- run Forward every following argument to OMP unchanged

For run, a passthrough --model value is also used as the route scope when --match is omitted.

 ⚙  Environment variables
Variable Purpose
OMP_ROUTE_DIR Override the directory containing routes.generated.yml
OMP_ROUTE_OMP_COMMAND Override the OMP executable name or path
OMP_ROUTE_OMP_PREFIX_ARGS JSON string array prepended to OMP arguments; mainly useful for wrappers and tests

07 · Safety model

Guarantee
local The planner does not call model-provider APIs or proxy model traffic; it invokes the locally installed OMP CLI.
redacted Usage is requested with OMP's --redact flag. Error output is additionally scrubbed for API-key and bearer-token patterns.
reversible The generated overlay is separate from the user's OMP config and requests file mode 0600 where supported.
fail-closed Invalid model-discovery JSON stops execution before OMP is launched.
bounded Unscoped plans above 200 routes are refused unless the user passes --all.
no-shell OMP is spawned without a shell and receives passthrough arguments as an array.

The full threat model, including what is explicitly out of scope, lives in SECURITY.md. Vulnerabilities go through private advisories, not public issues.

Important

omp-route is a proof of concept. Review plan output before relying on a new model family in unattended workloads.

08 · Boundaries

omp-route deliberately does not:

- proxy, stream, or issue model-generation requests
- migrate a request that is already mid-stream
- continuously re-plan routes during a running OMP session
- guarantee semantic equivalence for arbitrary or ambiguous model names
- replace OMP's retry classifier, cooldown handling, or runtime fallback logic

A real transition still depends on OMP classifying the provider response as retryable and on the provider returning a recognizable quota or availability error.

09 · Development

$ git clone https://github.com/Nigmat-future/omp-route.git
$ cd omp-route
$ npm test

The suite uses Node's built-in test runner and covers canonicalization, compatibility, quota ranking, CLI behavior, overlay generation, argument forwarding, degraded usage reporting, and malformed discovery output. There are no runtime dependencies.

Every push runs the suite on Node 22 and 24, across Linux and Windows, plus a CodeQL analysis and a guard that fails the build if a runtime dependency is ever added.

Path What lives there
src/core.js Canonicalization, compatibility gates, ranking, overlay shape
src/omp.js The only place that spawns OMP, and the output redaction
src/cli.js Argument parsing, output formatting, the route guard
tools/make-demo-svg.mjs Regenerates the animated terminal in the README

Issues and focused pull requests are welcome — please use a conventional commit prefix (feat:, fix:, docs:) in the PR title, since releases and the changelog are generated from them.


Released under the MIT License · built for Oh My Pi

discover → gate → rank → compile → delegate

About

Routing plan compiler for Oh My Pi: discover equivalent models across providers, rank them by quota, and compile safe fallback chains before OMP starts.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages