This guide covers AuraRouter's route analyzer subsystem: how analyzers work, how to build one, and how custom domain-specific intents flow through the routing pipeline.
A route analyzer is the component that classifies incoming tasks and decides which role (and therefore which model chain) handles execution. It sits at the top of the routing pipeline, above the ComputeFabric and provider layers.
Task Prompt
|
v
[Active Analyzer] -- classifies intent, assigns role
|
v
[Intent Registry] -- resolves intent -> target role
|
v
[ComputeFabric] -- executes through role's model chain
|
v
[Provider Layer] -- Ollama, llama.cpp, OpenAPI, MCP
Analyzers are registered as kind: analyzer artifacts in the unified catalog (catalog section of auraconfig.yaml). The active analyzer is set via system.active_analyzer.
The built-in aurarouter-default analyzer uses intent classification with complexity-based triage routing. It asks a fast router model to classify the task (e.g., SIMPLE_CODE, COMPLEX_REASONING, DIRECT) and assign a complexity score (1-10). Based on these, it routes to the appropriate role chain.
- Simple tasks (complexity 1-3) go straight to execution.
- Moderate tasks (4-7) go through Plan then Execute.
- Complex tasks (8-10) go through Plan, Execute, Review, and optionally Correct.
This analyzer is auto-registered on server startup if not already present.
A remote Mixture-of-Experts analyzer provided by AuraXLM. When active, AuraRouter delegates the routing decision to AuraXLM via MCP JSON-RPC. AuraXLM returns a ranked list of models and a recommended role.
The MCP tool interface is defined in contracts/auraxlm.py:
ANALYZE_ROUTE_PARAMS = {
"prompt": {"type": "string", "required": True},
"intent": {"type": "string", "required": False},
"candidates": {"type": "array", "items": "ModelMetadata", "required": False},
"cost_ceiling": {"type": "number", "required": False},
"latency_ceiling_ms": {"type": "number", "required": False},
"top_n": {"type": "integer", "required": False, "default": 3},
}Any external system can act as an analyzer by implementing the MCP endpoint contract (see Section 6) and declaring custom intents via role_bindings. For example, a SAR processing system might declare intents like sar_coherent_change, sar_detection, and sar_geolocation that map to specialized roles.
Analyzers are registered in the unified catalog via catalog_set() or the aurarouter catalog register CLI command.
catalog:
my-sar-analyzer:
kind: analyzer
display_name: SAR Processing Analyzer
description: Domain-specific analyzer for SAR imagery workflows
analyzer_kind: intent_triage
capabilities: [sar, geolocation, detection]
role_bindings:
sar_coherent_change: reasoning
sar_detection: coding
sar_geolocation: reasoning
explain_result: reasoning
chat: codingaurarouter catalog register my-sar-analyzer \
--kind analyzer \
--display-name "SAR Processing Analyzer"{
"tool": "aurarouter.catalog.register",
"arguments": {
"artifact_id": "my-sar-analyzer",
"kind": "analyzer",
"display_name": "SAR Processing Analyzer",
"analyzer_kind": "intent_triage",
"role_bindings": {
"sar_coherent_change": "reasoning",
"sar_detection": "coding"
}
}
}aurarouter analyzer set my-sar-analyzerOr via MCP: aurarouter.analyzer.set_active(analyzer_id="my-sar-analyzer")
Analyzer artifacts use the following spec fields (merged at the top level in YAML alongside the common kind, display_name, etc. fields):
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
analyzer_kind |
string |
Yes | -- | Analyzer type identifier. Known values: "intent_triage", "moe_ranking". Custom values are allowed. |
role_bindings |
dict[str, str] |
No | {} |
Maps intent names to target roles. Each key becomes a custom intent; each value must be a configured role name. |
mcp_endpoint |
string (URL) |
No | null |
MCP JSON-RPC endpoint for remote analyzers. When set, the analyzer is considered remote. |
mcp_tool_name |
string |
No | null |
The MCP tool name to call on the remote endpoint (e.g., "auraxlm.analyze_route"). |
capabilities |
list[str] |
No | [] |
Declared capabilities for catalog query matching (e.g., ["code", "reasoning", "sar"]). |
description |
string |
No | "" |
Human-readable description shown in the GUI and CLI. |
The validate_analyzer_spec() function in analyzer_schema.py checks:
- Required fields are present (
analyzer_kind). role_bindingskeys are valid Python identifiers.role_bindingsvalues reference configured roles (whenavailable_rolesis provided).mcp_endpointis a well-formed URL if present.capabilitiesis a list of strings if present.
Validation is warn-only for backwards compatibility. The result is an AnalyzerSpecValidation dataclass:
@dataclass
class AnalyzerSpecValidation:
valid: bool # True if no errors
warnings: list[str] # Non-fatal issues
errors: list[str] # Fatal issues (e.g., missing analyzer_kind)
declared_intents: list[str] # Intent names extracted from role_bindingsThe role_bindings dict is the mechanism by which analyzers declare custom intents. Each key is treated as an intent name, and its value is the target role that handles tasks classified under that intent.
- When an analyzer is set as active,
build_intent_registry()reads itsrole_bindingsfrom the catalog. - Each key-value pair is converted into an
IntentDefinitionwithpriority=10(higher than built-in priority of 0). - These definitions are registered in the
IntentRegistry, making them available for classification. - If a custom intent has the same name as a built-in intent, the higher-priority custom intent wins.
role_bindings:
sar_coherent_change: reasoning # New custom intent -> reasoning role
sar_detection: coding # New custom intent -> coding role
SIMPLE_CODE: coding # Overrides the built-in SIMPLE_CODE- Keys must be valid Python identifiers (letters, digits, underscores; cannot start with a digit).
- Values must reference roles that exist in the
rolessection ofauraconfig.yaml. - If a value references a non-existent role, validation produces a warning (not an error).
Remote analyzers communicate via MCP JSON-RPC. When a remote analyzer is active, route_task sends a tools/call request to the analyzer's mcp_endpoint.
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "<mcp_tool_name>",
"arguments": {
"prompt": "The user's task description",
"intent": "optional_intent_hint",
"candidates": [
{"model_id": "...", "provider": "...", "capabilities": [...]}
]
}
},
"id": 1
}The analyzer should return a JSON-RPC result with routing decisions:
{
"jsonrpc": "2.0",
"result": {
"content": [
{
"type": "text",
"text": "{\"role\": \"coding\", \"ranked_models\": [\"model-a\", \"model-b\"], \"reasoning\": \"...\"}"
}
]
},
"id": 1
}The text field contains a JSON string with:
| Field | Type | Description |
|---|---|---|
role |
string |
The role to route to (e.g., "coding", "reasoning") |
ranked_models |
list[str] |
Ordered list of model IDs to try |
reasoning |
string |
Human-readable explanation of the routing decision |
If the remote analyzer is unreachable, returns an error, or times out, AuraRouter automatically falls back to the built-in aurarouter-default analyzer. This ensures tasks always get processed.
Custom intents flow through five stages from declaration to execution:
An analyzer declares intents via role_bindings in its catalog spec:
role_bindings:
sar_detection: codingWhen the analyzer is set as active, build_intent_registry() calls register_from_role_bindings(), which creates an IntentDefinition for each entry:
IntentDefinition(
name="sar_detection",
description="Intent 'sar_detection' declared by analyzer 'my-sar-analyzer'",
target_role="coding",
source="my-sar-analyzer",
priority=10,
)During route_task, the router model classifies the user's prompt. The IntentRegistry.build_classifier_choices() method generates the prompt listing all available intents (built-in + custom) with their descriptions. The router model returns a JSON object like:
{"intent": "sar_detection", "complexity": 5}Alternatively, the user can force a specific intent via the CLI --intent flag or the GUI intent combobox, bypassing classification entirely.
The IntentRegistry.resolve_role() method maps the classified intent to its target role:
role = registry.resolve_role("sar_detection") # Returns "coding"The ComputeFabric executes the task through the resolved role's model chain. If models declare supported_intents, the chain is filtered via filter_chain_by_intent() to prefer models that explicitly support the classified intent:
filtered = fabric.filter_chain_by_intent(chain, "sar_detection")If no models in the chain declare supported_intents, the full chain is used (backwards compatible).
Routing advisors are MCP services that can reorder a role's model chain before execution. They sit between intent classification and model execution.
Register a routing advisor programmatically:
fabric.register_routing_advisor(client)Or declare a service in the catalog with the routing_advisor capability for auto-registration:
catalog:
my-advisor-service:
kind: service
display_name: My Routing Advisor
capabilities: [routing_advisor]
endpoint: http://advisor-host:9090During execution, ComputeFabric.consult_routing_advisors() queries each registered advisor:
chain = fabric.consult_routing_advisors(role, chain, intent="sar_detection")Advisors with the chain_reorder capability receive the role, current chain, and classified intent. They return a reordered chain. If no advisor responds (or all fail), the original chain is used.
| Method | Description |
|---|---|
register_routing_advisor(client) |
Register an MCP client as a routing advisor. Idempotent. |
unregister_routing_advisor(client_id) |
Remove an advisor by its identifier. |
list_routing_advisors() |
Return identifiers of all registered advisors. |
consult_routing_advisors(role, chain, intent=None) |
Query advisors for chain reordering. |
This walkthrough builds a complete analyzer for SAR (Synthetic Aperture Radar) image processing.
Decide what domain-specific intents your system needs:
| Intent | Target Role | Description |
|---|---|---|
sar_coherent_change |
reasoning |
Multi-step coherent change detection |
sar_detection |
coding |
Target detection in SAR imagery |
sar_geolocation |
reasoning |
Geolocation and coordinate extraction |
explain_result |
reasoning |
Explain processing results |
chat |
coding |
General questions about SAR |
Add to auraconfig.yaml:
catalog:
sar-processor:
kind: analyzer
display_name: SAR Processing Analyzer
description: Domain-specific intents for SAR imagery workflows
analyzer_kind: intent_triage
capabilities: [sar, geolocation, detection, coherent-change]
role_bindings:
sar_coherent_change: reasoning
sar_detection: coding
sar_geolocation: reasoning
explain_result: reasoning
chat: codingIf you want certain models to handle specific intents, declare supported_intents on the model artifact:
catalog:
sar-specialist-model:
kind: model
display_name: SAR Specialist
provider: ollama
supported_intents: [sar_coherent_change, sar_detection, sar_geolocation]When this model is in a role's chain and the classified intent matches, filter_chain_by_intent() will prefer it over models that do not declare support.
aurarouter analyzer set sar-processor# List all intents including the new SAR ones
aurarouter intent list
# Describe a specific intent
aurarouter intent describe sar_detection
# Route a task with explicit intent
aurarouter run "Detect targets in SAR scene" --intent sar_detectionIn the GUI workspace panel, the intent combobox will show your SAR intents under an "Analyzer: SAR Processing Analyzer" group. Select one to bypass auto-classification.
AuraRouter includes two reference analyzer contracts that serve as templates:
The AuraCode contract defines intents for code-focused workflows:
AURACODE_INTENTS = {
"generate_code": "coding",
"edit_code": "coding",
"complete_code": "coding",
"explain_code": "reasoning",
"review": "reasoning",
"chat": "reasoning",
"plan": "reasoning",
}
def create_auracode_analyzer_spec() -> dict:
"""Return the canonical analyzer spec for an AuraCode-compatible analyzer."""
return {
"analyzer_kind": "intent_triage",
"role_bindings": AURACODE_INTENTS,
"capabilities": ["code", "reasoning", "review", "planning"],
}The AuraXLM contract defines the MoE ranking analyzer interface:
AURAXLM_ANALYZER_SPEC = {
"analyzer_kind": "moe_ranking",
"capabilities": ["code", "reasoning", "review", "planning", "domain-expert"],
"mcp_tool_name": "auraxlm.analyze_route",
}It also defines ANALYZE_ROUTE_PARAMS (the expected parameters for the auraxlm.analyze_route tool) and ANALYZE_ROUTE_RESPONSE (the expected response schema).
See also:
- README.md for the intent classification overview
- DEPLOYMENT.md for configuration reference
- BACKEND_PLUGINS.md for backend vs. analyzer plugin comparison