Routing logo

Routing

Community
larcane97
routing

Run Claude Code or Codex on whichever clausona account has quota left, using clausona routes, and create, change or explain those routes, and the dir rules and defaults that pick one for a plain `clausona run claude`, for the user. Use when the user says "run this on an account with room", "spread these across my accounts", "make a route of my work accounts", "use my work accounts in this repo", "why did it pick that account", "wait until an account frees up", when a run stops on a usage limit (of the plan or of one model, such as Opus), when writing a script or cron job that runs on a route, or when starting several workers that should not all land on one account.

Overview

Publisherlarcane97
Repositoryclausona
Skill namerouting
Stars
57
Forks
11
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by larcane97 on GitHub. Read the source before you install it.

Installation

Install the Routing AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/larcane97/clausona/tree/main/plugins/routing/skills/routing
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/larcane97/clausona.git /tmp/clausona
mkdir -p .claude/skills
cp -r /tmp/clausona/plugins/routing/skills/routing .claude/skills/routing
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Routing in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Routing on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Routing is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Routing runs across clausona accounts

clausona keeps several Claude Code and Codex accounts on one machine. A route is a named group of those accounts and a rule for picking one of them by how much of its plan quota is used. clausona run --route <name> starts the tool on the account the rule picks right now. (csn is an alias for clausona that only the user's interactive shell has. Run clausona.)

Run clausona route --help once before anything else. It lists every command, option and exit code of the installed version. Where it differs from this skill, it wins.

clausona route with no arguments opens the Routes screen, a TUI meant for a person at a terminal. Do not run it; use the subcommands below. (In a shell without a terminal it only prints the help.) A user who would rather look through routes on that screen can run it themselves.

What decides the pick

  • An account's usage is the higher of its 5H and 7D windows: 0% 5H with 99% 7D is 99%. That number, and nothing else, is ranked and shown.
  • When the tool's arguments name a model (claude --model opus, codex -m gpt-5.3-codex-spark, also after exec), the account's limit on that model joins the max: Claude's is weekly, and a Codex one can have a 5-hour and a weekly window, of which the higher counts (named in the note and usage.window as GPT-5.3-Codex-Spark 5H or … 7D). A model falls under a limit when the limit's name (Opus, GPT-5.3-Codex-Spark) is a word of the model's name, in any case: opus, claude-opus-4-5, opus[1m] fall under Opus; gpt-5.3-codex does not fall under GPT-5.3-Codex-Spark. A run that names no model counts no model's limit, even if the account's default model has one: pass --model when the work needs a model with its own limit. -c model=…, a Codex config profile and opusplan are not read.
  • clausona stops at the first stage that finds someone:
    1. pool: from members under maxUsage (default 80), chosen by the strategy.
    2. fallback: the first fallback member, in listed order, under maxUsage.
    3. overflow: every member is at maxUsage or over it, so the one with the most left (lowest usage) is taken, pool or fallback, at 90% or 99% alike.
    4. nobody: every member is at 100% or skipped. Nothing is launched, exit code 75. With --wait, it waits for the soonest reset instead and starts again at 1 (see Waiting).
  • Strategies: round-robin (default; the account picked longest ago, a never-picked one first), headroom (lowest usage), expiring (lowest usage among accounts whose weekly limit resets within 24 hours; with none, as headroom).
  • Signed-out, expired and unreadable accounts are skipped at every stage, and so is one whose stored sign-in is another account's.
  • An API profile in a route (named exactly; no pattern matches one) is ranked by its spend as a share of its limit: a clausona budget (clausona route budget), else the limit set on its provider key. One with no limit, whose provider reports no spend, or whose spend could not be read is skipped. It is billed per use.
  • Resumed runs (-c/--continue, -r/--resume, --from-pr, codex resume or fork) use only accounts that share sessions: the primary account and profiles with merged sessions. If none of them can take it, the account that holds the session has to be run by name.

Looking before acting

bash
clausona route list --json                 # routes, their settings with defaults, their members, dir rules
clausona route explain <name> --json       # every member's usage and status; launches and records nothing
clausona route explain <name> --model opus --json   # as a run of that model would rank it
clausona route explain --json              # what clausona run claude and codex would take in this directory
clausona list --json                       # every profile, with its email and quota
clausona route budget --json               # every API profile: its limit, whose limit, spend and usage

explain --json gives:

  • settings: the route with its defaults. settings.tool is claude, codex or all (a route over the accounts of both tools).
  • outcome: {"kind": "picked", "id", "stage", "reason"}, or {"kind": "none"} with soonest ({"id", "at"}) when a reset time is known. explain exits 0 even when nobody could be picked, so read outcome.kind.
  • members, one per account: status is picked, eligible (under the cut, not picked), over-limit (at or above maxUsage) or skipped. A skipped one has skipReason: signed-out, expired, other-account (its stored sign-in is another account's), no-reading, not-registered, keeps-own-sessions, or for an API profile no-spend-limit, spend-not-reported or spend-unread. Each also has usage, fiveHour, sevenDay and lastPickedAt, scoped ({"label", "usedPercent", "resetsAt"}, its limit on the --model model, of a Codex limit with two windows the higher, or null) and budget (an API profile's {"usedPercent", "spentUsd", "limitUsd", "source", "per", "resetsAt"}, or null). usage.window is 5H, 7D, the name of that limit (its label for Claude, Opus; its label and window for Codex, GPT-5.3-Codex-Spark 7D), or budget. The top level has model.

route list --json gives each route's members, freeNow ({"free", "members"}) and next (as outcome), and problems: what is wrong with each route in routes.json that cannot be used, and with each dir rule or default that cannot be read. Such a route is left out, and only commands that use it fail; tell the user, and point them to clausona route edit rather than editing the file yourself. It also gives dirs ({"~/work": {"claude": "work"}}), defaults ({"claude": "main"}) and ruleWarnings: rules that name a route that is gone or is for the other tool, which a run skips.

With --json, a failing route command prints {"version": 1, "error", "message"} on stdout. error is usage, not-found (no such route) or failed; a routes.json, or a route named, that cannot be used adds file (its path) and problems.

Answer "why did it pick X" from explain: outcome.stage and outcome.reason for the pick, and each other member's status, skipReason and usage. explain takes the same field options as a run (--strategy, --max-usage, …) and --resume, to show what a run like that would get.

Creating or changing a route for the user

route add and route set never ask, in a terminal or not. They write at once, and route add then prints the route it made. So the asking is yours to do, before you write:

  1. Show the user which accounts the route would hold. Rank it unsaved and show them the result: clausona route explain --tool <claude|codex|all> --from '<patterns>' [--exclude '<patterns>']. For a change, show the route as it is (route explain <name>) and as it would be.
  2. Ask before including accounts that look like someone else's or shared: another person's name or email, *-share. Leave them out until the user says yes.
  3. * takes every subscription account of the tool, including ones added later. When the user described a subset ("my work accounts"), use names (work,work2) or an email pattern (*@example.com) instead.
  4. Never put an API profile in a route unless the user names it: it is billed per use. A pattern never matches one, so * is safe; it joins only by its exact name (claude:glm). It also needs a spend limit: route add and route set refuse one without, naming clausona route budget <profile> --usd 20 --per month. Set a budget only with the amount and period the user gives. A budget stops new routed sessions, not a running one. Run an API profile by name (clausona run claude:glm) only when the user asks for it.
  5. Wait for the user's OK, then write with the CLI. Never edit ~/.clausona/routes.json yourself, and do not use route edit: it opens an editor for a person.
bash
clausona route add <name> [--tool claude|codex|all] --from '<patterns>' [--exclude '<patterns>'] [--fallback '<patterns>'] [--strategy <s>] [--max-usage <n>]
clausona route set <name> [--from …] [--exclude …] [--fallback …] [--strategy …] [--max-usage …] [--add …] [--drop …] [--no-fallback]
clausona route rename <old> <new>
clausona route remove <name>
  • --tool is the route's tool: claude (the default), codex, or all for one route over the accounts of both tools. Without --tool, --from entries that all carry one tool's prefix (codex:a,codex:b) make a route for that tool, and prefixes of both tools make an all route. Check clausona list --json for which tools have accounts. route set cannot change the tool.
  • --yes is accepted and does nothing. You do not need it.
  • Patterns are comma-separated profile names or globs (team-*, claude:team-*). A pattern with an @ matches account emails. Matching ignores case. Quote the list.
  • On an all route a name without a prefix matches in both tools: personal is claude:personal and codex:personal. Use the prefixed id to mean one account.
  • In route set, each field option replaces its whole field: --exclude old makes the exclude list just old. To add to a list, pass its current entries too (from route list --json).
  • --add and --drop change from one entry at a time. --drop removes only an entry written in from, so it cannot take one account out of * or *@example.com. Use --exclude for that.
  • rename and remove act at once. Ask before removing a route. rename also rewrites the dir rules and defaults that name it; remove also removes them, and says which.
  • A route name starts with a letter or a digit, and the rest is letters, digits, ., _ and -. Names and patterns that look like an API key or a token are refused, and clausona does not print them back. Never put a key in either.

Running

bash
clausona run --route <name> -- -p "<prompt>"                # Claude Code, non-interactive
clausona run --route <name> -- exec "<prompt>"              # a Codex route
clausona run codex --route <name> -- exec "<prompt>"        # an all route: name the tool
clausona run claude --from '<patterns>' -- -p "<prompt>"    # an unsaved route
clausona run --route <name> --strategy headroom -- -p "…"   # change a field for this run only
  • Routing options (--route, --from, --exclude, --strategy, --max-usage, --fallback, --wait) go before the tool's own arguments. A -- ends them, and everything after it goes to the tool untouched (--model, --permission-mode, --output-format json, …).
  • The field options need --route or --from. On their own they are refused with exit 1.
  • On an all route (settings.tool is all), put the tool word before --route whenever you pass arguments: clausona run claude --route <name> -- -p "…". Only that tool's accounts are ranked. Arguments without a tool word are refused with exit 1, because Claude Code and Codex take different ones. route explain and route pick narrow the same way with --tool.
  • Next to --route, --exclude x leaves x out for this run on top of the route's own excludes. The other field options replace their field for this run. Nothing is saved.
  • Never put a profile right after routing options or a tool word. These are refused, because the tool would get the name as its prompt: clausona run --route main claude:work, clausona run claude claude:work. To run one account, name it alone (clausona run claude:work). If a profile is named like one of the tool's commands (exec, mcp), put -- before the command: clausona run codex -- exec ….
  • clausona run claude (or codex) with no routing options takes a route from the user's dir rules and defaults: the deepest dir rule for the current directory, then the tool's default, then the active profile. clausona route explain --json with no name says which. With no tool word and no --route or --from, it is refused.
  • Naming a profile (clausona run claude:work) always runs it, whatever its quota.
  • A routed run names the account it picked, and why, on stderr. stdout is the tool's own.
  • Without a terminal an unknown --route creates nothing: it exits 1 with "Create it: clausona route add ". Treat that as a new route: show the members and ask first, as above.
  • clausona run --route <name> with no tool arguments is an interactive session. Give that command to the user instead of starting it from your shell.

Waiting for a free account

--wait makes "nobody is free" a wait instead of an exit 75, for run and route pick alike:

bash
clausona run --route <name> --wait -- -p "<prompt>"              # waits up to 5h
clausona run --route <name> --wait=2h -- -p "<prompt>"           # or 30m, 1h30m: after `=`, never a space
id=$(clausona route pick <name> --wait=1h --model opus)          # an orchestrator's turn, waiting
  • It sleeps until 30 s after the soonest reset of an account at 100%, reads quota again at least every 30 minutes, and then ranks again. stderr says waiting until 14:05 for claude:work (5H resets) …; stdout stays the tool's, or pick's id or JSON.
  • If the soonest reset is past the cap, or no reset time is known, it exits 75 at once, and the message says the cap that would reach it (--wait=48h). Ctrl-C exits 130; nothing is launched or recorded.
  • Several waits that wake together take different accounts, as picks always do.
  • Your own shell tool call times out long before a wait of hours ends. Use --wait in a script, in cron, or in a command you give the user; from your shell, only with a cap shorter than your tool's timeout, or run it in the background. Ask before starting a wait of more than a few minutes.

A cron or script recipe, for the user:

bash
clausona run claude --route nightly --wait=4h -- -p "review yesterday's commits" > review.md
case $? in 0) ;; 75) echo "no account came free within 4h" >&2 ;; *) exit 1 ;; esac

cron has a short PATH (give it one that reaches clausona, claude and node) and no terminal, so an unknown route exits 1 instead of asking.

Dir rules and defaults

A dir rule gives a directory a route per tool: in that directory and below, a plain clausona run claude (or codex) with no --route or --from runs on it. The deepest rule for the current directory wins. A default does the same everywhere no rule holds. With neither, the run takes the tool's active profile.

bash
clausona route explain --json                    # here: what each tool's run takes, and why
clausona route dir                               # every dir rule and default
clausona route dir ~/work work                   # in ~/work and below, run claude takes route work
clausona route dir ~/work any --tool codex       # an all route fills both tools unless --tool says one
clausona route dir ~/work --clear [--tool codex]
clausona route default main                      # elsewhere, run claude takes route main
clausona route default --clear --tool claude     # --tool is required to clear (claude, codex or all)
  • These change what every plain run in that directory does, the user's own included. Say what will change (route explain from that directory shows what runs now) and wait for the user's OK before you set or clear one.
  • A route fills the slot of its own tool. An all route fills both, or the one --tool names. A route of the other tool is refused. The route must exist first.
  • A path may be relative, absolute or start with ~; it is stored with ~ when it is under home. A rule matches its directory through symlinks, and ignoring case on macOS and Windows.
  • route explain --json with no name gives {"directory", "runs": [...]}, one entry per tool (--tool limits it to one). A routed entry is the explain --json of its route, plus tool and skipped. Its resolvedBy is dir:<path> (the rule's path as stored, with ~) or default. An entry with no route is {"tool", "route": null, "resolvedBy": "active", "profile", "skipped"}, profile null when the tool has no active profile. skipped lists the rules passed over as {"rule", "reason"}, rule being dir:<path> or default.
  • A rule whose route is gone, cannot be used or is for the other tool is skipped: the run says so on stderr and goes on to the next rule. A rule that cannot be read at all is named by route list (in problems); a run only says that there is one. If routes.json cannot be read at all, a plain run says so in one line and runs the active profile; a run with --route fails as before.

Several workers at once

Take one turn per worker on a round-robin route, and start each worker on its own pick:

bash
id=$(clausona route pick main); code=$?            # one profile id on stdout; records the turn
clausona run "$id" -- -p "$(cat <brief file>)"     # start this worker in the background

Do both for each worker in turn, and check code every time: 0 starts the worker on $id; 75 means nobody is free, so start no more workers (next section); anything else is an error to show the user.

  • Each pick records the turn, so the next pick takes the next account under the cut. Never start every worker on one pick result, and never on ids copied from explain, which records nothing.
  • With fewer accounts under the cut than workers, later picks come back to an account already in use. Once every account is over the cut, a pick (stage overflow) takes the one with the most left, not the next turn. Tell the user which workers share an account.
  • One clausona run --route main -- -p … per worker also takes its own turn. Use pick when you want the id before you start.
  • On an all route a pick can be an account of either tool. Pick with --tool claude (or codex) so every id is of the tool your worker command is written for.
  • On a headroom or expiring route, picks made close together land on the same account (readings are cached for 5 minutes). Add --strategy round-robin to each pick, or use a round-robin route.
  • pick --json prints {"profile", "route", "stage", "usage", "reason"}. When nobody is free it still prints JSON, with "profile": null and soonest ({"id", "at"}, or null), and exits 75.
  • When workers run a model with its own limit, pick with --model too (clausona route pick main --model opus), so a spent Opus limit is not picked for an Opus worker.
  • To wait for a free account instead of stopping at 75, pick with --wait (above).

When nobody is free (exit 75)

Nothing was launched. Every account of the route is at 100% of a window, or was skipped. The message on stderr lists each account with its usage and when it resets, or why it was skipped, and marks the soonest reset (with --json, soonest.at). Tell the user which account frees up first, and when, and which skipped ones clausona login <profile> would bring back. Workers already started keep running. If the work can wait, offer the same command with --wait (or the longer --wait=<n>h the message names) for the user to run.

A higher --max-usage does not help: past the cut, any account under 100% is already taken. Do not run an account by name to get past the limit unless the user says so. If they do, name the risk: that account is at its limit, so the session may stop at once.

When a run stopped on a usage limit

If it was a limit on one model (Claude's Opus limit, say), start it again with that model named (-- --model opus), so the account whose limit on it is spent is not picked again.

Otherwise start it again on the route. The spent account is now at or above the cut, so another one is picked. But readings are cached for up to 5 minutes, and with every account over the cut, a cached reading under 100% can pick the spent one again: if explain would still pick it, or shows it eligible, add --exclude with it for this run. The route's own excludes still apply. To carry on the same session, pass -c or --resume after --; that run only goes to accounts that share sessions.

Frequently asked questions

What does the Routing AI skill do?

Run Claude Code or Codex on whichever clausona account has quota left, using clausona routes, and create, change or explain those routes, and the dir rules and defaults that pick one for a plain `clausona run claude`, for the user. Use when the user says "run this on an account with room", "spread these across my accounts", "make a route of my work accounts", "use my work accounts in this repo", "why did it pick that account", "wait until an account frees up", when a run stops on a usage limit (of the plan or of one model, such as Opus), when writing a script or cron job that runs on a rout...

Why use Routing on TypingMind?

Because you install it once and use it with any model. Routing is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Routing in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/larcane97/clausona/tree/main/plugins/routing/skills/routing. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Routing?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Routing?

As many as you like. As long as a model supports skills, you can use Routing with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Routing AI skill free?

Yes. It is published on GitHub by larcane97 under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇