Skip to content

Routing Specification — daari

Status: Draft v1.0 — pre-implementation
Related: PRD · ADR-0004 · PLAN-REVIEW
Fixes: Plan review issue #3


Purpose

Define how daari classifies requests, selects tiers, scores confidence, and escalates — so routing is testable before code is written.


Routing pipeline (ordered)

1. Normalize request
2. Check headers (X-Daari-Tier-Override, X-Daari-No-Cache)
3. L0 exact cache lookup
4. CCS command context lookup           [Phase B — ADR-0008]
5. L1 semantic cache lookup              [Phase B]
6. L2-dev developer command rules        [Phase B — ADR-0008]
7. L2 generic rules match              [Phase B]
8. Lt tool-native match / execute        [Phase B]
9. Classify task → initial model tier (L3 default in MVP)
10. Execute at tier
11. Confidence check on result           [Phase A.1 for L6 escalation]
12. Escalate L3 → L4 → L5 → L6 if below threshold
13. Cache write: CCS after Lt; L0 if cacheable
14. Return response + daari_meta

MVP (Phase A): Steps 1–3, 7 (heuristic only), 8 at L3 only, 11–12. No L1/L2/Lt/L4/L5/L6.


Classifier inputs

The router reads these signals from each request:

Signal Source Used for
message_count messages array length Multi-turn → skip L0 for some keys
total_tokens Estimated token count Size buckets (see below)
last_user_content Final user message text Keywords, regex, Lt patterns
has_tool_calls Request/response history Agent round — see ADR-0004
tools_defined tools array present Agent mode — routing restrictions
model_requested model field Client hint; daari may override internally
stream boolean Affects execution, not tier selection
temperature float Included in L0 cache key
X-Daari-* headers HTTP headers Override / no-cache

Not used in MVP: embeddings, SLM classifier (Phase B hybrid).


Heuristic classifier (Phase A — MVP)

Simple rule chain evaluated top-to-bottom; first match wins for tier ceiling (max tier allowed before escalation logic):

Rule ID Condition Max tier Rationale
R-A1 total_tokens < 50 AND matches classify regex¹ L3 Tiny classification
R-A2 total_tokens < 200 AND matches transform regex² L3 Small reformat/extract
R-A3 total_tokens < 500 L3 Default small local
R-A4 total_tokens ≥ 500 AND < 2000 L4 Medium generation [Phase B]
R-A5 total_tokens ≥ 2000 L6 Large context — skip local in MVP, escalate [Phase A.1]

¹ Classify regex (examples): (?i)(is this|classify|which type|yes or no|true or false)
² Transform regex (examples): (?i)(format|reformat|convert to json|extract|parse)

MVP simplification: All requests → L3 unless L0 cache hit. Heuristic rules logged but only affect Phase A.1 escalation.


Hybrid classifier (Phase B — v1)

Stage Method Output
1 Heuristic rules (above) Candidate tier + task type
2 Lt pattern registry Lt if high-confidence tool match
3 SLM prompt (L3) { task_type, suggested_tier, confidence } if heuristic ambiguous

Ambiguous = heuristic returns default AND total_tokens in 200–800 range AND no Lt match.


Task types

Type Description Typical tier
cache_hit Exact or semantic match L0 / L1
rule Deterministic transform L2
tool CLI/IDE dispatch Lt
classify Label, route, score L3
extract Pull structured data L3
transform Reformat, light edit L3
generate_small Short completion L3 / L4
generate_large Long reasoning, multi-file L5 / L6
agent_turn Has tool_calls in history L3+ (see ADR-0004)

Confidence scoring

Phase A (MVP)

No confidence scoring. L3 result always returned. L6 disabled.

Phase A.1+

Tier Confidence source Pass threshold Fail action
L3 Heuristic: response length > 10 chars AND no refusal phrases³ 0.7 (binary mapped) Escalate to L4
L4 SLM self-eval prompt: "Rate 1-5 completeness" ≥ 4/5 Escalate to L5
L5 Same self-eval ≥ 4/5 Escalate to L6
L6 N/A — terminal — Return or error

³ Refusal phrases: (?i)(i cannot|i can't|as an ai|i don't have access)

Phase B improvement: Use logprobs from Ollama when available; fall back to self-eval.

Escalation policy

L3 fail → L4 (if configured) → L5 (if configured) → L6 (if frontier.enabled)

If frontier.enabled: false and all local tiers fail → return best local attempt + daari_meta.warning: "below_confidence_threshold".

Config keys:

confidence:
  l3_min: 0.7
  l4_min: 0.8
  l5_min: 0.8
frontier:
  enabled: true


L2-dev — developer command rules (Phase B)

Purpose: Fine-tuned for coding/enterprise — detect execute command vs ask model.

Rule ID Trigger (regex / intent) Action Lt command
DEV-01 (?i)^(run \|execute )?(git status) execute git status
DEV-02 (?i)^(run \|execute )?(git diff) execute git diff
DEV-03 (?i)(run tests\|npm test\|pytest) execute project test command from config
DEV-04 (?i)(run lint\|eslint\|run linter) execute lint command from config
DEV-05 (?i)run (script )?(\./[\w./-]+\.(sh\|py)) execute script path (validated under repo)
DEV-06 (?i)(what did (test\|lint) (say\|show)\|last test output) ccs_read no execution — inject CCS
DEV-07 (?i)(re-run\|run again) (tests\|lint) execute + invalidate CCS force fresh Lt run

Project overrides: .daari/commands.yaml maps intent aliases → shell command (enterprise teams).

# .daari/commands.yaml example
commands:
  test: "npm test"
  lint: "npm run lint"
  build: "./gradlew build"
allow_scripts:
  - "./scripts/ci-check.sh"

CCS — command context store (Phase B)

Not L0. Stores execution results for developer reuse.

Key:

SHA256(repo_root + cwd + normalized_command)

On Lt execute success: write CCS entry (stdout summary + path to full log, exit code, TTL).

On DEV-06 / readonly query: return CCS content in response; tier = CCS in daari_meta.

TTL defaults:

Command type TTL
git status, git diff 60s
test/lint 300s
build 600s
scripts configurable

Headers: X-Daari-ReRun-Command: true bypasses CCS read.


Lt matching (Phase B)

Lt runs only when pattern match confidence ≥ 0.95. Patterns are explicit — no free-form NLP in v1.

Pattern ID Trigger (regex on last user message) Tool Destructive?
LT-01 (?i)run (eslint|lint) eslint No
LT-02 (?i)format (this |the )?(file|code) prettier No
LT-03 (?i)git status git status No
LT-04 (?i)git diff git diff No
LT-05 (?i)rename (symbol|method|class) intellij refactor Yes
LT-06 (?i)optimize imports intellij No

Destructive ops (LT-05+): Require X-Daari-Confirm-Tool: true header or config tools.auto_confirm: false (default) → return confirmation prompt instead of executing.


L0 cache key

SHA256(
  normalize(messages) +
  model +
  temperature +
  tools_schema_hash +    # see ADR-0004
  tier_override_or_none
)

Skip L0 if X-Daari-No-Cache: true. Agent turns (tools / tool_calls in history) use the same exact key (full messages + tools schema); a changed last tool result is a miss. L1 stays off for agent turns (ADR-0004 / G1).


Golden prompt eval set

File: evals/routing/prompts.jsonl (to be created at implementation)

ID Prompt (summary) Expected tier (MVP) Expected tier (v1)
GP-01 Exact repeat of prior request L0 L0
GP-02 "Is this a test file?" + 20 lines Java L3 L3
GP-03 "Format as JSON: {foo: 1}" L3 L2 or L3
GP-04 "Write commit message for: " + small diff L3 L3
GP-05 Same commit message request (repeat) L0 L0
GP-06 "Run eslint on src/" L3 Lt
GP-07 "git status" L3 Lt
GP-08 "Explain microservices vs monolith" (500+ words) L3 L6
GP-09 "Add docstring to this 10-line function" L3 L3
GP-10 "Refactor this 500-line class for SOLID" L3 L5/L6
GP-11 "What does this regex match?" (short) L3 L3
GP-12 Paraphrase of GP-04 (same intent) L3 L1
GP-13 "Rename method foo to bar in UserService" L3 Lt (confirm)
GP-14 "Convert this YAML to JSON" (small) L3 L2/L3
GP-15 "Summarize this 3-line error log" L3 L3
GP-16 "Generate unit tests for Calculator" L3 L4
GP-17 Empty/minimal prompt "hi" L3 L3
GP-18 Prompt with tools defined (agent) L3 L3 (passthrough rules)
GP-19 "Optimize imports in User.java" L3 Lt
GP-20 Multi-turn: 5 messages debugging session L3 L3/L4

MVP pass criteria: GP-01, GP-05 hit L0; GP-02–GP-04, GP-09, GP-11, GP-15, GP-17 route to L3; no silent failures.

v1 pass criteria: ≥90% match expected tier on GP-01–GP-20.


daari_meta response shape

{
  "daari_meta": {
    "tier": "L3",
    "task_type": "generate_small",
    "cache_hit": false,
    "executor": "ollama",
    "model": "llama3.2:3b",
    "latency_ms": 842,
    "confidence": 0.85,
    "escalated_from": null,
    "rule_id": "R-A3"
  }
}

Open items (tracked elsewhere)

Item ADR / doc
Tool-call cache/routing ADR-0004
Lt destructive confirmation ADR-0003, ADR-0012, PRD #14, #75
Execution policy (allow/deny/ask) ADR-0012
Semantic cache thresholds OD-3