name: model-router-profile-mapping description: "Design, verify, stage, and roll out per-profile model pools in an OpenAI-compatible multi-provider router such as 9Router. Use when mapping Hermes profiles to router combos, validating exact model IDs, or testing a staged profile rollout." version: 1.0.0 author: CEO AI OS created_by: agent
Use for configuring or reviewing profile-specific model routing where Hermes profiles call an OpenAI-compatible router that exposes named combos and models from multiple providers.
Use a direct, simple structure unless the router explicitly requires another one:
Hermes profile → exactly one named router combo → ordered JSON list of exact model IDs
A model ID may appear in several profile combos. Do not introduce shared or nested “mixing” combos merely to enable reuse. Reuse is achieved by placing the same exact model ID in multiple combo arrays.
/v1/models catalog immediately before generating a mapping.A model appearing in the router's /v1/models catalog does NOT mean it is usable. The upstream provider (e.g., Google AI Studio, Alibaba) may have zero quota on certain models for the account keys configured in the router. A request to such a model will fail after the router selects it, wasting the fallback/retry.
Before finalising any profile mapping, vet each model against its upstream provider's actual quota/rate-limit page:
https://aistudio.google.com/u/1/rate-limit (or the equivalent console). Models with RPM=0, TPM=0, and RPD=0 have no quota and must be excluded from all combos.Categorise each model into one of three tiers and tag them in the mapping document:
| Quota rating | Criteria | Action |
|---|---|---|
| ✅ Usable | RPM > 0 and RPD > 0 | Keep in pool |
| ⚠️ Throttled | RPM ≥ 1 but very low (≤ 5) | Keep but place after higher-quota models; document the throttle |
| ❌ Zero-quota | RPM = 0, TPM = 0, RPD = 0 | Exclude from every combo; note the exclusion reason |
Zero-quota models are harmful because: - The router may still list them and attempt fallback through the entire pool before failing. - They extend the fallback chain pointlessly, multiplying latency for every request. - A user hitting a zero-quota model gets a silent failure or cryptic error.
When the user provides a screenshot of the provider's rate-limit page, extract the quota table and cross-reference every router model against it before writing the mapping. Do not skip this step even for models that appear in the router's catalog — the router returns catalog entries regardless of quota availability.
See references/ai-studio-quota-vetting.md for an example rate-limit audit.
See references/ai-studio-quota-vetting-20260724.md for a real-world audit record of Google AI Studio quota data (2026-07-24) that resulted in exclusion of 5 zero-quota Gemini models from all profile pools.
Classify all live models before allocation. Keep the raw catalog in a reference document.
Allocate by the user's stated profile usage order, not evenly.
Before writing router DB state, create a Markdown file containing all of the following, with no ellipses or implied entries:
Do not replace exhaustive lists with phrases such as “all models”, “etc.”, “...”, or abbreviated provider summaries when the user asks to inspect the mapping. The user will reject abbreviated output — every model ID must appear on its own - bullet line. No implied continuation (“+N more”) is acceptable even if the full list was shown earlier.
Before rollout, verify rather than assume:
models accepts a JSON array of exact string IDs./v1/chat/completions.model; record HTTP status and the concrete resolved upstream model in the response.When the user asks to test one profile first:
profile-<target-profile>.model.default and local router provider default_model fields.default combo or any other profile configuration unless explicitly authorized.model: profile-<target-profile> through the router.default or their prior model.For a profile-specific combo with provider local9router, ensure the target profile config uses:
model:
provider: local9router
default: profile-<profile-name>
providers:
local9router:
default_model: profile-<profile-name>
If the config includes a duplicate profile-named provider block, update it only within the target profile config and document why. Do not change auxiliary vision routing unless asked.
Additionally, when deploying multiple profiles, ensure that every profile config file (e.g., ~/.hermes/profiles/<name>/config.yaml) is modified to point its model.default and custom_providers.local9router.default_model fields to its designated combo, rather than leaving them pointed to the general default combo.
These rules are non-negotiable — the user has explicitly corrected deviations. Do not deviate silently.
references/profile-model-mapping.md is the source of truth.ag/* (Antigravity non-Claude models: gemini-, gpt-oss-)openai-compatible-alibaba/* (Qwen, DeepSeek, GLM series)ag/claude-* (Antigravity Claude models: claude-opus, claude-sonnet)cx/* (Codex GPT-5.x series)gemini/*, openrouter/* (direct Gemini API, OpenRouter free tier)This ordering reflects cost, availability, and performance preferences. AG's distributed quota is preferred over paid Alibaba, which is preferred over AG's Claude (limited quota), which is preferred over Codex (paid).
⚠️ Common mistake: When asked to "optimize" or "rebalance" mappings, do not silently downgrade Writers or IT-AI to light models. Always enumerate proposed changes and confirm before applying.
/root/.9router/db/data.sqlite on the host, but the docker container mounts the database from a different volume or caches database state in-memory. Ensure you run docker inspect <container> to trace the volume binding (e.g., /root/.9router -> /app/data), run your updates directly on the mounted database path, and execute docker restart <container> to flush the cache.kind in the combos table represents the routing strategy. If UI shows "No combos yet" or behaves unexpectedly, verify if the kind string value matches the UI expectation (e.g., default, fallback, round-robin, fusion). A mismatch in the kind enum/string can cause UI render failures.default combo while staging a target profile. It can interrupt all other profiles still using it."default" inside the default combo's own model array is a separate cleanup item. Do not repair it during a scoped staging test unless authorized.stream: false if necessary.See references/9router-hermes-staged-rollout.md for a validated staged rollout and verification record.