| name | openrouter-routing-rules |
| description | Define custom routing rules for OpenRouter requests based on user tier, task type, cost budget, and availability. Triggers: 'openrouter rules', 'routing rules', 'custom routing openrouter', 'conditional model selection'.
|
| allowed-tools | Read, Write, Edit, Grep, Bash(python3:*) |
| version | 1.20.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
| tags | ["saas","openrouter","routing","rules-engine"] |
| compatibility | Designed for Claude Code, also compatible with Codex and OpenClaw |
OpenRouter Routing Rules
Overview
Beyond simple task-based model selection, production systems need configurable routing rules that consider user tier, cost budget, time of day, model availability, and feature requirements. This skill covers building a rules engine for OpenRouter model selection with config-driven rules, dynamic conditions, and override capabilities.
Prerequisites
- An OpenRouter API key (
sk-or-v1-...) exported as OPENROUTER_API_KEY — see the openrouter-install-auth skill for setup
- Python 3.8+ with the OpenAI SDK — the rules engine itself is stdlib (
dataclasses, json, random) layered on top
- Per-request metadata available in your app: user tier, task type, remaining budget, tool/vision needs, latency SLA (the
RoutingContext fields)
- Budget tracking wired up (see
openrouter-cost-controls) if you use budget-conditioned rules like low-budget
Instructions
- Model each request's metadata as a
RoutingContext (user tier, task type, budget remaining, tools/vision flags, latency SLA) per Rules Engine.
- Define
RoutingRule entries in priority order — free-tier first, then budget, capability (tools/vision), task type, latency, and always a priority=99 default catch-all.
- Resolve the winning rule with
evaluate_rules(ctx): first match by ascending priority wins; failing conditions return False instead of raising.
- Execute through
routed_completion() per Routed Completion — it applies the rule's model, fallback chain (models + route: "fallback"), and max_tokens.
- To make rules hot-reloadable, express them as JSON per Config-Driven Rules and match with
match_config_rule() instead of lambdas.
- Validate any rule change on a slice of traffic with
ab_test_routing() per A/B Testing Rules before full rollout.
Rules Engine
import os, json, time
from dataclasses import dataclass
from typing import Optional, Callable
openai OpenAI
client = OpenAI(
base_url=,
api_key=os.environ[],
default_headers={: , : },
)
:
user_tier: =
task_type: =
budget_remaining: =
prompt_tokens_est: =
needs_tools: =
needs_vision: =
max_latency_ms: =
:
name:
priority:
condition: [[RoutingContext], ]
model:
fallbacks: [] =
max_tokens: =
() -> :
:
.condition(ctx)
Exception:
RULES = [
RoutingRule(
name=,
priority=,
condition= ctx: ctx.user_tier == ,
model=,
fallbacks=[],
max_tokens=,
),
RoutingRule(
name=,
priority=,
condition= ctx: ctx.budget_remaining < ctx.user_tier != ,
model=,
fallbacks=[],
max_tokens=,
),
RoutingRule(
name=,
priority=,
condition= ctx: ctx.needs_tools,
model=,
fallbacks=[],
),
RoutingRule(
name=,
priority=,
condition= ctx: ctx.needs_vision,
model=,
fallbacks=[, ],
),
RoutingRule(
name=,
priority=,
condition= ctx: ctx.task_type == ,
model=,
fallbacks=[],
),
RoutingRule(
name=,
priority=,
condition= ctx: ctx.max_latency_ms < ,
model=,
fallbacks=[],
),
RoutingRule(
name=,
priority=,
condition= ctx: ctx.user_tier == ,
model=,
fallbacks=[, ],
),
RoutingRule(
name=,
priority=,
condition= ctx: ,
model=,
fallbacks=[],
),
]
() -> RoutingRule:
sorted_rules = (RULES, key= r: r.priority)
rule sorted_rules:
rule.matches(ctx):
rule
sorted_rules[-]