docs
// Tools

erectl semantic-router

Read and write the project's semantic-router settings, manage dynamic routing rules, and inspect why each request went where it did -- everything the dashboard settings page offers, from the terminal.

Overview

The semantic router picks a generative endpoint per turn by embedding the request and ranking your endpoints against it. The semantic-router command group configures that behaviour and reports on it: the enablement flag and its ranking tunables, the exclusion list and the deterministic fallback, the dynamic routing rules that fire above the classifier, the last 24 hours of routing decisions, and the aggregate health and consumption counters.

Every subcommand hits the router's management plane at /{project_id}/v1/management/semantic-router and requires an API key carrying the management scope. A key without it gets 403 with code: "scope_insufficient". There are no project UUIDs to pass -- each subcommand resolves the active erectl context and authenticates with that project's API key. Use --context <name> to target a different deployment, and --dry-run on any of the writing verbs to print the request without sending it. Full REST reference: Semantic Router Management API.

Scope and Prompt Content

Read this before you issue a management-scoped key.

erectl semantic-router decisions returns an excerpt of the user prompt behind each routing decision, and it returns those rows for every workspace in the project.

The dashboard shows the same view narrowed to the workspaces the signed-in operator is allowed to read, so an operator never sees another member's private workspace there. An API key carries no user identity, so there is no principal to evaluate that rule against and no equivalent filter can be applied. The holder of a management-scoped key can therefore read prompt text from workspaces they would not be shown in the web UI.

This is deliberate -- it is what gives the CLI parity with the dashboard -- but it means a management key is as sensitive as the prompts in the project. Scope keys accordingly, and prefer erectl semantic-router health when you only need to know whether routing is working: that command reads counts and totals and never touches prompt content.

Usage Pattern

bash
erectl semantic-router config show # Show the config erectl semantic-router config set <key> <value> # Set one setting erectl semantic-router rules list # List routing rules erectl semantic-router rules add ... # Add a routing rule erectl semantic-router rules update <id> # Patch a routing rule erectl semantic-router rules enable <id> # Enable a routing rule erectl semantic-router rules disable <id> # Disable a routing rule erectl semantic-router rules delete <id> # Delete a routing rule erectl semantic-router decisions # Recent route decisions erectl semantic-router health # Routing health + usage

config and rules each have a default subcommand, so erectl semantic-router config is config show and erectl semantic-router rules is rules list. The group itself has none: bare erectl semantic-router prints help rather than guessing.

-o json switches the read verbs -- config show, rules list, decisions, health -- to a machine-readable dump of the whole response. The writing verbs print a human-readable success line before their JSON, so pipe those through -q as well if you intend to parse them.

config show

Prints the project's effective semantic-router configuration: the enablement flag, the resolved availability, whether an embedding endpoint is present, whether multi-model dispatch is on, the three ranking tunables (each showing the deployment default when the project has not overridden it), the fallback pin, the exclusion list, and the rule count. It also lists the endpoints the router can currently route over, and -- separately -- any endpoint a stored setting still references that the router cannot route over today.

bash
erectl semantic-router config show erectl semantic-router config show -o json

config set

Sets exactly one setting. Keys the command does not name are left untouched, so a single-key write can never clobber a setting you did not mention. On success it prints Setting '<key>' updated. and nothing else; run config show if you want the resulting configuration back.

bash
erectl semantic-router config set semantic_router_enabled false erectl semantic-router config set semantic_router_similarity_floor 0.35 erectl semantic-router config set semantic_router_similarity_floor default erectl semantic-router config set semantic_router_excluded_endpoint_ids none

Keys

Key Value Meaning
semantic_router_enabled true | false Whether semantic routing runs for this project
semantic_router_multi_model_enabled true | false Whether multi-model set-cover dispatch runs
semantic_router_similarity_floor 0..1 | default Minimum cosine score an endpoint must clear
semantic_router_switch_margin 0..1 | default Margin a challenger must beat the incumbent by mid-conversation
semantic_router_proximity_bonus 0..1 | default Region-locality ranking bonus
semantic_router_fallback_endpoint_id <uuid> | default Endpoint used when nothing clears the floor
semantic_router_excluded_endpoint_ids <uuid,uuid,...> | none Endpoints kept out of semantic routing

default clears an override so the deployment default applies again; none clears the exclusion list. The two boolean keys also accept yes/no, on/off and 1/0, case-insensitively.

The 0..1 range is inclusive of both ends, and a value outside it is rejected rather than clamped. The router discards a value it cannot use and falls back to the deployment default, so a stored out-of-range number would save cleanly and then do nothing -- a setting that reads back as changed and changes no behaviour is worse than an error.

A key outside this table is rejected by the server, so a management key cannot reach unrelated project preferences through this endpoint.

Routing rules are not settable here. They have their own verbs, which mutate one rule at a time instead of asking you to retype the whole array.

rules list

Lists the project's rules in stored order, which is the order they were written, not the order they are evaluated in. The router evaluates by priority, highest first; read the Priority column, not the row order, to predict which rule fires. Stored order does matter for one thing: it is the index used in a validation error's param field. A rule whose target endpoint has since been deleted is still listed rather than hidden -- hiding it would hide the reason your routing broke.

bash
erectl semantic-router rules list erectl semantic-router rules list -o json

rules add

Adds a rule. Rules are evaluated in priority order above the classifier: when one fires, no embedding is computed and no ranking runs. The rule id is assigned by the server.

bash
erectl semantic-router rules add \ --name "Refactors" \ --query-contains "refactor,rewrite" \ --endpoint-id 11111111-2222-3333-4444-555555555555 \ --priority 10

Options

Option Description
--name <name> Rule display name (required)
--endpoint-id <uuid> Target endpoint (required)
--query-contains <list> Comma-separated substrings that must ALL appear in the query
--min-input-tokens <n> Only fire at or above this input-token count
--exact-request-model <name> Only fire for this requested model name
--priority <n> Evaluation order; higher runs first. Omit it and the server stores 0.
--disabled Create the rule without enabling it
--no-fallback-to-classification Fail the request instead of falling back to classification when the target cannot serve

A rule must be narrowed by at least one condition. A rule with an empty --query-contains and no token or model condition matches every request -- an all-satisfy over an empty list is vacuously true -- so it would hijack all of the project's traffic. Both the CLI and the server reject it.

Server-side limits: at most 20 rules per project, at most 10 --query-contains substrings per rule, and at most 200 characters per substring. The target must be a functional generative endpoint in the project; a suspended one is still a legal target.

rules update

Patches one rule. Only the options you supply change; every other field of that rule, and every other rule in the project, is carried through untouched by the server. At least one option is required.

bash
erectl semantic-router rules update 11111111-2222-3333-4444-555555555555 --priority 20 erectl semantic-router rules update 11111111-2222-3333-4444-555555555555 \ --query-contains "refactor,rewrite,extract"

Options

Option Description
--name <name> New display name
--endpoint-id <uuid> Repoint the rule at a different endpoint
--query-contains <list> New comma-separated substrings, replacing the stored list whole
--min-input-tokens <n> New input-token floor
--exact-request-model <name> New requested-model condition
--priority <n> New evaluation priority

update deliberately carries a narrower option set than add. --disabled and --no-fallback-to-classification do not exist here: use rules enable / rules disable for the switch, and delete and re-add to change the fallback behaviour. There is also no way to clear --min-input-tokens or --exact-request-model through a patch -- an omitted option means "leave it alone", so a rule that must lose a condition has to be deleted and re-added.

rules enable / disable

Flips a rule's participation without deleting it. Useful for bisecting a routing problem: disable the rule, watch erectl semantic-router health, re-enable.

bash
erectl semantic-router rules disable 11111111-2222-3333-4444-555555555555 erectl semantic-router rules enable 11111111-2222-3333-4444-555555555555

rules delete

Removes a rule. Prompts for confirmation unless --force is supplied.

bash
erectl semantic-router rules delete 11111111-2222-3333-4444-555555555555 erectl semantic-router rules delete 11111111-2222-3333-4444-555555555555 --force

decisions

Answers "why did this request go to that endpoint" for the last 24 hours, newest first. Each row shows the timestamp, the chosen endpoint, the cosine score behind the choice, the arm that produced it, the routing time, and an excerpt of the query.

This command returns prompt content from every workspace in the project. See Scope and Prompt Content.

bash
erectl semantic-router decisions erectl semantic-router decisions --limit 200 erectl semantic-router decisions -o json

Arms

Arm Meaning
rule A dynamic routing rule dispatched the request; the classifier never ran
fallback Nothing cleared the similarity floor, so the deterministic endpoint served the turn
direct No single cosine score governed the turn: the single-endpoint short-circuit, or multi-model dispatch
sticky Conversation affinity kept the incumbent endpoint
matched A fresh classifier match

--limit defaults to 50 and is clamped to 1..200; a non-numeric value is rejected rather than quietly defaulted. The 24-hour window is fixed and not a parameter. Excerpts are truncated to 500 characters at the moment they are recorded, and a row whose stored excerpt cannot be decrypted shows an empty preview rather than failing the page.

health

Counts and totals only. This command reads no prompt content, so it is safe to poll and safe to paste into a ticket.

bash
erectl semantic-router health erectl semantic-router health -o json

Fallback share is a percentage of classified decisions, not of all decisions. On a single-endpoint project the router short-circuits before classifying, and counting those turns would drive the ratio toward zero while telling you nothing about how classification is going.

Whole-Array Rule Writes

The routing rules live in a single stored array. The rule verbs each send one rule, and the server does the read-modify-write -- which is what lets it carry every other rule through untouched -- but it then validates the resulting array whole. One consequence is worth knowing before it surprises you: a pre-existing rule whose target endpoint has since been deleted will reject an edit to a completely unrelated rule.

The error names the offending rule in its param field, so you can see which one is blocking you:

text
Router returned HTTP 400: {"error":{"message":"Invalid dynamic routing rule at semantic_router_dynamic_rules[2].action.endpoint_id: Must reference a functional generative endpoint in this project","type":"invalid_request_error", "code":"invalid_semantic_router_config", "param":"semantic_router_dynamic_rules[2].action.endpoint_id"}}

The index is the rule's position in rules list. Delete or repoint that rule and the rest of your edits go through. Deleting the blocking rule always succeeds, so you can never be wedged.

Unavailable Endpoints

A setting can legitimately reference an endpoint the router cannot route over today -- a suspended endpoint that is still a valid fallback pin, an excluded endpoint you want to keep excluded, a rule aimed at an endpoint you have paused. Those endpoints do not appear in the routable list, so config show prints them under Referenced But Unavailable instead of silently omitting them.

Check that section before you rewrite semantic_router_excluded_endpoint_ids: the value you supply replaces the stored list whole, and an id you leave out is an exclusion you just removed. Rule edits do not have this hazard -- the server mutates the single rule you named and carries the rest through untouched, including rules aimed at unavailable endpoints.

Examples

Turn Semantic Routing On and Tune It

bash
erectl semantic-router config set semantic_router_enabled true # Require a stronger match before switching endpoints erectl semantic-router config set semantic_router_similarity_floor 0.35 erectl semantic-router config set semantic_router_switch_margin 0.15 # Confirm what the router now resolves erectl semantic-router config show

Pin Long Prompts to a Large-Context Endpoint

bash
erectl semantic-router rules add \ --name "Long context" \ --min-input-tokens 32000 \ --endpoint-id 11111111-2222-3333-4444-555555555555 \ --priority 100

Diagnose Unexpected Routing

bash
# Is classification falling back a lot? erectl semantic-router health # Which turns, and why erectl semantic-router decisions --limit 100 -o json # Suspect a rule? Disable it and watch the health counters erectl semantic-router rules disable 11111111-2222-3333-4444-555555555555