{"id":"affa5267-5055-4833-b71a-58bffacad199","entityType":"agent","slug":"clawhub-fanyadan-super-router","name":"Super Router","canonicalUrl":"https://www.xpersona.co/agent/clawhub-fanyadan-super-router","canonicalPath":"/agent/clawhub-fanyadan-super-router","generatedAt":"2026-10-12T04:04:12.306Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-12T01:15:28.405Z","emptyReason":null},"description":"LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalat... Skill: Super Router Owner: fanyadan Summary: LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalat... Tags: latest:0.1.5, openclaw:0.1.5 Version history: v0.1.5 | 2026-06-30T07:36:35.571Z | user Document dependency DAG handling and runtime dependencies in SKILL.md. v0.1.4 | 2026-06-30T06:29:44.925Z | user Improve t","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 962 downloads reported by the source. Last updated 10/12/2026.","installCommand":"clawhub skill install s179ht9jn7zkzxwewsg4b9ztw585qv9t:super-router","sourceUrl":"https://clawhub.ai/fanyadan/super-router","homepage":"https://clawhub.ai/fanyadan/skills/super-router","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/fanyadan/super-router","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/fanyadan/skills/super-router","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalat..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-12T01:15:28.405Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-12T01:15:28.405Z","emptyReason":null},"stars":null,"forks":null,"downloads":962,"likes":null,"task":null,"library":null,"packageName":null,"latestVersion":"0.1.5","tractionLabel":"962 downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-12T01:15:28.392Z","emptyReason":null},"lastUpdatedAt":"2026-10-12T01:15:28.405Z","lastCrawledAt":"2026-10-12T01:15:28.392Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-13T01:15:28.392Z","lastVerifiedAt":null,"highlights":[{"version":"0.1.5","createdAt":"2026-06-30T07:36:35.571Z","changelog":"Document dependency DAG handling and runtime dependencies in SKILL.md.","fileCount":16,"zipByteSize":100223},{"version":"0.1.4","createdAt":"2026-06-30T06:29:44.925Z","changelog":"Improve the ClawHub introduction and public summary while preserving the script invocation instructions in the skill body.","fileCount":16,"zipByteSize":99293},{"version":"0.1.3","createdAt":"2026-06-30T05:20:42.191Z","changelog":"Refresh ClawHub package to current OpenClaw implementation: Codex/Claude/Gemini provider routing, dependency-aware scheduling, token usage accounting, LangSmith tracing, updated docs, and regression tests.","fileCount":16,"zipByteSize":99490},{"version":"0.1.2","createdAt":"2026-05-10T14:26:59.575Z","changelog":"Improved parallelism mode.","fileCount":7,"zipByteSize":50228},{"version":"0.1.1","createdAt":"2026-04-28T06:40:49.085Z","changelog":"Initial release","fileCount":6,"zipByteSize":47667},{"version":"0.1.0","createdAt":"2026-04-28T04:40:58.276Z","changelog":"Initial release","fileCount":6,"zipByteSize":45870}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s179ht9jn7zkzxwewsg4b9ztw585qv9t:super-router","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-12T04:04:12.300Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-fanyadan-super-router/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-12T01:15:28.405Z","emptyReason":null},"readme":"Skill: Super Router\n\nOwner: fanyadan\n\nSummary: LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalat...\n\nTags: latest:0.1.5, openclaw:0.1.5\n\nVersion history:\n\nv0.1.5 | 2026-06-30T07:36:35.571Z | user\n\nDocument dependency DAG handling and runtime dependencies in SKILL.md.\n\nv0.1.4 | 2026-06-30T06:29:44.925Z | user\n\nImprove the ClawHub introduction and public summary while preserving the script invocation instructions in the skill body.\n\nv0.1.3 | 2026-06-30T05:20:42.191Z | user\n\nRefresh ClawHub package to current OpenClaw implementation: Codex/Claude/Gemini provider routing, dependency-aware scheduling, token usage accounting, LangSmith tracing, updated docs, and regression tests.\n\nv0.1.2 | 2026-05-10T14:26:59.575Z | user\n\nImproved parallelism mode.\n\nv0.1.1 | 2026-04-28T06:40:49.085Z | user\n\nInitial release\n\nv0.1.0 | 2026-04-28T04:40:58.276Z | user\n\nInitial release\n\nArchive index:\n\nArchive v0.1.5: 16 files, 100223 bytes\n\nFiles: README.md (29883b), references/background-artifact-launches.md (2893b), references/gemini-cli-ripgrep-path-fix.md (1311b), references/gemini-cli-token-recovery.md (4675b), references/gemini-temperature-gap.md (1907b), references/linux-mm-source-html-example.md (4187b), references/long-running-quantitative-tasks.md (1508b), references/source-html-background-wrapper.md (4327b), scripts/render_super_router_diagram.py (21961b), scripts/router.py (215311b), skill-card.md (3275b), SKILL.md (24918b), templates/source-html-background-wrapper.sh (3244b), tests/__init__.py (1b), tests/test_router.py (60203b), _meta.json (131b)\n\nFile v0.1.5:SKILL.md\n\n---\nname: super-router\ndescription: \"LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalates failures, and records token usage for auditable runs.\"\nversion: 1.0.0\nauthor: Yadan Fan\nlicense: MIT\nmetadata:\n  openclaw:\n    tags: [model-routing, langgraph, task-decomposition, multi-model, complexity-scoring]\n    requires:\n      bins: [python]\n  related_skills: [btc_analyzer, api-tester, ddg-search]\n---\n\n# Super Router (LangGraph Edition)\n\nSuper Router decomposes complex work into dependency-aware subtasks, scores each branch for complexity and risk, and executes it on the right model role. It combines PRO/FLASH routing, provider fallback, FLASH retry and escalation, metadata extraction, LangSmith tracing, and token usage accounting into one auditable LangGraph workflow.\n\n## Mandatory OpenClaw Invocation\n\nFor any request to use `super-router`, `super_router`, or `走 super-router`, do this exact workflow:\n\n1. Use the OpenClaw `exec` tool to run:\n   `/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py '<task>'`\n2. If `exec` returns `Command still running`, call the OpenClaw `process` tool with `action=\"poll\"` on the returned `sessionId` until the process exits.\n3. The next assistant message after completion must start with `Router result:` or `Router failed:` and must include a concrete detail from the router output.\n\nDo not run `openclaw super_router`, `openclaw super-router`, `openclaw skill`, `openclaw skills`, or a nested `openclaw agent` command to satisfy this skill. Those are not the router.\n\n## When to Use This Skill\n\nUse super-router when you need:\n- **Intelligent model routing** — automatically choose between heavy (PRO) and fast (FLASH) models per subtask\n- **Task decomposition** — break complex tasks into structured subtasks with independent routing\n- **Cost optimization** — use fast models for simple work, heavy models only when needed\n- **Configurable models** — use deterministic defaults, with environment-variable overrides for each role\n- **Failure escalation** — FLASH retry on infra failures, escalate to PRO on capability failures\n- **Audit trail** — full logging of planned vs actual routes, retries, and failure classifications\n\n**Not needed for:** Simple single-turn tasks, tasks where you already know which model to use, or when you want manual control over every routing decision.\n\n## Optimization for Parallelism\n\nTo achieve true parallel execution (when `ROUTER_MAX_CONCURRENCY > 1`), the Planner must be instructed to use **Atomic Decomposition**. \n\n- **Atomic Decomposition**: Breaking a task into the smallest possible independent units rather than grouped phases.\n- **Pitfall: Planner Grouping**: The Planner may occasionally group multiple entities into a single subtask, which kills true parallelism.\n- **Verification**: Always verify the `planned_subtasks` count matches the entity count. If the planner groups entities, treat as capability failure and retry with correction prompt.\n- **Benefit**: Prevents 'lost-in-the-middle' failures and allows executor branches to fire simultaneously.\n- **Deferred synthesis**: Summary and synthesis subtasks are held until independent executor branches finish.\n- **Implementation**: Explicitly demand atomic per-entity decomposition when prompting for multi-entity tasks.\n\n## Core Architecture (LangGraph StateGraph)\n\n| Node | Function |\n|------|----------|\n| **Planner** | Decomposes original task into a JSON array of atomic, actionable subtasks. Uses Atomic Decomposition for maximum parallelism. |\n| **Judge** | Scores each subtask on 5 dimensions: `reasoning_depth`, `code_change_scope`, `ambiguity`, `risk`, `io_heaviness`; combines with thresholds + confidence to decide PRO/FLASH |\n| **Executor Fanout** | Uses LangGraph `Send(...)` to dispatch independent subtasks concurrently, then joins ordered results by original step number |\n| **PRO Executor Branch** | Heavy reasoning model (override via `ROUTER_PRO_MODEL`) |\n| **FLASH Executor Branch** | Fast model with review/retry logic (override via `ROUTER_FLASH_MODEL`) |\n| **FLASH Review** | Validates output quality; distinguishes infra failures from capability failures; retries FLASH or escalates to PRO |\n| **Metadata Extractor** | Extracts 'Technical Gold' (atomic high-precision facts) from step output to prevent finalizer timeouts and loss of detail |\n| **Recorder/Finalizer** | Logs every step; compiles final report using a hybrid of Technical Gold and full audit trails; supports FLASH→PRO→deterministic fallback chain |\n\n## Dependency Handling\n\nDependency handling is part of the router's execution contract, not just a\nplanning hint.\n\n- The Planner must return subtasks with stable IDs plus `depends_on` and\n  `dependency_reason` fields. Independent subtasks should use `depends_on: []`.\n- The dependency judge verifies and corrects only dependency edges and reasons;\n  it must keep the planner's existing subtask IDs and must not add, remove,\n  merge, split, or rewrite subtasks.\n- The dependency validator rejects duplicate IDs, unknown dependency IDs,\n  self-dependencies, and cycles. If validation fails, the router falls back to a\n  conservative serial dependency chain instead of crashing the graph.\n- `dependency_scheduler` computes the ready set on each wave. A subtask is ready\n  only when every ID in `depends_on` has completed.\n- Ready subtasks are dispatched with LangGraph `Send(...)`; completed wave\n  results are joined, ordered by original step, and scheduling repeats until all\n  subtask IDs are complete.\n- Executor prompts include direct dependency results for the active subtask.\n  This keeps synthesis, comparison, validation-after-implementation, and final\n  reporting work from running before their evidence-producing branches finish.\n- If remaining work exists but no subtask is ready, `dependency_deadlock`\n  records blocked fallback results and errors so the finalizer can report the\n  dependency issue.\n\nFor maximum parallelism, prompt multi-entity work as atomic per-entity\ndecomposition, and ensure final synthesis/reporting subtasks depend on the\nevidence-producing subtasks they summarize.\n\n## Runtime Dependencies\n\n- Python 3.10+ is required.\n- `langgraph` is the required Python runtime dependency.\n- `langsmith` is optional and used only when LangSmith telemetry is enabled.\n- `Pillow` is optional and needed only when regenerating `super-router.png`.\n- At least one model provider must be available for the selected model names:\n  Codex CLI, Gemini CLI, Claude Code CLI, or Ollama.\n\n## Installation\n\n```bash\n# Required: LangGraph\npip install langgraph\n\n# Optional: LangSmith telemetry\npip install langsmith\n\n# Optional: architecture diagram regeneration\npip install pillow\n```\n\nAll model and provider choices are configured via `ROUTER_*` variables in the OpenClaw environment config file `~/.openclaw/.env`. The router loads that file itself and still honors any explicit process environment overrides. No model names are hardcoded in the skill.\n\n## Usage\n\n### Configuring ROUTER_* Variables\n\nSet `ROUTER_*` environment variables in `~/.openclaw/.env`. OpenClaw normally exposes this file to `exec` child processes, and `router.py` also loads it directly before reading `os.environ`, so the same command works from OpenClaw and from a plain shell.\n\nTo see current values: `grep '^ROUTER_' ~/.openclaw/.env`\n\nTo use one model for every router role, set `ROUTER_MODEL`:\n\n```bash\nROUTER_MODEL=gpt-5.5\n# Equivalent explicit form:\n# ROUTER_MODEL=codex/gpt-5.5\n```\n\nRole-specific variables such as `ROUTER_PRO_MODEL` and `ROUTER_FLASH_MODEL` override `ROUTER_MODEL` when set.\n\n### Basic Usage (via OpenClaw exec)\n\nWhen the user says \"走 super-router\", \"use super-router\", or asks for router analysis, invoke `router.py` directly through OpenClaw `exec`:\n\n```python\nexec(\n    command=\"/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py 'Analyze K8s YAML errors and rewrite config'\"\n)\n```\n\n### With Streaming (Node-Level Progress)\n\n```python\nexec(command=\"/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py --stream 'Your complex task'\")\n```\n\n### Via Environment Variable (Agent Compatibility)\n\nFor agents that struggle with non-ASCII arguments, pass the task via `ROUTER_TASK`:\n\n```python\nexec(\n    command=\"/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py\",\n    env={\"ROUTER_TASK\": \"Your complex task description\"},\n)\n```\n\n### Handling Long-Running Execution\n\nIf `exec` returns \"Command still running\":\n\n```python\n# Continue polling with process tool\nprocess(action=\"poll\", session_id=\"<session_id_from_exec>\")\n\n# Wait for completion\nprocess(action=\"wait\", session_id=\"<session_id_from_exec>\", timeout=300)\n```\n\nFor background launches requested by the user, use `exec(background=true, notify_on_complete=true)` and verify the process is actually running with an immediate `process(action=\"poll\")`. If a background router launch exits immediately, inspect the preview and relaunch with the fix rather than reporting success.\n\nFor complex or multiline `ROUTER_TASK` prompts, avoid fragile inline heredocs inside `zsh -lic`. Write the task to a prompt file first, then launch with:\n\n```bash\nexport ROUTER_TASK=\"$(/bin/cat \"$HOME/.openclaw/logs/<task-name>.txt\")\"\n/opt/homebrew/Caskroom/miniforge/base/bin/python \"$HOME/.openclaw/skills/super-router/scripts/router.py\" --stream 2>&1 | tee \"$HOME/.openclaw/logs/<task-name>.log\"\n```\n\nThis preserves quotes/apostrophes in the task, keeps an auditable prompt artifact, and avoids zsh parse failures from nested heredocs.\n\n**Important:** Once process shows completion, your next assistant message MUST start with `Router result:` or `Router failed:` and include at least one real detail from the output (e.g., \"Planner fallback\", \"timeout\", \"BTC\"). Never reply with just `---`, punctuation, or empty lines.\n\n### Post-Completion Artifact Verification\n\nFor router runs that create or modify artifacts (reports, JSON logs, database ingests, generated files), do not trust the router final stdout alone. Before reporting success to the user:\n\n1. Inspect the declared output artifacts directly (`stat`, read the JSON/Markdown headers, count expected sections/cards when relevant).\n2. Compare the router final summary against the saved artifacts and machine-readable logs.\n3. If stdout and artifacts disagree, treat the artifacts/logs as the source of truth and report the discrepancy immediately.\n4. If the discrepancy means the user requirement is not satisfied (for example, requested 20 items but artifact contains 33), do not claim success. Either launch a correction pass when permitted or state the exact blocker.\n5. For ingestion workflows, verify the saved ingest JSON fields (`status`, checked/accepted/skipped counts, threshold, document list) and ensure the user-facing Markdown/HTML item set matches the accepted ingested documents.\n\n## Environment Variables\n\nAll `ROUTER_*` variables are loaded from `~/.openclaw/.env` by `router.py` before the router resolves defaults. Explicit process environment values win over `.env` values.\n\n| Variable | Purpose | Default |\n|----------|---------|---------|\n| `ROUTER_MODEL` | Global model default for planner, judge, PRO, and FLASH roles | None |\n| `ROUTER_PLANNER_MODEL` | Task decomposition model | internal default |\n| `ROUTER_PLANNER_TASK_CHAR_LIMIT` | Character budget for the compact planner-only context manifest JSON | 6000 |\n| `ROUTER_PLANNER_MAX_OUTPUT_TOKENS` | Planner JSON subtask output token cap | 4096 |\n| `ROUTER_JUDGE_CONTEXT_CHAR_LIMIT` | Character budget for judge context JSON | 3000 |\n| `ROUTER_EXECUTOR_CONTEXT_CHAR_LIMIT` | Character budget for executor context JSON | 8000 |\n| `ROUTER_METADATA_OUTPUT_CHAR_LIMIT` | Character budget for metadata extraction context JSON and output excerpts | 6000 |\n| `ROUTER_FINALIZER_CONTEXT_CHAR_LIMIT` | Character budget for finalizer context JSON | 12000 |\n| `ROUTER_JUDGE_MODEL` | Complexity scoring model | internal default |\n| `ROUTER_PRO_MODEL` | Heavy reasoning executor | internal default |\n| `ROUTER_FLASH_MODEL` | Fast executor | internal default |\n| `ROUTER_PRO_FALLBACK_MODELS` | Comma-separated PRO fallback list | None |\n| `ROUTER_FLASH_FALLBACK_MODELS` | Comma-separated FLASH fallback list | None |\n| `ROUTER_CODEX_CLI` | Codex CLI executable path for Codex-backed model names | first `codex` on `PATH`, else `codex` |\n| `ROUTER_CODEX_CWD` | Optional working directory passed to `codex exec --cd` | None |\n| `ROUTER_CODEX_SANDBOX` | Sandbox mode passed to `codex exec --sandbox` | `read-only` |\n| `ROUTER_CLAUDE_CLI` | Claude Code CLI executable path for Claude-backed model names | first `claude` on `PATH`, else `claude` |\n| `ROUTER_FLASH_RETRY_BUDGET` | Max FLASH retries before escalation | 1 |\n| `ROUTER_RECURSION_LIMIT` | Python recursion limit | 128 |\n| `ROUTER_JUDGE_TIMEOUT` | Timeout for Judge node LLM calls (seconds) | 300 |\n| `ROUTER_MAX_CONCURRENCY` | Max concurrent LangGraph branches for judge and executor fanout | Auto |\n| `ROUTER_OLLAMA_URL` | Ollama API endpoint (if used) | `http://localhost:11434/api/generate` |\n| `ROUTER_FINALIZER_TIMEOUT` | Timeout for the final reporting synthesis (seconds) | 600 |\n| `ROUTER_DEBUG` | Print raw diagnostic snippets | Off |\n| `ROUTER_LANGSMITH_ENABLED` | Enable optional LangSmith graph and model-call telemetry when `LANGSMITH_API_KEY` is set | Off |\n| `ROUTER_LANGSMITH_PROJECT` | LangSmith project name | `super-router` |\n| `ROUTER_LANGSMITH_TAGS` | Comma-separated extra LangSmith tags | None |\n| `ROUTER_LANGSMITH_TRACE_PROMPTS` | Include prompt previews in custom model-call traces | Off |\n| `ROUTER_LANGSMITH_TRACE_OUTPUTS` | Include output previews in custom model-call traces | Off |\n| `ROUTER_LANGSMITH_HIDE_INPUTS` | Request LangSmith SDK input hiding for graph traces | Off |\n| `ROUTER_LANGSMITH_HIDE_OUTPUTS` | Request LangSmith SDK output hiding for graph traces | Off |\n| `ROUTER_LANGSMITH_FLUSH` | Flush LangSmith traces before process exit | On |\n| `ROUTER_TOKEN_USAGE_LEDGER` | Optional append-only JSONL path for per-call token usage records | None |\n\nLarge local models may require higher timeouts and `ROUTER_MAX_CONCURRENCY=1`.\n\nProvider selection is model-name based:\n- Codex CLI: `codex/...`, bare `gpt-*`, bare `chatgpt-*`, or bare `o` plus digit names such as `codex/gpt-5.5` or `gpt-5.5`.\n  The router passes `--sandbox` but intentionally does not pass `--ask-for-approval`, because some `codex exec` versions do not support that option.\n- Gemini CLI: `google-gemini-cli/...`, `gemini-*`, `pro`, `flash`, `flash-lite`, or `auto`.\n- Claude Code CLI: `claude/...` or bare `claude-*` model names.\n- Ollama: all other model names, or explicit `ollama/...`.\n\n### LangSmith Telemetry\n\nLangSmith is optional and non-fatal. Enable it only when external trace upload\nis desired:\n\n```bash\nROUTER_LANGSMITH_ENABLED=1\nLANGSMITH_API_KEY=<your-langsmith-key>\nROUTER_LANGSMITH_PROJECT=super-router\n```\n\nThe router adds graph tags/metadata and traces raw provider calls as child LLM\nruns. Ollama token usage is captured from `prompt_eval_count` and `eval_count`.\nClaude Code CLI token usage is captured from JSON `total_input_tokens` and\n`total_output_tokens`. Gemini CLI token usage is captured from JSON\n`stats.models.*.tokens` when available, with `usageMetadata`-style fields as a\nfallback. Prompt and output text previews are disabled by default; enable them\nexplicitly with `ROUTER_LANGSMITH_TRACE_PROMPTS=1` or\n`ROUTER_LANGSMITH_TRACE_OUTPUTS=1`.\n\n### Token Usage Accounting\n\nToken usage is tracked even when LangSmith is disabled. The router records every\nsuccessful provider call in a run-local ledger, prints a token summary after the\nfinal report, and returns `token_usage` plus `token_usage_summary` in the final\nstate. Calls without provider token data are recorded as\n`usage_source=unavailable`. Set\n`ROUTER_TOKEN_USAGE_LEDGER=~/.openclaw/super-router-usage.jsonl` to persist the\nper-call records as append-only JSONL.\n\nIf a super-router process stops before the final token ledger is printed, Gemini\nCLI may still have persisted exact per-call token records in\n`~/.gemini/tmp/<user>/chats/session-*.jsonl`. This applies to planning-capture\ntermination, timeouts, manual kills, crashes, executor fanout interruptions, and\nmetadata/finalizer failures. Use `references/gemini-cli-token-recovery.md` to\nrecover `input`, `output`, `cached`, `thoughts`, `tool`, and `total` fields from\nmatching session JSONL files. Treat recovered values as provider telemetry;\ntreat dollar cost separately because cached-token billing depends on provider\npricing.\n\n## Complexity Routing Rules\n\n### 5-Dimension Scoring\n\nThe Judge scores each subtask on:\n\n1. **reasoning_depth** (1-10): How much logical inference is needed?\n2. **code_change_scope** (1-10): How many files/lines of code to modify?\n3. **ambiguity** (1-10): How unclear is the task specification?\n4. **risk** (1-10): What's the impact of getting this wrong?\n5. **io_heaviness** (1-10): How much reading/writing vs. thinking?\n\n### Routing Thresholds\n\n| Condition | Route |\n|-----------|-------|\n| `complexity_score >= 5` | PRO |\n| `complexity_score <= 2` | FLASH |\n| Summary-like task (no deep work) | FLASH |\n| High-risk incident diagnosis | PRO |\n| High-risk evidence gathering | PRO |\n| High-risk decision/rollback evaluation | PRO |\n| Boundary case + low confidence | PRO (safe default) |\n\n### Contextual Score Biases\n\nThe router applies automatic adjustments:\n- **High-risk context** (production, billing, security): boosts `reasoning_depth`, `risk`, `ambiguity`\n- **Evidence gathering** in incident: keeps on PRO (not mere IO)\n- **Communication/summary** subtasks: routed to FLASH unless deep work is also required\n\n## FLASH Review & Escalation Logic\n\nWhen FLASH execution fails or produces questionable output:\n\n1. **Classify failure type:**\n   - `infra_transient`: timeout, network, rate limit, service unavailable\n   - `capability_quality`: \"need more info\", empty output, too short, repeated task\n\n2. **Decision:**\n   - Infra failure -> Retry FLASH (up to `ROUTER_FLASH_RETRY_BUDGET`)\n   - Capability failure -> Escalate to PRO immediately\n   - Unknown -> Retry once, then escalate\n\n3. **Post-execution verification:**\n   - Empty output -> escalate\n   - Output < 48 chars (non-summary) -> escalate\n   - Output explicitly says \"can't complete\" -> escalate\n   - Output just repeats task description -> escalate\n\n## Finalizer Fallback Chain\n\nFinal report generation follows:\n\n```\nFLASH finalizer -> (if fails) -> PRO finalizer -> (if fails) -> Deterministic template\n```\n\n## Output Structure\n\n- **Output Structure**: The router returns a JSON-serializable state. When summarizing these results in reports or documentation, always use ASCII/Terminal-style arrows (e.g., '-->', '->') rather than mathematical arrows for all diagrams and flow representations. This is a high-priority stylistic requirement.\n\n```json\n{\n  \"task\": \"original task string\",\n  \"planner_model\": \"model name used for planning\",\n  \"judge_model\": \"model name used for complexity scoring\",\n  \"pro_model\": \"primary PRO model\",\n  \"flash_model\": \"primary FLASH model\",\n  \"planned_subtasks\": [{\"desc\": \"...\"}],\n  \"subtasks\": [\n    {\n      \"desc\": \"...\",\n      \"model\": \"PRO|FLASH\",\n      \"assessment\": {\n        \"scores\": {\"reasoning_depth\": 5, \"code_change_scope\": 3, \"ambiguity\": 2, \"risk\": 4, \"io_heaviness\": 1},\n        \"complexity_score\": 15,\n        \"suggested_route\": \"PRO\",\n        \"final_route\": \"PRO\",\n        \"confidence\": 0.85,\n        \"reason\": \"...\",\n        \"judge_source\": \"llm|heuristic\"\n      }\n    }\n  ],\n  \"results\": [\n    {\n      \"step\": 1,\n      \"planned_route\": \"PRO\",\n      \"route\": \"PRO\",\n      \"model_name\": \"...\",\n      \"desc\": \"...\",\n      \"output\": \"...\",\n      \"status\": \"success|failed\",\n      \"attempt_count\": 1,\n      \"retry_count\": 0,\n      \"escalated_from_flash\": false,\n      \"used_provider_fallback\": false,\n      \"flash_review\": {\"decision\": \"record\", \"failure_type\": \"none\", \"reason\": \"...\"},\n      \"attempt_log\": [\"...\"]\n    }\n  ],\n  \"final_report\": \"...\",\n  \"finalizer_outcome\": {\n    \"route\": \"FLASH|PRO|DETERMINISTIC\",\n    \"model_name\": \"...\",\n    \"status\": \"...\",\n    \"used_provider_fallback\": false,\n    \"reason\": \"...\",\n    \"attempt_log\": [\"...\"]\n  }\n}\n```\n\n## Maintenance\n\n| File | Purpose |\n|------|---------|\n| `scripts/router.py` | Main LangGraph router script |\n| `SKILL.md` | This documentation |\n| `references/long-running-quantitative-tasks.md` | Guidance for heavy Monte Carlo / financial modeling tasks and background execution |\n| `references/background-artifact-launches.md` | Wrapper pattern for background router runs that produce durable artifacts: prompt/context capture, stream logs, verification, and safe handling of blocked launches |\n| `references/source-html-background-wrapper.md` | Concrete pattern for source-tree-to-HTML hierarchy/explainer jobs: source JSON collector, compact router prompt, HTML generator from context+log, background launch, immediate poll, and artifact verification |\n| `references/linux-mm-source-html-example.md` | Session-specific exemplar for a large Linux `mm/` source hierarchy HTML guide: bucket taxonomy, artifact sections, and verification thresholds. Use as a model for similarly large kernel/subsystem explainers. |\n| `templates/source-html-background-wrapper.sh` | Copyable shell wrapper template for source-tree-to-HTML background jobs. Use it to avoid retyping the run/status/log/verification scaffold; replace placeholders and tune verification thresholds per artifact. |\n\n## Troubleshooting\n\n### Verifying Model Routing\n\nTo audit which model each stage actually used, run with `--stream` and check the output:\n- **Planner model**: printed as `规划模型: <model>` in the routing plan summary\n- **Judge model**: printed as `判定模型: <model>` in the routing plan summary\n- **PRO Executor**: printed as `-> <model>` per step in executor fanout\n- **FLASH Executor**: printed as `-> <model>` per step\n- **Metadata Extractor**: uses the PRO model\n- **Finalizer**: routed to FLASH first, then PRO on failure — check `finalizer_outcome.route` / `finalizer_outcome.model_name` in the returned state\n\n**Verification Audit Pattern**: For explicit per-phase LLM validation runs (e.g. K8s anomaly detection tasks), execute the router with a complex high-risk task, capture the full streaming transcript, then synthesize a self-contained HTML report. The report should include:\n- Phase cards showing attempted model vs actual outcome (including heuristic fallbacks on quota errors)\n- Routing decision table\n- Key findings on whether PRO/FLASH routing matched expectations\n- Recommendations for fallback configuration\n\nThis produces an auditable artifact that confirms the 5-node flow (Planner → Judge → Executor Fanout → Metadata → Finalizer) and surfaces any provider-specific issues like TerminalQuotaError without altering the core router logic.\n\n### Non-Determinism with Cloud APIs\n\nEven at `temperature=0.0`, cloud-hosted models may produce different decompositions across runs due to backend inference differences. The router is deterministic in its *routing logic*, not in upstream model sampling. For guaranteed reproducibility, cache planner results by task hash or use a seed parameter if the provider supports it.\n\n### Timeouts or Empty Responses\n\n- Use `--stream` and increase the terminal/process timeout if the Planner itself may take longer than 60s.\n- Set `ROUTER_JUDGE_TIMEOUT` or `ROUTER_FINALIZER_TIMEOUT` higher for large models.\n- If a model appears unexpectedly, check whether `~/.openclaw/.env` or the OpenClaw process environment contains stale `ROUTER_*_MODEL` values.\n\n### Planner produced only one subtask\n\nTask may be simple enough to not need decomposition, or the planner model may benefit from stronger prompting for atomic decomposition.\n\n### FLASH kept escalating to PRO\n\nTask may genuinely require heavy reasoning. Consider configuring a stronger FLASH model via `ROUTER_FLASH_MODEL`.\n\n## Related Skills\n\n- **dspy** — Declarative LM programming with automatic prompt optimization (Python framework alternative)\n- **btc_analyzer** — OpenClaw BTC analysis workflow that delegates structured market questions to this router\n- **api-tester** — API validation workflow that can route complex investigation subtasks through this router\n- **ddg-search** — Search-oriented support skill for evidence gathering before router execution\n- **llama-cpp** — Run LLM inference locally (alternative backend)\n\n## See Also\n\n- LangGraph documentation: https://langchain-ai.github.io/langgraph/\n- Ollama documentation: https://ollama.com/docs\n\nFile v0.1.5:README.md\n\n# Super Router\n\nSuper Router is a LangGraph-based task router that decomposes a user request,\njudges each subtask, and executes ready subtasks across PRO and FLASH model\nroles. It is built for workloads where some branches need stronger reasoning\nwhile others are simple reporting, formatting, or low-risk IO.\n\nThe current implementation supports planner and dependency fallback paths,\ndependency-aware executor fanout, provider fallback lists, FLASH retry and\nFLASH-to-PRO escalation, embedded technical metadata extraction, LangSmith\ntracing, and token usage accounting.\n\n## Workflow\n\n![Super-Router LangGraph Architecture](super-router.png)\n\n## What It Does\n\n- Compacts long task text into deterministic context manifests before planning,\n  judging, executing, metadata extraction, and finalization.\n- Plans atomic subtasks with stable IDs and optional `depends_on` edges.\n- Verifies and corrects the dependency DAG before execution.\n- Scores each subtask on reasoning depth, code-change scope, ambiguity, risk,\n  and IO heaviness.\n- Routes subtasks to `PRO` or `FLASH` using model scores plus deterministic\n  risk, summary, and confidence guards.\n- Schedules only dependency-ready subtasks, fans them out with LangGraph\n  `Send(...)`, joins completed waves, and repeats until the DAG is complete.\n- Executes model calls through Codex CLI, Gemini CLI, Claude Code CLI, or\n  Ollama, selected by model name.\n- Retries FLASH on transient infrastructure failures and escalates to PRO on\n  quality or capability failures.\n- Extracts compact \"technical gold\" metadata from successful executor outputs\n  inside each executor branch.\n- Produces the final report through a FLASH finalizer, then a PRO finalizer,\n  then a deterministic fallback report if model finalization fails.\n- Tracks provider token usage per run, prints an aggregate summary, and can\n  persist append-only JSONL records.\n\n## Repository Layout\n\n```text\n.\n|-- README.md\n|-- SKILL.md\n|-- super-router.png\n|-- references/\n|-- scripts/\n|   |-- render_super_router_diagram.py\n|   `-- router.py\n|-- templates/\n`-- tests/\n    |-- __init__.py\n    `-- test_router.py\n```\n\n| Path | Purpose |\n| --- | --- |\n| `SKILL.md` | OpenClaw skill contract, usage notes, architecture summary, and environment reference. |\n| `scripts/router.py` | Main LangGraph router, provider dispatch, fallback logic, telemetry, token accounting, and CLI. |\n| `scripts/render_super_router_diagram.py` | Deterministic diagram renderer; verifies the diagram node set against `build_router_graph()`. |\n| `super-router.png` | Current architecture diagram used by this README. |\n| `tests/test_router.py` | Offline regression tests using `unittest` and mocks. |\n| `references/` | Supplemental operational notes. |\n| `templates/` | Shell helper templates. |\n\n## Requirements\n\n- Python 3.10+.\n- `langgraph` for the runtime graph.\n- `langsmith` only when optional telemetry is enabled.\n- `Pillow` only when regenerating `super-router.png`.\n- At least one usable model provider:\n  - Codex CLI for `codex/...`, bare `gpt-*`, bare `chatgpt-*`, or bare\n    `o` plus digit model names.\n  - Gemini CLI for `google-gemini-cli/...`, `gemini-*`, `auto`, `pro`,\n    `flash`, or `flash-lite`.\n  - Claude Code CLI for `claude/...` or bare `claude-*` model names.\n  - Ollama for all other names, or explicit `ollama/...`.\n\nInstall the required runtime dependency:\n\n```bash\npip install langgraph\n```\n\nOptional dependencies:\n\n```bash\npip install langsmith\npip install pillow\n```\n\n## Installation\n\n### As an OpenClaw Skill\n\nInstall or copy this repository into the local OpenClaw skills directory, then\nplace router configuration in `~/.openclaw/.env`. OpenClaw normally exposes that\nfile to `exec` child processes, and `router.py` also loads it directly before\nresolving defaults.\n\nTypical local install:\n\n```bash\nmkdir -p ~/.openclaw/skills\ncp -R . ~/.openclaw/skills/super-router\n```\n\nAfter installation, trigger it with phrasing such as `use super-router` or\n`走 super-router`.\n\n### Standalone\n\nRun from this repository after installing `langgraph`:\n\n```bash\npython scripts/router.py \"Inspect router state flow and summarize\"\n```\n\nFor Ollama-backed models, start Ollama and pull the models you intend to use:\n\n```bash\nollama serve\nollama pull <model-name>\n```\n\n## Quick Start\n\nRun a task:\n\n```bash\npython scripts/router.py \"Analyze a multi-step task and prepare an action summary\"\n```\n\nStream node-level LangGraph progress:\n\n```bash\npython scripts/router.py --stream \"Analyze a complex task, identify required actions, and draft a final note\"\n```\n\nPass the task through the environment:\n\n```bash\nROUTER_TASK=\"Update a module, add tests, and refresh documentation\" \\\npython scripts/router.py\n```\n\nRun tests:\n\n```bash\npython -m unittest tests/test_router.py\n```\n\n## Current Architecture\n\nThe main graph is built by `build_router_graph()` in `scripts/router.py`.\n\n```text\nSTART\n  -> planner_warmup\n       loops until 3 attempts, or is skipped with ROUTER_SKIP_WARMUP\n  -> planner_invoke\n  -> planner_parse\n       parse failure -> planner_fallback\n  -> dependency_judge\n  -> dependency_validate\n       invalid DAG -> conservative serial dependency fallback\n  -> planner_ready\n  -> judge_warmup\n  -> judge_subtask fanout\n  -> assemble_plan\n  -> dependency_scheduler\n       ready subtasks -> parallel_executor fanout\n       no ready subtasks with remaining work -> dependency_deadlock\n       no remaining work -> execution_finalize_join\n  -> dependency_execution_join\n       returns to dependency_scheduler for the next ready wave\n  -> execution_finalize_join\n  -> flash_finalizer\n  -> flash_finalizer_verify\n       accepted -> finalizer_complete\n       rejected or failed -> pro_finalizer or deterministic_finalizer\n  -> pro_finalizer\n  -> pro_finalizer_verify\n       accepted -> finalizer_complete\n       rejected or failed -> deterministic_finalizer\n  -> deterministic_finalizer\n  -> finalizer_complete\n  -> END\n```\n\nThe router also uses a nested provider fallback graph for every model call that\nneeds fallback support:\n\n```text\nmodel_attempt_prepare -> model_invoke -> model_attempt_prepare or END\n```\n\nFallback candidates are deduplicated. Infrastructure or unknown failures can\nadvance to the next provider candidate; capability or quality failures stop the\nprovider fallback loop.\n\n## Runtime Flow\n\n1. Build initial state, resolve model roles, fallback lists, retry budget,\n   recursion limit, and optional max concurrency.\n2. Warm the planner model with three `OK` calls unless warmup is skipped.\n3. Ask the planner for raw JSON subtasks with stable IDs and dependency hints.\n4. Parse and normalize planner output; if that fails, build heuristic fallback\n   subtasks.\n5. Ask the dependency judge to correct only `depends_on` edges and dependency\n   reasons.\n6. Validate the DAG; if invalid, convert it to a conservative serial plan.\n7. Warm the judge model unless warmup is skipped.\n8. Fan out one judge branch per planned subtask.\n9. Assemble the ordered plan and display route, score, confidence, and\n   dependency rationale.\n10. Repeatedly schedule every subtask whose dependencies have completed.\n11. Execute each ready branch through PRO or FLASH, including provider\n   fallback, FLASH review, retry, escalation, and branch-local metadata\n   extraction.\n12. Join executor wave results and return to the scheduler until all subtask\n   IDs are complete.\n13. If dependency scheduling deadlocks, record fallback results for blocked\n   subtasks and continue to finalization.\n14. Finalize with FLASH, escalate to PRO when useful, or emit a deterministic\n   fallback report.\n15. Print the final report, token usage summary, and optional ledger path.\n\n## Planning And Dependencies\n\nThe planner receives a compact task context manifest rather than unbounded raw\ntask text. Long prompts are converted into JSON fields such as objective,\nentities, constraints, deliverables, evidence requirements, decomposition\nhints, and a compact source brief.\n\nPlanner output is expected to be raw JSON:\n\n```json\n[\n  {\n    \"id\": \"S1\",\n    \"desc\": \"Inspect the first required technical area\",\n    \"depends_on\": [],\n    \"dependency_reason\": \"Independent evidence collection.\"\n  },\n  {\n    \"id\": \"S2\",\n    \"desc\": \"Prepare the requested final summary\",\n    \"depends_on\": [\"S1\"],\n    \"dependency_reason\": \"Summary depends on the inspection findings.\"\n  }\n]\n```\n\nThe dependency judge may remove unnecessary dependencies or add required ones,\nbut it must keep the existing subtasks and IDs. If dependency judgment fails,\nthe router keeps the planner dependencies and still validates them. If\nvalidation detects duplicate IDs, unknown dependencies, self-dependencies, or\ncycles, execution falls back to a serial dependency chain.\n\n## Complexity Scoring\n\nEach subtask is judged independently with the original task available as risk\ncontext. The judge returns:\n\n```json\n{\n  \"scores\": {\n    \"reasoning_depth\": 2,\n    \"code_change_scope\": 1,\n    \"ambiguity\": 1,\n    \"risk\": 0,\n    \"io_heaviness\": 0\n  },\n  \"suggested_route\": \"PRO\",\n  \"confidence\": 0.87,\n  \"reason\": \"Requires debugging and non-trivial code inspection.\"\n}\n```\n\nScore ranges:\n\n| Field | Range | Meaning |\n| --- | --- | --- |\n| `reasoning_depth` | `0-3` | Lookup or formatting through architecture/open-ended investigation. |\n| `code_change_scope` | `0-3` | No code change through broad refactor or migration. |\n| `ambiguity` | `0-2` | Clear through unclear or open-ended. |\n| `risk` | `0-2` | Low risk through high-risk or hard-to-reverse. |\n| `io_heaviness` | `0-2` | Little IO through mostly IO, reporting, or formatting. |\n\nThe aggregate `complexity_score` is:\n\n```text\nreasoning_depth + code_change_scope + ambiguity + risk\n```\n\nRouting guards then adjust or override the model suggestion:\n\n| Condition | Route |\n| --- | --- |\n| Summary, report, recap, or status update with no deep-work language | FLASH |\n| Diagnostic investigation, debugging, fixing, implementation, migration, refactor, or design work | PRO |\n| High-risk operational, financial, security, rollback, containment, or incident work | PRO |\n| High-risk evidence gathering that supports diagnosis or decision-making | PRO |\n| Judge confidence below `0.35` | PRO |\n| `complexity_score >= 5` | PRO |\n| Any of reasoning depth, code-change scope, or risk is at least `2` | PRO |\n| `complexity_score <= 2` and IO-heavy with high confidence | FLASH |\n| Boundary or unclear case | PRO |\n\nIf structured judge output fails, the router builds a heuristic assessment using\nthe same score fields, route decision function, and audit fields.\n\n## Dependency-Aware Execution\n\nExecution is wave-based:\n\n- `dependency_scheduler` computes completed subtask IDs and remaining work.\n- Ready subtasks are those whose `depends_on` IDs are all complete.\n- Ready subtasks are dispatched concurrently to `parallel_executor`, bounded by\n  LangGraph `max_concurrency`.\n- `dependency_execution_join` orders completed wave results, records progress,\n  and returns control to the scheduler.\n- `execution_finalize_join` creates the final ordered `results` list once all\n  subtasks are complete.\n\nExecutor prompts include only direct dependency results for the active subtask.\nThis keeps comparison, synthesis, and reporting steps from running before the\nevidence-producing branches they depend on.\n\nIf no subtask is ready while work remains, `dependency_deadlock` records\nfallback results for blocked subtasks, adds errors, and allows the finalizer to\nreport the dependency issue instead of crashing the graph.\n\n## FLASH Review And Escalation\n\nFLASH execution is accepted only when the output passes heuristic review.\n\nInfrastructure-style failures are retried until `ROUTER_FLASH_RETRY_BUDGET` is\nexhausted:\n\n- timeout\n- network failure\n- rate limit\n- connection reset or refused\n- service unavailable\n- transport or deadline errors\n\nCapability or quality failures escalate to PRO:\n\n- empty output\n- too-short output for a non-summary subtask\n- output that simply repeats the subtask description\n- output saying it cannot complete or needs more context\n- provider failure classified as capability or quality rather than\n  infrastructure\n\nIf FLASH retry budget is exhausted, the branch records a deterministic failure\nmessage and the graph continues.\n\n## Provider Selection\n\nModel names choose the transport:\n\n| Transport | Model-name match |\n| --- | --- |\n| Codex CLI | `codex/...`, bare `gpt-*`, bare `chatgpt-*`, or bare `o` plus digit names such as `o3` or `o4-mini`. Explicit `ollama/`, `claude/`, and `google-gemini-cli/` prefixes take precedence. |\n| Gemini CLI | `google-gemini-cli/...`, bare `gemini-*`, `auto`, `pro`, `flash`, or `flash-lite`. |\n| Claude Code CLI | `claude/...` or bare `claude-*`. |\n| Ollama HTTP | All other model names, including explicit `ollama/...`. |\n\nDefault role models:\n\n| Role | Default |\n| --- | --- |\n| Planner | `google-gemini-cli/gemini-3-pro-preview` |\n| Judge | `google-gemini-cli/gemini-3-flash-preview` |\n| PRO executor/finalizer | `google-gemini-cli/gemini-3-pro-preview` |\n| FLASH executor/finalizer | `google-gemini-cli/gemini-3-flash-preview` |\n\nUse one model for every role:\n\n```bash\nexport ROUTER_MODEL=gpt-5.5\n```\n\nOverride individual roles:\n\n```bash\nexport ROUTER_PLANNER_MODEL=google-gemini-cli/gemini-3-pro-preview\nexport ROUTER_JUDGE_MODEL=google-gemini-cli/gemini-3-flash-preview\nexport ROUTER_PRO_MODEL=google-gemini-cli/gemini-3-pro-preview\nexport ROUTER_FLASH_MODEL=google-gemini-cli/gemini-3-flash-preview\n```\n\nProvider fallback placeholders:\n\n```bash\nexport ROUTER_PRO_MODEL=google-gemini-cli/gemini-3-pro-preview\nexport ROUTER_PRO_FALLBACK_MODELS=<pro-fallback-1>,<pro-fallback-2>\n\nexport ROUTER_FLASH_MODEL=google-gemini-cli/gemini-3-flash-preview\nexport ROUTER_FLASH_FALLBACK_MODELS=<flash-fallback-1>,<flash-fallback-2>\n```\n\nCodex-specific settings:\n\n```bash\nexport ROUTER_MODEL=codex/gpt-5.5\nexport ROUTER_CODEX_CWD=/path/to/worktree\nexport ROUTER_CODEX_SANDBOX=read-only\n```\n\nThe router invokes Codex with `codex exec`, `--ephemeral`,\n`--skip-git-repo-check`, `--color never`, and `--output-last-message`. It\nintentionally does not pass `--ask-for-approval`, because some `codex exec`\nversions do not support that option.\n\nFor local large models, prefer a strong planner and a smaller judge, and\nserialize fanout:\n\n```bash\nexport ROUTER_PLANNER_MODEL=<strong-local-model>\nexport ROUTER_JUDGE_MODEL=<smaller-local-model>\nexport ROUTER_MAX_CONCURRENCY=1\n```\n\n## Environment Variables\n\nWhen running as an OpenClaw skill, set these in `~/.openclaw/.env` (one\n`KEY=VALUE` per line). When running standalone, either keep `~/.openclaw/.env`\nin place or export values in your shell.\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `ROUTER_TASK` | unset | Task text used when no positional CLI task is provided. |\n| `ROUTER_MODEL` | unset | Global model default for planner, judge, PRO, and FLASH roles. Role-specific variables override it. |\n| `ROUTER_PLANNER_MODEL` | `google-gemini-cli/gemini-3-pro-preview` | Model used for task decomposition. |\n| `ROUTER_JUDGE_MODEL` | `google-gemini-cli/gemini-3-flash-preview` | Model used for dependency judgment and complexity scoring. |\n| `ROUTER_PRO_MODEL` | `google-gemini-cli/gemini-3-pro-preview` | Primary PRO executor and PRO finalizer model. |\n| `ROUTER_FLASH_MODEL` | `google-gemini-cli/gemini-3-flash-preview` | Primary FLASH executor and FLASH finalizer model. |\n| `ROUTER_PRO_FALLBACK_MODELS` | unset | Comma-separated PRO provider fallback list. |\n| `ROUTER_FLASH_FALLBACK_MODELS` | unset | Comma-separated FLASH provider fallback list. |\n| `ROUTER_FLASH_RETRY_BUDGET` | `1` | Number of FLASH retries for transient or unknown failures before recording failure. |\n| `ROUTER_SKIP_WARMUP` | false | Skip planner and judge warmup pings when set to `1`, `true`, or `yes`. |\n| `ROUTER_RECURSION_LIMIT` | `128` | LangGraph recursion limit for the main graph. |\n| `ROUTER_MAX_CONCURRENCY` | auto | Max concurrent LangGraph branches. Auto resolves to `1` for large judge models and otherwise leaves LangGraph default behavior. |\n| `ROUTER_PLANNER_TASK_CHAR_LIMIT` | `6000` | Character budget for the compact planner context manifest. |\n| `ROUTER_PLANNER_MAX_OUTPUT_TOKENS` | `4096` | Planner JSON output token cap. |\n| `ROUTER_JUDGE_CONTEXT_CHAR_LIMIT` | `3000` | Character budget for judge context JSON. |\n| `ROUTER_EXECUTOR_CONTEXT_CHAR_LIMIT` | `8000` | Character budget for executor context JSON. |\n| `ROUTER_METADATA_OUTPUT_CHAR_LIMIT` | `6000` | Character budget for metadata extraction context and output excerpts. |\n| `ROUTER_FINALIZER_CONTEXT_CHAR_LIMIT` | `12000` | Character budget for finalizer context JSON. |\n| `ROUTER_JUDGE_TIMEOUT` | `6000` for large judge models, otherwise `300` | Timeout in seconds for dependency judge and complexity judge calls. |\n| `ROUTER_FINALIZER_TIMEOUT` | `6000` | Timeout in seconds for FLASH and PRO finalizer calls. |\n| `ROUTER_OLLAMA_URL` | `http://localhost:11434/api/generate` | Ollama generate endpoint. |\n| `ROUTER_CODEX_CLI` | first `codex` on `PATH`, else `codex` | Codex CLI executable path. |\n| `ROUTER_CODEX_CWD` | unset | Optional working directory passed to `codex exec --cd`. |\n| `ROUTER_CODEX_SANDBOX` | `read-only` | Sandbox mode passed to `codex exec --sandbox`. |\n| `ROUTER_GEMINI_CLI` | first `gemini` on `PATH`, else `/opt/homebrew/bin/gemini` | Gemini CLI executable path. |\n| `GEMINI_CLI_SYSTEM_SETTINGS_PATH` | platform default | Optional base Gemini CLI settings file. The router writes a temporary settings override per call to force temperature. |\n| `ROUTER_CLAUDE_CLI` | first `claude` on `PATH`, else `claude` | Claude Code CLI executable path. |\n| `ROUTER_DEBUG` | false | Print raw planner, judge, and provider diagnostic snippets when set to `1`, `true`, `yes`, `on`, or `debug`. |\n| `ROUTER_TOKEN_USAGE_LEDGER` | unset | Optional append-only JSONL path for per-call token usage records. |\n\nThe code-level PRO executor, FLASH executor, and finalizer defaults are\nconservative (`6000` seconds) for long-running model workflows. External shell,\nterminal, or process supervisors can still stop the process earlier.\n\nUnset judge, executor, metadata, and finalizer context limits are doubled for\nhigh-risk tasks. Explicit environment values are used as-is.\n\n## LangSmith Telemetry\n\nLangSmith tracing is optional and non-fatal. It is active only when the\n`langsmith` package is importable, tracing is requested, and an API key is\nconfigured.\n\nEnable tracing:\n\n```bash\nexport ROUTER_LANGSMITH_ENABLED=1\nexport LANGSMITH_API_KEY=<your-langsmith-key>\nexport ROUTER_LANGSMITH_PROJECT=super-router\nexport ROUTER_LANGSMITH_TAGS=local,openclaw\n```\n\nTracing can also be requested through `LANGSMITH_TRACING` or\n`LANGCHAIN_TRACING_V2` when `ROUTER_LANGSMITH_ENABLED` is unset. Set\n`ROUTER_LANGSMITH_ENABLED=false` to force tracing off.\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `ROUTER_LANGSMITH_ENABLED` | unset/false | Router-specific tracing toggle. |\n| `LANGSMITH_API_KEY` / `LANGCHAIN_API_KEY` | unset | API key used by the LangSmith client. |\n| `ROUTER_LANGSMITH_PROJECT` | `super-router` | Project name; falls back to `LANGSMITH_PROJECT`. |\n| `ROUTER_LANGSMITH_TAGS` | unset | Comma-separated tags appended to `super-router,langgraph`. |\n| `LANGSMITH_ENDPOINT` / `LANGCHAIN_ENDPOINT` | LangSmith default | Optional API endpoint. |\n| `LANGSMITH_WORKSPACE_ID` | unset | Optional workspace ID. |\n| `ROUTER_LANGSMITH_TRACE_PROMPTS` | false | Include compact prompt previews in custom model-call traces. |\n| `ROUTER_LANGSMITH_TRACE_OUTPUTS` | false | Include compact output previews in custom model-call traces. |\n| `ROUTER_LANGSMITH_HIDE_INPUTS` | false | Request SDK input hiding for graph traces. |\n| `ROUTER_LANGSMITH_HIDE_OUTPUTS` | false | Request SDK output hiding for graph traces. Token counts are retained when available. |\n| `ROUTER_LANGSMITH_FLUSH` | true | Flush traces before process exit. |\n\nThe graph run includes `super-router` and `langgraph` tags, role model names,\nfallback counts, retry budget, run ID, and task length. Raw provider calls are\ntraced as `Super Router Model Call` child runs with provider, transport,\ntimeout, token usage when available, and prompt/output lengths by default.\nPrompt and output text previews are opt-in.\n\n## Token Usage Accounting\n\nToken usage is tracked even when LangSmith is disabled. Each successful\nprovider call records:\n\n- run ID and call index\n- label, provider, model, and usage source\n- input, output, total, cached, candidate, thought, and tool tokens when\n  available\n- prompt and output character counts\n\nProvider sources:\n\n| Provider | Usage source |\n| --- | --- |\n| Ollama | `prompt_eval_count` and `eval_count` from `/api/generate`. |\n| Gemini CLI | `stats.models.*.tokens` when available, with `usageMetadata` fields as fallback. |\n| Claude Code CLI | `usage`, `model_usage`, or legacy total input/output token fields from JSON output. |\n| Codex CLI | Recorded as `usage_source=unavailable` unless the CLI output supplies token data in the future. |\n\nThe final state contains `token_usage` and `token_usage_summary`, and the CLI\nprints the same aggregate after the final report. Persist JSONL records with:\n\n```bash\nexport ROUTER_TOKEN_USAGE_LEDGER=~/.openclaw/super-router-usage.jsonl\n```\n\nEach JSONL line contains run metadata, the aggregate summary, and one\nprovider-call record.\n\n## CLI\n\n```text\nusage: router.py [-h] [--stream] [task ...]\n```\n\n| Argument | Meaning |\n| --- | --- |\n| `task` | Task description. Positional words are joined with spaces. If omitted, `ROUTER_TASK` is used. |\n| `--stream` | Emit node-level LangGraph progress updates while the graph runs. |\n| `-h`, `--help` | Show CLI help. |\n\n## Python API\n\nThe main programmatic entry point is `run_router_app()`:\n\n```python\nfrom scripts.router import run_router_app\n\nstate = run_router_app(\n    \"Inspect router state flow and summarize\",\n    planner_model=\"google-gemini-cli/gemini-3-pro-preview\",\n    judge_model=\"google-gemini-cli/gemini-3-flash-preview\",\n    pro_model=\"google-gemini-cli/gemini-3-pro-preview\",\n    flash_model=\"google-gemini-cli/gemini-3-flash-preview\",\n    max_concurrency=1,\n    stream=True,\n)\n\nprint(state[\"status\"])\nprint(state[\"final_report\"])\n```\n\nUseful lower-level helpers:\n\n| Helper | Purpose |\n| --- | --- |\n| `create_initial_state()` | Resolve models, fallback lists, retry budget, and initial graph state. |\n| `prepare_router_run()` | Build the graph and resolve graph config without invoking it. |\n| `build_router_graph()` | Compile the main LangGraph `StateGraph`. |\n| `generate_text()` | Dispatch one prompt to the provider inferred from the model name. |\n| `invoke_with_provider_fallback()` | Execute a provider candidate sequence through the nested fallback graph. |\n| `build_fallback_assessment()` | Build heuristic judge output when structured scoring fails. |\n| `verify_flash_output()` | Apply FLASH quality review. |\n| `build_fallback_report()` | Build the deterministic final report. |\n\n## Output State\n\n`run_router_app()` returns a JSON-serializable `RouterState`. Important fields:\n\n```json\n{\n  \"run_id\": \"uuid\",\n  \"task\": \"original task string\",\n  \"planner_model\": \"model used for planning\",\n  \"judge_model\": \"model used for dependency and route judgment\",\n  \"pro_model\": \"primary PRO model\",\n  \"flash_model\": \"primary FLASH model\",\n  \"pro_fallback_models\": [\"optional\", \"fallbacks\"],\n  \"flash_fallback_models\": [\"optional\", \"fallbacks\"],\n  \"planned_subtasks\": [\n    {\n      \"id\": \"S1\",\n      \"desc\": \"subtask text\",\n      \"depends_on\": [],\n      \"dependency_reason\": \"why this dependency shape is valid\"\n    }\n  ],\n  \"subtasks\": [\n    {\n      \"id\": \"S1\",\n      \"desc\": \"subtask text\",\n      \"depends_on\": [],\n      \"model\": \"PRO\",\n      \"assessment\": {\n        \"scores\": {\n          \"reasoning_depth\": 2,\n          \"code_change_scope\": 1,\n          \"ambiguity\": 1,\n          \"risk\": 0,\n          \"io_heaviness\": 0\n        },\n        \"complexity_score\": 4,\n        \"suggested_route\": \"PRO\",\n        \"final_route\": \"PRO\",\n        \"confidence\": 0.9,\n        \"reason\": \"Requires investigation.\",\n        \"judge_source\": \"structured_llm\"\n      }\n    }\n  ],\n  \"results\": [\n    {\n      \"step\": 1,\n      \"subtask_id\": \"S1\",\n      \"depends_on\": [],\n      \"planned_route\": \"FLASH\",\n      \"route\": \"PRO\",\n      \"model_name\": \"google-gemini-cli/gemini-3-pro-preview\",\n      \"desc\": \"subtask text\",\n      \"output\": \"model output\",\n      \"status\": \"executed\",\n      \"attempt_count\": 2,\n      \"retry_count\": 0,\n      \"escalated_from_flash\": true,\n      \"used_provider_fallback\": false,\n      \"flash_review\": {\n        \"decision\": \"escalate\",\n        \"failure_type\": \"capability_quality\",\n        \"reason\": \"FLASH output was too short for a non-summary step.\"\n      },\n      \"attempt_log\": [\"audit log entries\"]\n    }\n  ],\n  \"history\": [\"graph audit history and technical metadata blocks\"],\n  \"errors\": [\"fallback or failure messages\"],\n  \"final_report\": \"final report text\",\n  \"finalizer_outcome\": {\n    \"route\": \"FLASH\",\n    \"model_name\": \"google-gemini-cli/gemini-3-flash-preview\",\n    \"status\": \"finished\",\n    \"used_provider_fallback\": false,\n    \"reason\": \"Finalizer output passed heuristic verification.\",\n    \"attempt_log\": [\"audit log entries\"]\n  },\n  \"token_usage\": [],\n  \"token_usage_summary\": {\n    \"calls\": 0,\n    \"calls_with_usage\": 0,\n    \"calls_without_usage\": 0,\n    \"input_tokens\": 0,\n    \"output_tokens\": 0,\n    \"total_tokens\": 0\n  },\n  \"status\": \"finished\"\n}\n```\n\n## Development\n\nRun the full regression suite:\n\n```bash\npython -m unittest tests/test_router.py\n```\n\nUseful focused checks:\n\n```bash\npython -m unittest tests.test_router.RouterHelperTests\npython -m unittest tests.test_router.ProviderFallbackTests\npython -m unittest tests.test_router.FlashReviewAndMetadataTests\npython -m unittest tests.test_router.FinalizerTests\npython -m unittest tests.test_router.RouterGraphIntegrationTests\n```\n\nRegenerate the architecture diagram after changing graph nodes:\n\n```bash\npython scripts/render_super_router_diagram.py\n```\n\nThe renderer raises an error if `EXPECTED_GRAPH_NODES` in\n`scripts/render_super_router_diagram.py` is stale relative to\n`build_router_graph()`.\n\nCurrent tests cover:\n\n- environment parsing and default state construction\n- LangSmith configuration and trace redaction helpers\n- planner JSON extraction and subtask normalization\n- planner context compaction for long tasks\n- dependency judgment and DAG validation behavior\n- bounded context packs for judge, executor, metadata, and finalizer prompts\n- provider selection for Gemini, Codex, Claude, and Ollama\n- provider usage metadata extraction\n- provider fallback retry and capability-stop behavior\n- token usage tracking and JSONL ledger persistence\n- FLASH review, retry, and escalation guards\n- metadata extraction behavior\n- finalizer timeout, verification, and fallback behavior\n- full mocked graph success, FLASH escalation, dependency-aware concurrency,\n  dependency blocking, and streamed execution\n\nWhen changing router logic, add regression coverage for new route decisions,\nenvironment variables, graph nodes or edges, fallback order, token accounting,\nstream output, and finalizer behavior.\n\n## Troubleshooting\n\n### Task Description Required\n\nProvide a positional task or set `ROUTER_TASK`:\n\n```bash\nROUTER_TASK=\"Summarize the router graph\" python scripts/router.py\n```\n\n### Gemini CLI Executable Was Not Found\n\nInstall Gemini CLI or set:\n\n```bash\nexport ROUTER_GEMINI_CLI=/path/to/gemini\n```\n\n### Claude CLI Executable Was Not Found\n\nInstall Claude Code CLI or set:\n\n```bash\nexport ROUTER_CLAUDE_CLI=/path/to/claude\n```\n\n### Codex CLI Executable Was Not Found\n\nInstall Codex CLI or set:\n\n```bash\nexport ROUTER_CODEX_CLI=/path/to/codex\n```\n\n### Gemini Network Preflight Failed\n\nBefore invoking Gemini CLI, the router checks connectivity to required Google\nendpoints when no proxy is configured. If your environment requires a proxy,\nconfigure one of:\n\n```bash\nexport HTTPS_PROXY=http://proxy.example:8080\nexport HTTP_PROXY=http://proxy.example:8080\nexport ALL_PROXY=socks5://proxy.example:1080\n```\n\n### Unable To Reach Ollama\n\nStart Ollama and confirm the endpoint:\n\n```bash\nollama serve\nexport ROUTER_OLLAMA_URL=http://localhost:11434/api/generate\n```\n\n### Planner Or Judge Is Slow\n\nLarge local models can take minutes, especially on first load. Use streaming\nand serialize fanout:\n\n```bash\nexport ROUTER_MAX_CONCURRENCY=1\npython scripts/router.py --stream \"Analyze a complex task and draft a summary\"\n```\n\nSkip warmup pings during local iteration:\n\n```bash\nexport ROUTER_SKIP_WARMUP=1\n```\n\n### FLASH Keeps Escalating To PRO\n\nInspect `flash_review` in `state[\"results\"]`. Common reasons are empty output,\nvery short non-summary output, \"need more context\" style responses, or an\ninfrastructure failure that exhausted the retry budget.\n\n### Finalizer Uses The Deterministic Report\n\nInspect `finalizer_outcome`, `finalizer_error`, and\n`finalizer_attempt_log`. Common causes are provider timeouts, authentication\nfailures, short finalizer output, or FLASH and PRO resolving to the same\neffective model path after a non-capability FLASH failure.\n\n## Security Notes\n\n- Do not commit credentials, private endpoints, or provider authentication\n  artifacts.\n- Keep provider configuration in environment variables or `~/.openclaw/.env`.\n- Leave prompt and output tracing disabled for sensitive workloads unless you\n  explicitly need previews.\n- Treat model outputs as untrusted text; validate before automating\n  irreversible operations.\n- Keep tests offline by mocking provider calls.\n\n## Related Documentation\n\n- `SKILL.md` for OpenClaw-specific invocation guidance.\n- `references/` for supplemental operational notes.\n- LangGraph documentation: https://langchain-ai.github.io/langgraph/\n- Ollama documentation: https://ollama.com/docs\n- Gemini CLI headless JSON output: https://google-gemini.github.io/gemini-cli/docs/cli/headless.html\n\nFile v0.1.5:_meta.json\n\n{\n  \"ownerId\": \"kn71hy12wp4z8b19wb103v938d81yez7\",\n  \"slug\": \"super-router\",\n  \"version\": \"0.1.5\",\n  \"publishedAt\": 1782804995571\n}\n\nFile v0.1.5:references/background-artifact-launches.md\n\n# Background Router Artifact Launches\n\nUse this pattern when a user asks to run super-router in background mode and produce a durable artifact such as an HTML report.\n\n## Pattern\n\n1. Build small, auditable support files before launching:\n   - a source/context collection script, if the task depends on local code or data;\n   - a router prompt file for complex/multiline task text;\n   - a wrapper script that records `run_dir`, status, router stream log, final artifact path, and verification results.\n2. Launch the wrapper with `exec(background=true, notify_on_complete=true)`.\n3. If the launch succeeds, immediately poll once to verify the process is actually running or completed with useful output.\n4. The wrapper should tee router stdout/stderr to a log and preserve the exact prompt/context used for the run.\n5. For artifact-producing jobs, generate or finalize the artifact only from real collected context and router output. If router/provider execution fails, the artifact may still be created only if it truthfully records the failure/log tail and uses verified local context; never hide a failed router run behind a polished report.\n6. Verify the final artifact directly before claiming success, e.g. `wc -c`, section/card counts, and any required source-derived sections.\n7. If the command guard blocks the launch, do not retry, rephrase, or work around it. Report the prepared files and the exact blocked launch scope, then wait for user approval.\n\n## Wrapper skeleton\n\n```bash\n#!/usr/bin/env bash\nset -u\nSRC=\"$HOME/path/to/source\"\nRUN_DIR=\"$HOME/.openclaw/logs/task_$(date +%Y%m%d_%H%M%S)\"\nmkdir -p \"$RUN_DIR\"\nCTX=\"$RUN_DIR/source_context.md\"\nPROMPT=\"$RUN_DIR/router_prompt.txt\"\nLOG=\"$RUN_DIR/super_router_stream.log\"\nOUT=\"$HOME/path/to/output.html\"\nSTATUS=\"$RUN_DIR/status.txt\"\n\npython3 collect_context.py \"$SRC\" \"$CTX\" 2>&1 | tee -a \"$STATUS\"\n{\n  /bin/cat prompt_base.txt\n  printf '\\n\\n# Source-derived context\\n\\n'\n  /bin/cat \"$CTX\"\n} > \"$PROMPT\"\n\nROUTER_EXIT=0\n(\n  export ROUTER_TASK=\"$(/bin/cat \"$PROMPT\")\"\n  /opt/homebrew/Caskroom/miniforge/base/bin/python \\\n    \"$HOME/.openclaw/skills/super-router/scripts/router.py\" --stream\n) 2>&1 | tee \"$LOG\" || ROUTER_EXIT=${PIPESTATUS[0]}\n\npython3 generate_artifact.py \"$SRC\" \"$CTX\" \"$LOG\" \"$OUT\" 2>&1 | tee -a \"$STATUS\"\nBYTES=$(wc -c < \"$OUT\" | tr -d ' ')\nSECTIONS=$(grep -Eo '<section id=\"[^\"]+\"' \"$OUT\" | wc -l | tr -d ' ')\nprintf '[verify] html=%s bytes=%s sections=%s router_exit=%s\\n' \\\n  \"$OUT\" \"$BYTES\" \"$SECTIONS\" \"$ROUTER_EXIT\" | tee -a \"$STATUS\"\n```\n\n## Why this matters\n\nBackground router jobs otherwise become opaque: the user sees only that a process was launched, while the prompt, source evidence, partial provider output, and artifact verification may be scattered or lost. A wrapper turns the job into a reproducible run directory and makes blocked launches safe to report without pretending work is still running.\n\nFile v0.1.5:references/gemini-cli-ripgrep-path-fix.md\n\n# Gemini CLI ripgrep Detection Fix\n\n## Problem\nDuring super-router runs, the Gemini CLI repeatedly logs:\n> \"Ripgrep is not available. Falling back to GrepTool\"\n\nThis occurs even when ripgrep is correctly installed at `/opt/homebrew/bin/rg` and PATH is set in `~/.openclaw/.env`.\n\n## Root Cause\nThe Gemini CLI binary performs its own internal tool discovery for commands like `rg`. When invoked via `subprocess.run`, these child processes do not always inherit the environment variables (including PATH) that the router sets from `~/.openclaw/.env`.\n\n## Solution\nForce-prepend the required tool paths directly inside `invoke_gemini_cli()` before every subprocess call.\n\n### Patch Applied\n```python\n# Force inject ripgrep + common tool paths\nextra_paths = [\"/opt/homebrew/bin\", \"/usr/local/bin\"]\ncurrent_path = env.get(\"PATH\", \"\")\npath_parts = [p for p in extra_paths if p not in current_path.split(\":\")]\nif path_parts:\n    env[\"PATH\"] = \":\".join(path_parts + [current_path]) if current_path else \":\".join(path_parts)\n```\n\nThis replaces the previous conditional injection and ensures `rg` is always visible to Gemini's internal tools.\n\n## Verification\nAfter applying the patch, run any complex task through the router and confirm the \"Ripgrep is not available\" message no longer appears in the Gemini CLI stderr.\n\nFile v0.1.5:references/gemini-cli-token-recovery.md\n\n# Recovering Gemini CLI token usage when super-router ledger is unavailable\n\nUse this when any super-router process stops before the final token ledger is printed, but one or more underlying Gemini CLI calls completed. This includes planning-capture harness termination, manual kill, timeout, crash, interrupted executor fanout, metadata extraction failure, or finalizer failure. The recovery is phase-agnostic: recover every completed Gemini CLI call in the router process time window, then attribute calls to phases where possible.\n\n## Symptom\n\nA super-router run stops before emitting its normal token ledger / `Token Usage Summary`, for example:\n\n- planning-capture harness terminates after the streamed plan\n- user/manual kill\n- timeout\n- process crash\n- executor fanout interruption\n- metadata extractor/finalizer failure\n- any other incomplete router run\n\nThe router artifact may show token fields as `null` / unavailable, often with:\n\n```json\n\"usage_source\": \"unavailable: router terminated after streamed plan before final token ledger\"\n```\n\nThe router log may also contain no `Token Usage Summary` lines.\n\n## Recovery source\n\nGemini CLI persists session JSONL files under:\n\n```text\n~/.gemini/tmp/<user>/chats/session-*.jsonl\n```\n\nFor a run, filter by the router capture time window. Each relevant JSONL often contains a `tokens` object like:\n\n```json\n\"tokens\": {\n  \"input\": 16338,\n  \"output\": 306,\n  \"cached\": 0,\n  \"thoughts\": 3348,\n  \"tool\": 0,\n  \"total\": 19992\n},\n\"model\": \"gemini-3-flash-preview\"\n```\n\n## Procedure\n\n1. Determine the router process start/stop window from available evidence: wrapper JSON, terminal/process timestamps, router logs, output artifact mtimes, or shell history.\n2. Normalize the time window carefully. Gemini CLI `session-*.jsonl` filenames may align with UTC-like timestamps while terminal `date` output or user-facing run logs may be local time. If an initial local-time search finds zero token records, retry using the UTC timestamp from the run artifact.\n3. Read router artifacts for phase/model context: planner, judge, pro, flash, metadata extractor, and finalizer models when available.\n4. List Gemini CLI session files around that time:\n\n```bash\nls -lt ~/.gemini/tmp/$USER/chats/session-YYYY-MM-DDTHH-*.jsonl\n```\n\n4. Parse candidate files and extract nested objects containing `tokens.total`, `model`, and timestamps/snippets if present.\n5. Deduplicate by `(file, model, token-object)`.\n6. Attribute records whose timestamps overlap the router run window and whose models/prompts/snippets match expected router phases.\n7. Sum `input`, `output`, `cached`, `thoughts`, `tool`, and `total`; optionally group by model and inferred phase.\n8. Patch telemetry as recovered provider telemetry, not an estimate. If phase attribution is uncertain, label it `super_router_recovered_unattributed` rather than guessing.\n\n## Python snippet\n\n```python\nimport json, pathlib\nchatdir = pathlib.Path('~/.gemini/tmp').expanduser() / pathlib.Path.home().name / 'chats'\nfiles = sorted(chatdir.glob('session-YYYY-MM-DDTHH-*.jsonl'))\nrecords = []\nfor p in files:\n    for line in p.read_text(errors='ignore').splitlines():\n        try:\n            obj = json.loads(line)\n        except Exception:\n            continue\n        def visit(x):\n            if isinstance(x, dict):\n                if isinstance(x.get('tokens'), dict) and 'total' in x['tokens']:\n                    records.append({'file': p.name, 'model': x.get('model'), 'tokens': x['tokens']})\n                for v in x.values():\n                    visit(v)\n            elif isinstance(x, list):\n                for v in x:\n                    visit(v)\n        visit(obj)\nseen, uniq = set(), []\nfor r in records:\n    key = (r['file'], r.get('model'), json.dumps(r['tokens'], sort_keys=True))\n    if key not in seen:\n        seen.add(key)\n        uniq.append(r)\nsums = {k: sum(int(r['tokens'].get(k, 0) or 0) for r in uniq)\n        for k in ['input', 'output', 'cached', 'thoughts', 'tool', 'total']}\nprint(sums)\n```\n\n## Interpretation\n\n- `input`: prompt/context tokens.\n- `cached`: subset of input/context served from provider cache; do not add it again to input.\n- `thoughts`: provider-reported internal reasoning tokens.\n- `output`: visible response tokens.\n- `total`: provider-reported total accounting field.\n\n## Caveats\n\n- This recovers token usage, not dollar cost. Dollar cost depends on current provider pricing and cached-token billing rules.\n- Only use files in the matching time window; other Gemini/Codex jobs may create nearby sessions.\n- If multiple concurrent Gemini jobs used the same models in the same minute, inspect prompts/text snippets before attributing records.\n\nFile v0.1.5:references/gemini-temperature-gap.md\n\n# Gemini Temperature Gap in generate_text()\n\n## The Bug\n\n`generate_text()` accepts `temperature=0.0` but only passes it to `ollama_generate()`.\nWhen the model is Gemini CLI, the temperature parameter is silently dropped.\n\n## Code Trace (router.py)\n\n```\ngenerate_text(model, prompt, *, timeout=60, num_predict=400, temperature=0.0)\n    |\n    +--> is_gemini_model(model)?\n         YES --> gemini_generate(model, prompt, timeout=timeout)\n                       |\n                       +--> invoke_gemini_cli(model, prompt, timeout=timeout)\n                       |\n                       temperature: NEVER PASSED. Gemini uses its built-in default (~0.7+).\n\n         NO  --> ollama_generate(model, prompt, timeout=timeout,\n                                 num_predict=num_predict,\n                                 temperature=temperature)\n                       |\n                       temperature: 0.0 (deterministic, greedy decoding)\n```\n\n## Impact\n\n- **Planner**: Same task --> different decomposition counts (5 vs 6 steps observed).\n- **Judge**: Same subtask --> slightly different scores across runs.\n- **PRO Executor**: Same prompt --> different phrasings.\n- **FLASH Executor**: Same prompt --> different output formatting.\n- **Finalizer**: Slightly different report text each run.\n\nAll of these are affected for any role configured to use Gemini CLI models.\n\n## Severity\n\n- For most use cases: minor. The outputs are still correct, just surface-level variation.\n- For reproducibility-critical workflows: unacceptable.\n- For multi-run benchmarks where decomposition count affects fanout parallelism: disruptive.\n\n## Workaround\n\nUse Ollama-backed models when deterministic output matters. Temperature=0.0 IS respected there.\n\n## Root Fix\n\n`gemini_generate()` and `invoke_gemini_cli()` need to accept and forward a `temperature` parameter.\nThis is a code change in router.py, not a configuration change.\n\nFile v0.1.5:references/linux-mm-source-html-example.md\n\n# Linux mm Source-to-HTML Hierarchy Example\n\nSession-specific pattern for a successful `background=true + notify_on_complete=true` Super-Router job that turns a large local source tree into a durable HTML explainer.\n\n## Scenario\n\nUser requested: analyze `~/home_B/linux/mm/` and generate a self-contained HTML file containing:\n\n- an elaborated hierarchy picture of the Linux `mm/` implementation;\n- interpretation and description of what `mm` is responsible for;\n- detailed workflows, principles, and source-reading guide;\n- background execution via `exec(background=true, notify_on_complete=true)`.\n\n## Durable technique\n\nUse the generic `source-html-background-wrapper` pattern, but for a very large source tree add a deterministic local source inventory stage before invoking the router:\n\n1. Create a run directory under `~/.openclaw/logs/<topic>_<timestamp>/`.\n2. Write `collect_context.py` that scans source files and emits `context.json` with:\n   - source path, file count, total lines/bytes;\n   - Makefile object samples and Kconfig option samples;\n   - subsystem buckets with file lists and line counts;\n   - representative function/symbol samples with file:line provenance;\n   - exported symbol samples where practical.\n3. Write `make_router_prompt.py` that compacts `context.json` into a grounded `ROUTER_TASK`; do not stuff full source files into the prompt.\n4. Write `generate_html.py` that builds the final self-contained HTML from `context.json` plus `super_router_stream.log`.\n5. Write `run_<topic>_router.sh` that performs collection -> prompt -> `zsh -lic` router stream -> HTML generation -> verification.\n6. Launch the wrapper with `exec(background=true, notify_on_complete=true)` and immediately `process(action=\"poll\")` once.\n\n## Linux mm bucket taxonomy that worked well\n\nFor `linux/mm/`, useful source-derived buckets were:\n\n- Boot/init + topology: `memblock`, `mm_init`, `init-mm`, `sparse`, `sparse-vmemmap`, `numa`, `memory_hotplug`, `mmzone`.\n- Physical pages + zones: `page_alloc`, `page_ext`, `page_owner`, `page_isolation`, `page_reporting`, `page_idle`, `compaction`, `shuffle`, `show_mem`.\n- Virtual address spaces: `memory.c`, `mmap`, `mprotect`, `mremap`, `msync`, `mlock`, `vma`, `vmalloc`, `pagewalk`, `pgtable`, `mseal`.\n- Page cache + file IO: `filemap`, `readahead`, `fadvise`, `truncate`, `page-writeback`, `backing-dev`, `mapping_dirty_helpers`.\n- Reclaim + working set: `vmscan`, `workingset`, `shrinker`, `list_lru`, `vmpressure`, `damon`.\n- Swap + compression: `swap`, `swapfile`, `swap_state`, `page_io`, `zswap`, `zsmalloc`, `zpool`, `zpdesc`.\n- Kernel allocators: `slab`, `slub`, `mempool`, `percpu`, `page_frag_cache`, `dmapool`, `kasan`, `kmsan`, `kfence`, `kmemleak`.\n- Huge pages + THP: `hugetlb`, `huge_memory`, `khugepaged`.\n- Cgroups + policy: `memcontrol`, `mempolicy`, `memory-tiers`, `page_counter`, `bpf_memcontrol`, `swap_cgroup`, `hugetlb_cgroup`.\n- Special mappings + reliability: `gup`, `userfaultfd`, `hmm`, `migrate`, `memory-failure`, `secretmem`, `memfd`, `cma`, `balloon`, `memremap`.\n\n## Artifact shape\n\nThe generated HTML should be self-contained and include:\n\n- source metrics near the top;\n- a clear interpretation of `mm/` as the translation layer between memory intent and physical pages;\n- an inline SVG hierarchy diagram;\n- workflow cards for boot/init, page fault, page allocation/free, page cache IO, reclaim/swap, SLUB, memcg, huge pages/migration/failure;\n- detailed `<details>` sections for subsystem buckets;\n- Makefile/Kconfig/exported-symbol evidence;\n- a provenance section with run dir, context JSON, router log, router exit, and log excerpt.\n\n## Verification thresholds\n\nTune thresholds to catch a half-written artifact. For the Linux mm hierarchy guide, suitable minimums were approximately:\n\n```bash\nbytes >= 25000\nsections >= 7\nworkflow cards >= 8\ndetails >= 10\nsvg >= 1\n```\n\nThe wrapper may still generate a valid artifact if the router provider exits non-zero, provided the HTML explicitly records the router failure and the content is grounded in verified local source inventory. Do not claim provider analysis succeeded when only the deterministic local collector and HTML generator succeeded.\n\nFile v0.1.5:references/long-running-quantitative-tasks.md\n\n# Long-Running Quantitative Tasks with Super-Router\n\n## When to Use Background Mode\n- Any task involving Monte Carlo simulation, GBM modeling, or heavy statistical computation will exceed the 600s foreground timeout.\n- Always launch with `background=true` + `notify_on_complete=true` for these workloads.\n- Foreground `--stream` runs are limited to 600s and will be killed.\n\n## Prompt Engineering for Numeric/Price Inputs\n- Explicitly write the number in words or with clear units: \"exactly 212 dollars\" instead of \"~$212\".\n- List target price levels explicitly in the prompt (e.g., 220, 240, 260, 280, 300) to reduce hallucination risk.\n- The router has shown a tendency to misparse \"$212\" as much lower values or drop the price context entirely during complex modeling steps.\n\n## Observed Failure Modes\n- Price level hallucination during Monte Carlo / GBM steps (common when the model receives ambiguous numeric input).\n- Timeout during Step 5 (Monte Carlo simulation) even when volatility modeling is requested.\n- Finalizer sometimes produces reports based on completely wrong price assumptions if the prompt is not extremely explicit.\n\n## Recommended Workflow\n1. First attempt: background mode with very explicit numeric phrasing.\n2. If the first run produces wrong price levels in the output, immediately start a second background job with even more rigid prompt language.\n3. Never rely on a single router run for financial probability estimates without verifying the price context in the final report.\n\nFile v0.1.5:references/source-html-background-wrapper.md\n\n# Source-to-HTML Background Router Wrapper\n\nUse this pattern when the user asks Super-Router to analyze a local source tree and produce a durable HTML explainer/diagram/report while explicitly requesting `background=true + notify_on_complete=true`.\n\n## What to build before launch\n\nCreate a reproducible run directory under `~/.openclaw/logs/<task>_<timestamp>/` with:\n\n- `collect_<topic>_context.py` — deterministic source scanner that writes JSON. Keep it source-derived: file inventory, line counts, key build/config files, exported symbols, representative function names, doc comments, and subsystem buckets.\n- `make_router_prompt.py` — converts the JSON inventory into a compact prompt. Avoid stuffing entire source files into `ROUTER_TASK`; summarize evidence and include paths.\n- `generate_<topic>_html.py` — creates the final self-contained HTML from the source JSON plus the router stream log. If the router fails, the HTML may still be generated only if it truthfully records the failure/log excerpt and relies on verified local context.\n- `run_<topic>_router.sh` — wrapper that runs collection, prompt generation, `router.py --stream`, artifact generation, and verification.\n\n## Wrapper requirements\n\nThe wrapper should:\n\n1. `set -uo pipefail`, create/clear `status.txt`, and print run scope (`src`, `out`, `router`).\n2. Run the context collector first and fail immediately if collection fails.\n3. Build the prompt file, then launch router via `ROUTER_TASK=\"$(/bin/cat \"$PROMPT\")\"`.\n4. Use `zsh -lic` for the router invocation so the same environment/profile setup as interactive Super-Router is visible.\n5. Tee router stdout/stderr to `super_router_stream.log` and preserve `ROUTER_EXIT` without preventing artifact generation.\n6. Generate the HTML after router completion from real `context.json` and `super_router_stream.log`.\n7. Verify the artifact directly with objective thresholds: byte count, `<section>` count, workflow/card/detail counts, and final path.\n8. Exit non-zero only for real collection/generation/verification failure, not merely because the router provider failed, as long as the artifact clearly reports that failure.\n\n## Launch and immediate response\n\nLaunch exactly with `exec(background=true, notify_on_complete=true)` when the user requested background mode. Immediately poll once with `process(action=\"poll\")` to verify the process is actually running or has already completed.\n\nThe user-facing reply after launch is not a success claim. It should include:\n\n- process session id;\n- `background=true` and `notify_on_complete=true` confirmation;\n- run directory;\n- wrapper path;\n- expected final artifact path;\n- immediate poll status (`running`, `completed`, or failed with log/status hint).\n\nDo not say the artifact is done until the background completion notification arrives and the artifact has been verified directly.\n\n## HTML artifact notes\n\nFor source hierarchy explainers, pair this with `html-artifact` conventions:\n\n- self-contained file: inline CSS/SVG, no CDN, no remote assets;\n- source-derived metrics near the top;\n- an elaborated SVG hierarchy picture;\n- workflow cards for the main execution paths;\n- subsystem guide grouped by source buckets;\n- key symbol/function anchors extracted deterministically from the source tree when the source language makes that practical;\n- a Super-Router section that records run dir, context JSON, router log path, router exit code, and phase/token excerpt.\n\nIf the router provider partially fails but the wrapper can still generate the artifact from verified local context, the HTML must say that explicitly in the provenance section. Do not claim the failed provider analysis succeeded; make the source inventory plus verification thresholds the source of truth.\n\n## Minimal verification line\n\nAt the end of the wrapper, write something like:\n\n```bash\nBYTES=$(wc -c < \"$OUT\" | tr -d ' ')\nSECTIONS=$(grep -Eo '<section' \"$OUT\" | wc -l | tr -d ' ')\nWORKFLOWS=$(grep -Eo 'class=\"workflow\"' \"$OUT\" | wc -l | tr -d ' ')\nDETAILS=$(grep -Eo '<details' \"$OUT\" | wc -l | tr -d ' ')\nprintf '[verify] html=%s bytes=%s sections=%s workflows=%s details=%s router_exit=%s\\n' \\\n  \"$OUT\" \"$BYTES\" \"$SECTIONS\" \"$WORKFLOWS\" \"$DETAILS\" \"$ROUTER_EXIT\" | tee -a \"$STATUS\"\n```\n\nUse task-appropriate thresholds so a half-written artifact fails loudly.\n\nFile v0.1.5:skill-card.md\n\n## Description:\n\nLangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalates failures, and records token usage for auditable runs.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[fanyadan](https://clawhub.ai/user/fanyadan)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agent operators use this skill to break complex requests into dependency-aware subtasks, route each branch to an appropriate model role, and produce auditable execution reports with retry, escalation, and token-usage details.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The router may send task text and project context to configured model providers.\n\nMitigation: Use a dedicated environment with minimal secrets, prefer local-only Ollama for sensitive work, and keep LangSmith prompt and output tracing off unless the data is appropriate for external tracing.\n\nRisk: The skill uses broad local execution and environment-based provider configuration.\n\nMitigation: Review local execution behavior before installation and avoid placing unrelated credentials in ~/.openclaw/.env.\n\nRisk: Untrusted task text may be unsafe until shell-invocation examples and Gemini auto-approval behavior are hardened.\n\nMitigation: Do not route untrusted task text through the skill until those behaviors have been reviewed and hardened.\n\n## Reference(s):\n\n- [Super Router on ClawHub](https://clawhub.ai/fanyadan/skills/super-router)\n- [Publisher profile](https://clawhub.ai/user/fanyadan)\n- [LangGraph documentation](https://langchain-ai.github.io/langgraph/)\n- [Ollama documentation](https://ollama.com/docs)\n- [Gemini CLI headless JSON output](https://google-gemini.github.io/gemini-cli/docs/cli/headless.html)\n- [Linux mm Source-to-HTML Hierarchy Example](references/linux-mm-source-html-example.md)\n- [Recovering Gemini CLI token usage when super-router ledger is unavailable](references/gemini-cli-token-recovery.md)\n- [Gemini CLI ripgrep Detection Fix](references/gemini-cli-ripgrep-path-fix.md)\n- [Gemini Temperature Gap in generate_text()](references/gemini-temperature-gap.md)\n- [Long-Running Quantitative Tasks with Super-Router](references/long-running-quantitative-tasks.md)\n- [Background Router Artifact Launches](references/background-artifact-launches.md)\n- [Source-to-HTML Background Router Wrapper](references/source-html-background-wrapper.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown or text reports with JSON-serializable router state and inline shell/configuration examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Outputs can include planned subtasks, model route decisions, execution results, fallback status, audit history, final reports, and token-usage summaries.]\n\n## Skill Version(s):\n\n0.1.5 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.1.4: 16 files, 99293 bytes\n\nFiles: README.md (29883b), references/background-artifact-launches.md (2893b), references/gemini-cli-ripgrep-path-fix.md (1311b), references/gemini-cli-token-recovery.md (4675b), references/gemini-temperature-gap.md (1907b), references/linux-mm-source-html-example.md (4187b), references/long-running-quantitative-tasks.md (1508b), references/source-html-background-wrapper.md (4327b), scripts/render_super_router_diagram.py (21961b), scripts/router.py (215311b), skill-card.md (2923b), SKILL.md (22854b), templates/source-html-background-wrapper.sh (3244b), tests/__init__.py (1b), tests/test_router.py (60203b), _meta.json (131b)\n\nFile v0.1.4:SKILL.md\n\n---\nname: super-router\ndescription: \"LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalates failures, and records token usage for auditable runs.\"\nversion: 1.0.0\nauthor: Yadan Fan\nlicense: MIT\nmetadata:\n  openclaw:\n    tags: [model-routing, langgraph, task-decomposition, multi-model, complexity-scoring]\n    requires:\n      bins: [python]\n  related_skills: [btc_analyzer, api-tester, ddg-search]\n---\n\n# Super Router (LangGraph Edition)\n\nSuper Router decomposes complex work into dependency-aware subtasks, scores each branch for complexity and risk, and executes it on the right model role. It combines PRO/FLASH routing, provider fallback, FLASH retry and escalation, metadata extraction, LangSmith tracing, and token usage accounting into one auditable LangGraph workflow.\n\n## Mandatory OpenClaw Invocation\n\nFor any request to use `super-router`, `super_router`, or `走 super-router`, do this exact workflow:\n\n1. Use the OpenClaw `exec` tool to run:\n   `/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py '<task>'`\n2. If `exec` returns `Command still running`, call the OpenClaw `process` tool with `action=\"poll\"` on the returned `sessionId` until the process exits.\n3. The next assistant message after completion must start with `Router result:` or `Router failed:` and must include a concrete detail from the router output.\n\nDo not run `openclaw super_router`, `openclaw super-router`, `openclaw skill`, `openclaw skills`, or a nested `openclaw agent` command to satisfy this skill. Those are not the router.\n\n## When to Use This Skill\n\nUse super-router when you need:\n- **Intelligent model routing** — automatically choose between heavy (PRO) and fast (FLASH) models per subtask\n- **Task decomposition** — break complex tasks into structured subtasks with independent routing\n- **Cost optimization** — use fast models for simple work, heavy models only when needed\n- **Configurable models** — use deterministic defaults, with environment-variable overrides for each role\n- **Failure escalation** — FLASH retry on infra failures, escalate to PRO on capability failures\n- **Audit trail** — full logging of planned vs actual routes, retries, and failure classifications\n\n**Not needed for:** Simple single-turn tasks, tasks where you already know which model to use, or when you want manual control over every routing decision.\n\n## Optimization for Parallelism\n\nTo achieve true parallel execution (when `ROUTER_MAX_CONCURRENCY > 1`), the Planner must be instructed to use **Atomic Decomposition**. \n\n- **Atomic Decomposition**: Breaking a task into the smallest possible independent units rather than grouped phases.\n- **Pitfall: Planner Grouping**: The Planner may occasionally group multiple entities into a single subtask, which kills true parallelism.\n- **Verification**: Always verify the `planned_subtasks` count matches the entity count. If the planner groups entities, treat as capability failure and retry with correction prompt.\n- **Benefit**: Prevents 'lost-in-the-middle' failures and allows executor branches to fire simultaneously.\n- **Deferred synthesis**: Summary and synthesis subtasks are held until independent executor branches finish.\n- **Implementation**: Explicitly demand atomic per-entity decomposition when prompting for multi-entity tasks.\n\n## Core Architecture (LangGraph StateGraph)\n\n| Node | Function |\n|------|----------|\n| **Planner** | Decomposes original task into a JSON array of atomic, actionable subtasks. Uses Atomic Decomposition for maximum parallelism. |\n| **Judge** | Scores each subtask on 5 dimensions: `reasoning_depth`, `code_change_scope`, `ambiguity`, `risk`, `io_heaviness`; combines with thresholds + confidence to decide PRO/FLASH |\n| **Executor Fanout** | Uses LangGraph `Send(...)` to dispatch independent subtasks concurrently, then joins ordered results by original step number |\n| **PRO Executor Branch** | Heavy reasoning model (override via `ROUTER_PRO_MODEL`) |\n| **FLASH Executor Branch** | Fast model with review/retry logic (override via `ROUTER_FLASH_MODEL`) |\n| **FLASH Review** | Validates output quality; distinguishes infra failures from capability failures; retries FLASH or escalates to PRO |\n| **Metadata Extractor** | Extracts 'Technical Gold' (atomic high-precision facts) from step output to prevent finalizer timeouts and loss of detail |\n| **Recorder/Finalizer** | Logs every step; compiles final report using a hybrid of Technical Gold and full audit trails; supports FLASH→PRO→deterministic fallback chain |\n\n## Installation\n\n```bash\n# Required: LangGraph\npip install langgraph\n\n# Optional: LangSmith telemetry\npip install langsmith\n```\n\nAll model and provider choices are configured via `ROUTER_*` variables in the OpenClaw environment config file `~/.openclaw/.env`. The router loads that file itself and still honors any explicit process environment overrides. No model names are hardcoded in the skill.\n\n## Usage\n\n### Configuring ROUTER_* Variables\n\nSet `ROUTER_*` environment variables in `~/.openclaw/.env`. OpenClaw normally exposes this file to `exec` child processes, and `router.py` also loads it directly before reading `os.environ`, so the same command works from OpenClaw and from a plain shell.\n\nTo see current values: `grep '^ROUTER_' ~/.openclaw/.env`\n\nTo use one model for every router role, set `ROUTER_MODEL`:\n\n```bash\nROUTER_MODEL=gpt-5.5\n# Equivalent explicit form:\n# ROUTER_MODEL=codex/gpt-5.5\n```\n\nRole-specific variables such as `ROUTER_PRO_MODEL` and `ROUTER_FLASH_MODEL` override `ROUTER_MODEL` when set.\n\n### Basic Usage (via OpenClaw exec)\n\nWhen the user says \"走 super-router\", \"use super-router\", or asks for router analysis, invoke `router.py` directly through OpenClaw `exec`:\n\n```python\nexec(\n    command=\"/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py 'Analyze K8s YAML errors and rewrite config'\"\n)\n```\n\n### With Streaming (Node-Level Progress)\n\n```python\nexec(command=\"/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py --stream 'Your complex task'\")\n```\n\n### Via Environment Variable (Agent Compatibility)\n\nFor agents that struggle with non-ASCII arguments, pass the task via `ROUTER_TASK`:\n\n```python\nexec(\n    command=\"/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py\",\n    env={\"ROUTER_TASK\": \"Your complex task description\"},\n)\n```\n\n### Handling Long-Running Execution\n\nIf `exec` returns \"Command still running\":\n\n```python\n# Continue polling with process tool\nprocess(action=\"poll\", session_id=\"<session_id_from_exec>\")\n\n# Wait for completion\nprocess(action=\"wait\", session_id=\"<session_id_from_exec>\", timeout=300)\n```\n\nFor background launches requested by the user, use `exec(background=true, notify_on_complete=true)` and verify the process is actually running with an immediate `process(action=\"poll\")`. If a background router launch exits immediately, inspect the preview and relaunch with the fix rather than reporting success.\n\nFor complex or multiline `ROUTER_TASK` prompts, avoid fragile inline heredocs inside `zsh -lic`. Write the task to a prompt file first, then launch with:\n\n```bash\nexport ROUTER_TASK=\"$(/bin/cat \"$HOME/.openclaw/logs/<task-name>.txt\")\"\n/opt/homebrew/Caskroom/miniforge/base/bin/python \"$HOME/.openclaw/skills/super-router/scripts/router.py\" --stream 2>&1 | tee \"$HOME/.openclaw/logs/<task-name>.log\"\n```\n\nThis preserves quotes/apostrophes in the task, keeps an auditable prompt artifact, and avoids zsh parse failures from nested heredocs.\n\n**Important:** Once process shows completion, your next assistant message MUST start with `Router result:` or `Router failed:` and include at least one real detail from the output (e.g., \"Planner fallback\", \"timeout\", \"BTC\"). Never reply with just `---`, punctuation, or empty lines.\n\n### Post-Completion Artifact Verification\n\nFor router runs that create or modify artifacts (reports, JSON logs, database ingests, generated files), do not trust the router final stdout alone. Before reporting success to the user:\n\n1. Inspect the declared output artifacts directly (`stat`, read the JSON/Markdown headers, count expected sections/cards when relevant).\n2. Compare the router final summary against the saved artifacts and machine-readable logs.\n3. If stdout and artifacts disagree, treat the artifacts/logs as the source of truth and report the discrepancy immediately.\n4. If the discrepancy means the user requirement is not satisfied (for example, requested 20 items but artifact contains 33), do not claim success. Either launch a correction pass when permitted or state the exact blocker.\n5. For ingestion workflows, verify the saved ingest JSON fields (`status`, checked/accepted/skipped counts, threshold, document list) and ensure the user-facing Markdown/HTML item set matches the accepted ingested documents.\n\n## Environment Variables\n\nAll `ROUTER_*` variables are loaded from `~/.openclaw/.env` by `router.py` before the router resolves defaults. Explicit process environment values win over `.env` values.\n\n| Variable | Purpose | Default |\n|----------|---------|---------|\n| `ROUTER_MODEL` | Global model default for planner, judge, PRO, and FLASH roles | None |\n| `ROUTER_PLANNER_MODEL` | Task decomposition model | internal default |\n| `ROUTER_PLANNER_TASK_CHAR_LIMIT` | Character budget for the compact planner-only context manifest JSON | 6000 |\n| `ROUTER_PLANNER_MAX_OUTPUT_TOKENS` | Planner JSON subtask output token cap | 4096 |\n| `ROUTER_JUDGE_CONTEXT_CHAR_LIMIT` | Character budget for judge context JSON | 3000 |\n| `ROUTER_EXECUTOR_CONTEXT_CHAR_LIMIT` | Character budget for executor context JSON | 8000 |\n| `ROUTER_METADATA_OUTPUT_CHAR_LIMIT` | Character budget for metadata extraction context JSON and output excerpts | 6000 |\n| `ROUTER_FINALIZER_CONTEXT_CHAR_LIMIT` | Character budget for finalizer context JSON | 12000 |\n| `ROUTER_JUDGE_MODEL` | Complexity scoring model | internal default |\n| `ROUTER_PRO_MODEL` | Heavy reasoning executor | internal default |\n| `ROUTER_FLASH_MODEL` | Fast executor | internal default |\n| `ROUTER_PRO_FALLBACK_MODELS` | Comma-separated PRO fallback list | None |\n| `ROUTER_FLASH_FALLBACK_MODELS` | Comma-separated FLASH fallback list | None |\n| `ROUTER_CODEX_CLI` | Codex CLI executable path for Codex-backed model names | first `codex` on `PATH`, else `codex` |\n| `ROUTER_CODEX_CWD` | Optional working directory passed to `codex exec --cd` | None |\n| `ROUTER_CODEX_SANDBOX` | Sandbox mode passed to `codex exec --sandbox` | `read-only` |\n| `ROUTER_CLAUDE_CLI` | Claude Code CLI executable path for Claude-backed model names | first `claude` on `PATH`, else `claude` |\n| `ROUTER_FLASH_RETRY_BUDGET` | Max FLASH retries before escalation | 1 |\n| `ROUTER_RECURSION_LIMIT` | Python recursion limit | 128 |\n| `ROUTER_JUDGE_TIMEOUT` | Timeout for Judge node LLM calls (seconds) | 300 |\n| `ROUTER_MAX_CONCURRENCY` | Max concurrent LangGraph branches for judge and executor fanout | Auto |\n| `ROUTER_OLLAMA_URL` | Ollama API endpoint (if used) | `http://localhost:11434/api/generate` |\n| `ROUTER_FINALIZER_TIMEOUT` | Timeout for the final reporting synthesis (seconds) | 600 |\n| `ROUTER_DEBUG` | Print raw diagnostic snippets | Off |\n| `ROUTER_LANGSMITH_ENABLED` | Enable optional LangSmith graph and model-call telemetry when `LANGSMITH_API_KEY` is set | Off |\n| `ROUTER_LANGSMITH_PROJECT` | LangSmith project name | `super-router` |\n| `ROUTER_LANGSMITH_TAGS` | Comma-separated extra LangSmith tags | None |\n| `ROUTER_LANGSMITH_TRACE_PROMPTS` | Include prompt previews in custom model-call traces | Off |\n| `ROUTER_LANGSMITH_TRACE_OUTPUTS` | Include output previews in custom model-call traces | Off |\n| `ROUTER_LANGSMITH_HIDE_INPUTS` | Request LangSmith SDK input hiding for graph traces | Off |\n| `ROUTER_LANGSMITH_HIDE_OUTPUTS` | Request LangSmith SDK output hiding for graph traces | Off |\n| `ROUTER_LANGSMITH_FLUSH` | Flush LangSmith traces before process exit | On |\n| `ROUTER_TOKEN_USAGE_LEDGER` | Optional append-only JSONL path for per-call token usage records | None |\n\nLarge local models may require higher timeouts and `ROUTER_MAX_CONCURRENCY=1`.\n\nProvider selection is model-name based:\n- Codex CLI: `codex/...`, bare `gpt-*`, bare `chatgpt-*`, or bare `o` plus digit names such as `codex/gpt-5.5` or `gpt-5.5`.\n  The router passes `--sandbox` but intentionally does not pass `--ask-for-approval`, because some `codex exec` versions do not support that option.\n- Gemini CLI: `google-gemini-cli/...`, `gemini-*`, `pro`, `flash`, `flash-lite`, or `auto`.\n- Claude Code CLI: `claude/...` or bare `claude-*` model names.\n- Ollama: all other model names, or explicit `ollama/...`.\n\n### LangSmith Telemetry\n\nLangSmith is optional and non-fatal. Enable it only when external trace upload\nis desired:\n\n```bash\nROUTER_LANGSMITH_ENABLED=1\nLANGSMITH_API_KEY=<your-langsmith-key>\nROUTER_LANGSMITH_PROJECT=super-router\n```\n\nThe router adds graph tags/metadata and traces raw provider calls as child LLM\nruns. Ollama token usage is captured from `prompt_eval_count` and `eval_count`.\nClaude Code CLI token usage is captured from JSON `total_input_tokens` and\n`total_output_tokens`. Gemini CLI token usage is captured from JSON\n`stats.models.*.tokens` when available, with `usageMetadata`-style fields as a\nfallback. Prompt and output text previews are disabled by default; enable them\nexplicitly with `ROUTER_LANGSMITH_TRACE_PROMPTS=1` or\n`ROUTER_LANGSMITH_TRACE_OUTPUTS=1`.\n\n### Token Usage Accounting\n\nToken usage is tracked even when LangSmith is disabled. The router records every\nsuccessful provider call in a run-local ledger, prints a token summary after the\nfinal report, and returns `token_usage` plus `token_usage_summary` in the final\nstate. Calls without provider token data are recorded as\n`usage_source=unavailable`. Set\n`ROUTER_TOKEN_USAGE_LEDGER=~/.openclaw/super-router-usage.jsonl` to persist the\nper-call records as append-only JSONL.\n\nIf a super-router process stops before the final token ledger is printed, Gemini\nCLI may still have persisted exact per-call token records in\n`~/.gemini/tmp/<user>/chats/session-*.jsonl`. This applies to planning-capture\ntermination, timeouts, manual kills, crashes, executor fanout interruptions, and\nmetadata/finalizer failures. Use `references/gemini-cli-token-recovery.md` to\nrecover `input`, `output`, `cached`, `thoughts`, `tool`, and `total` fields from\nmatching session JSONL files. Treat recovered values as provider telemetry;\ntreat dollar cost separately because cached-token billing depends on provider\npricing.\n\n## Complexity Routing Rules\n\n### 5-Dimension Scoring\n\nThe Judge scores each subtask on:\n\n1. **reasoning_depth** (1-10): How much logical inference is needed?\n2. **code_change_scope** (1-10): How many files/lines of code to modify?\n3. **ambiguity** (1-10): How unclear is the task specification?\n4. **risk** (1-10): What's the impact of getting this wrong?\n5. **io_heaviness** (1-10): How much reading/writing vs. thinking?\n\n### Routing Thresholds\n\n| Condition | Route |\n|-----------|-------|\n| `complexity_score >= 5` | PRO |\n| `complexity_score <= 2` | FLASH |\n| Summary-like task (no deep work) | FLASH |\n| High-risk incident diagnosis | PRO |\n| High-risk evidence gathering | PRO |\n| High-risk decision/rollback evaluation | PRO |\n| Boundary case + low confidence | PRO (safe default) |\n\n### Contextual Score Biases\n\nThe router applies automatic adjustments:\n- **High-risk context** (production, billing, security): boosts `reasoning_depth`, `risk`, `ambiguity`\n- **Evidence gathering** in incident: keeps on PRO (not mere IO)\n- **Communication/summary** subtasks: routed to FLASH unless deep work is also required\n\n## FLASH Review & Escalation Logic\n\nWhen FLASH execution fails or produces questionable output:\n\n1. **Classify failure type:**\n   - `infra_transient`: timeout, network, rate limit, service unavailable\n   - `capability_quality`: \"need more info\", empty output, too short, repeated task\n\n2. **Decision:**\n   - Infra failure -> Retry FLASH (up to `ROUTER_FLASH_RETRY_BUDGET`)\n   - Capability failure -> Escalate to PRO immediately\n   - Unknown -> Retry once, then escalate\n\n3. **Post-execution verification:**\n   - Empty output -> escalate\n   - Output < 48 chars (non-summary) -> escalate\n   - Output explicitly says \"can't complete\" -> escalate\n   - Output just repeats task description -> escalate\n\n## Finalizer Fallback Chain\n\nFinal report generation follows:\n\n```\nFLASH finalizer -> (if fails) -> PRO finalizer -> (if fails) -> Deterministic template\n```\n\n## Output Structure\n\n- **Output Structure**: The router returns a JSON-serializable state. When summarizing these results in reports or documentation, always use ASCII/Terminal-style arrows (e.g., '-->', '->') rather than mathematical arrows for all diagrams and flow representations. This is a high-priority stylistic requirement.\n\n```json\n{\n  \"task\": \"original task string\",\n  \"planner_model\": \"model name used for planning\",\n  \"judge_model\": \"model name used for complexity scoring\",\n  \"pro_model\": \"primary PRO model\",\n  \"flash_model\": \"primary FLASH model\",\n  \"planned_subtasks\": [{\"desc\": \"...\"}],\n  \"subtasks\": [\n    {\n      \"desc\": \"...\",\n      \"model\": \"PRO|FLASH\",\n      \"assessment\": {\n        \"scores\": {\"reasoning_depth\": 5, \"code_change_scope\": 3, \"ambiguity\": 2, \"risk\": 4, \"io_heaviness\": 1},\n        \"complexity_score\": 15,\n        \"suggested_route\": \"PRO\",\n        \"final_route\": \"PRO\",\n        \"confidence\": 0.85,\n        \"reason\": \"...\",\n        \"judge_source\": \"llm|heuristic\"\n      }\n    }\n  ],\n  \"results\": [\n    {\n      \"step\": 1,\n      \"planned_route\": \"PRO\",\n      \"route\": \"PRO\",\n      \"model_name\": \"...\",\n      \"desc\": \"...\",\n      \"output\": \"...\",\n      \"status\": \"success|failed\",\n      \"attempt_count\": 1,\n      \"retry_count\": 0,\n      \"escalated_from_flash\": false,\n      \"used_provider_fallback\": false,\n      \"flash_review\": {\"decision\": \"record\", \"failure_type\": \"none\", \"reason\": \"...\"},\n      \"attempt_log\": [\"...\"]\n    }\n  ],\n  \"final_report\": \"...\",\n  \"finalizer_outcome\": {\n    \"route\": \"FLASH|PRO|DETERMINISTIC\",\n    \"model_name\": \"...\",\n    \"status\": \"...\",\n    \"used_provider_fallback\": false,\n    \"reason\": \"...\",\n    \"attempt_log\": [\"...\"]\n  }\n}\n```\n\n## Maintenance\n\n| File | Purpose |\n|------|---------|\n| `scripts/router.py` | Main LangGraph router script |\n| `SKILL.md` | This documentation |\n| `references/long-running-quantitative-tasks.md` | Guidance for heavy Monte Carlo / financial modeling tasks and background execution |\n| `references/background-artifact-launches.md` | Wrapper pattern for background router runs that produce durable artifacts: prompt/context capture, stream logs, verification, and safe handling of blocked launches |\n| `references/source-html-background-wrapper.md` | Concrete pattern for source-tree-to-HTML hierarchy/explainer jobs: source JSON collector, compact router prompt, HTML generator from context+log, background launch, immediate poll, and artifact verification |\n| `references/linux-mm-source-html-example.md` | Session-specific exemplar for a large Linux `mm/` source hierarchy HTML guide: bucket taxonomy, artifact sections, and verification thresholds. Use as a model for similarly large kernel/subsystem explainers. |\n| `templates/source-html-background-wrapper.sh` | Copyable shell wrapper template for source-tree-to-HTML background jobs. Use it to avoid retyping the run/status/log/verification scaffold; replace placeholders and tune verification thresholds per artifact. |\n\n## Troubleshooting\n\n### Verifying Model Routing\n\nTo audit which model each stage actually used, run with `--stream` and check the output:\n- **Planner model**: printed as `规划模型: <model>` in the routing plan summary\n- **Judge model**: printed as `判定模型: <model>` in the routing plan summary\n- **PRO Executor**: printed as `-> <model>` per step in executor fanout\n- **FLASH Executor**: printed as `-> <model>` per step\n- **Metadata Extractor**: uses the PRO model\n- **Finalizer**: routed to FLASH first, then PRO on failure — check `finalizer_outcome.route` / `finalizer_outcome.model_name` in the returned state\n\n**Verification Audit Pattern**: For explicit per-phase LLM validation runs (e.g. K8s anomaly detection tasks), execute the router with a complex high-risk task, capture the full streaming transcript, then synthesize a self-contained HTML report. The report should include:\n- Phase cards showing attempted model vs actual outcome (including heuristic fallbacks on quota errors)\n- Routing decision table\n- Key findings on whether PRO/FLASH routing matched expectations\n- Recommendations for fallback configuration\n\nThis produces an auditable artifact that confirms the 5-node flow (Planner → Judge → Executor Fanout → Metadata → Finalizer) and surfaces any provider-specific issues like TerminalQuotaError without altering the core router logic.\n\n### Non-Determinism with Cloud APIs\n\nEven at `temperature=0.0`, cloud-hosted models may produce different decompositions across runs due to backend inference differences. The router is deterministic in its *routing logic*, not in upstream model sampling. For guaranteed reproducibility, cache planner results by task hash or use a seed parameter if the provider supports it.\n\n### Timeouts or Empty Responses\n\n- Use `--stream` and increase the terminal/process timeout if the Planner itself may take longer than 60s.\n- Set `ROUTER_JUDGE_TIMEOUT` or `ROUTER_FINALIZER_TIMEOUT` higher for large models.\n- If a model appears unexpectedly, check whether `~/.openclaw/.env` or the OpenClaw process environment contains stale `ROUTER_*_MODEL` values.\n\n### Planner produced only one subtask\n\nTask may be simple enough to not need decomposition, or the planner model may benefit from stronger prompting for atomic decomposition.\n\n### FLASH kept escalating to PRO\n\nTask may genuinely require heavy reasoning. Consider configuring a stronger FLASH model via `ROUTER_FLASH_MODEL`.\n\n## Related Skills\n\n- **dspy** — Declarative LM programming with automatic prompt optimization (Python framework alternative)\n- **btc_analyzer** — OpenClaw BTC analysis workflow that delegates structured market questions to this router\n- **api-tester** — API validation workflow that can route complex investigation subtasks through this router\n- **ddg-search** — Search-oriented support skill for evidence gathering before router execution\n- **llama-cpp** — Run LLM inference locally (alternative backend)\n\n## See Also\n\n- LangGraph documentation: https://langchain-ai.github.io/langgraph/\n- Ollama documentation: https://ollama.com/docs\n\nFile v0.1.4:README.md\n\n# Super Router\n\nSuper Router is a LangGraph-based task router that decomposes a user request,\njudges each subtask, and executes ready subtasks across PRO and FLASH model\nroles. It is built for workloads where some branches need stronger reasoning\nwhile others are simple reporting, formatting, or low-risk IO.\n\nThe current implementation supports planner and dependency fallback paths,\ndependency-aware executor fanout, provider fallback lists, FLASH retry and\nFLASH-to-PRO escalation, embedded technical metadata extraction, LangSmith\ntracing, and token usage accounting.\n\n## Workflow\n\n![Super-Router LangGraph Architecture](super-router.png)\n\n## What It Does\n\n- Compacts long task text into deterministic context manifests before planning,\n  judging, executing, metadata extraction, and finalization.\n- Plans atomic subtasks with stable IDs and optional `depends_on` edges.\n- Verifies and corrects the dependency DAG before execution.\n- Scores each subtask on reasoning depth, code-change scope, ambiguity, risk,\n  and IO heaviness.\n- Routes subtasks to `PRO` or `FLASH` using model scores plus deterministic\n  risk, summary, and confidence guards.\n- Schedules only dependency-ready subtasks, fans them out with LangGraph\n  `Send(...)`, joins completed waves, and repeats until the DAG is complete.\n- Executes model calls through Codex CLI, Gemini CLI, Claude Code CLI, or\n  Ollama, selected by model name.\n- Retries FLASH on transient infrastructure failures and escalates to PRO on\n  quality or capability failures.\n- Extracts compact \"technical gold\" metadata from successful executor outputs\n  inside each executor branch.\n- Produces the final report through a FLASH finalizer, then a PRO finalizer,\n  then a deterministic fallback report if model finalization fails.\n- Tracks provider token usage per run, prints an aggregate summary, and can\n  persist append-only JSONL records.\n\n## Repository Layout\n\n```text\n.\n|-- README.md\n|-- SKILL.md\n|-- super-router.png\n|-- references/\n|-- scripts/\n|   |-- render_super_router_diagram.py\n|   `-- router.py\n|-- templates/\n`-- tests/\n    |-- __init__.py\n    `-- test_router.py\n```\n\n| Path | Purpose |\n| --- | --- |\n| `SKILL.md` | OpenClaw skill contract, usage notes, architecture summary, and environment reference. |\n| `scripts/router.py` | Main LangGraph router, provider dispatch, fallback logic, telemetry, token accounting, and CLI. |\n| `scripts/render_super_router_diagram.py` | Deterministic diagram renderer; verifies the diagram node set against `build_router_graph()`. |\n| `super-router.png` | Current architecture diagram used by this README. |\n| `tests/test_router.py` | Offline regression tests using `unittest` and mocks. |\n| `references/` | Supplemental operational notes. |\n| `templates/` | Shell helper templates. |\n\n## Requirements\n\n- Python 3.10+.\n- `langgraph` for the runtime graph.\n- `langsmith` only when optional telemetry is enabled.\n- `Pillow` only when regenerating `super-router.png`.\n- At least one usable model provider:\n  - Codex CLI for `codex/...`, bare `gpt-*`, bare `chatgpt-*`, or bare\n    `o` plus digit model names.\n  - Gemini CLI for `google-gemini-cli/...`, `gemini-*`, `auto`, `pro`,\n    `flash`, or `flash-lite`.\n  - Claude Code CLI for `claude/...` or bare `claude-*` model names.\n  - Ollama for all other names, or explicit `ollama/...`.\n\nInstall the required runtime dependency:\n\n```bash\npip install langgraph\n```\n\nOptional dependencies:\n\n```bash\npip install langsmith\npip install pillow\n```\n\n## Installation\n\n### As an OpenClaw Skill\n\nInstall or copy this repository into the local OpenClaw skills directory, then\nplace router configuration in `~/.openclaw/.env`. OpenClaw normally exposes that\nfile to `exec` child processes, and `router.py` also loads it directly before\nresolving defaults.\n\nTypical local install:\n\n```bash\nmkdir -p ~/.openclaw/skills\ncp -R . ~/.openclaw/skills/super-router\n```\n\nAfter installation, trigger it with phrasing such as `use super-router` or\n`走 super-router`.\n\n### Standalone\n\nRun from this repository after installing `langgraph`:\n\n```bash\npython scripts/router.py \"Inspect router state flow and summarize\"\n```\n\nFor Ollama-backed models, start Ollama and pull the models you intend to use:\n\n```bash\nollama serve\nollama pull <model-name>\n```\n\n## Quick Start\n\nRun a task:\n\n```bash\npython scripts/router.py \"Analyze a multi-step task and prepare an action summary\"\n```\n\nStream node-level LangGraph progress:\n\n```bash\npython scripts/router.py --stream \"Analyze a complex task, identify required actions, and draft a final note\"\n```\n\nPass the task through the environment:\n\n```bash\nROUTER_TASK=\"Update a module, add tests, and refresh documentation\" \\\npython scripts/router.py\n```\n\nRun tests:\n\n```bash\npython -m unittest tests/test_router.py\n```\n\n## Current Architecture\n\nThe main graph is built by `build_router_graph()` in `scripts/router.py`.\n\n```text\nSTART\n  -> planner_warmup\n       loops until 3 attempts, or is skipped with ROUTER_SKIP_WARMUP\n  -> planner_invoke\n  -> planner_parse\n       parse failure -> planner_fallback\n  -> dependency_judge\n  -> dependency_validate\n       invalid DAG -> conservative serial dependency fallback\n  -> planner_ready\n  -> judge_warmup\n  -> judge_subtask fanout\n  -> assemble_plan\n  -> dependency_scheduler\n       ready subtasks -> parallel_executor fanout\n       no ready subtasks with remaining work -> dependency_deadlock\n       no remaining work -> execution_finalize_join\n  -> dependency_execution_join\n       returns to dependency_scheduler for the next ready wave\n  -> execution_finalize_join\n  -> flash_finalizer\n  -> flash_finalizer_verify\n       accepted -> finalizer_complete\n       rejected or failed -> pro_finalizer or deterministic_finalizer\n  -> pro_finalizer\n  -> pro_finalizer_verify\n       accepted -> finalizer_complete\n       rejected or failed -> deterministic_finalizer\n  -> deterministic_finalizer\n  -> finalizer_complete\n  -> END\n```\n\nThe router also uses a nested provider fallback graph for every model call that\nneeds fallback support:\n\n```text\nmodel_attempt_prepare -> model_invoke -> model_attempt_prepare or END\n```\n\nFallback candidates are deduplicated. Infrastructure or unknown failures can\nadvance to the next provider candidate; capability or quality failures stop the\nprovider fallback loop.\n\n## Runtime Flow\n\n1. Build initial state, resolve model roles, fallback lists, retry budget,\n   recursion limit, and optional max concurrency.\n2. Warm the planner model with three `OK` calls unless warmup is skipped.\n3. Ask the planner for raw JSON subtasks with stable IDs and dependency hints.\n4. Parse and normalize planner output; if that fails, build heuristic fallback\n   subtasks.\n5. Ask the dependency judge to correct only `depends_on` edges and dependency\n   reasons.\n6. Validate the DAG; if invalid, convert it to a conservative serial plan.\n7. Warm the judge model unless warmup is skipped.\n8. Fan out one judge branch per planned subtask.\n9. Assemble the ordered plan and display route, score, confidence, and\n   dependency rationale.\n10. Repeatedly schedule every subtask whose dependencies have completed.\n11. Execute each ready branch through PRO or FLASH, including provider\n   fallback, FLASH review, retry, escalation, and branch-local metadata\n   extraction.\n12. Join executor wave results and return to the scheduler until all subtask\n   IDs are complete.\n13. If dependency scheduling deadlocks, record fallback results for blocked\n   subtasks and continue to finalization.\n14. Finalize with FLASH, escalate to PRO when useful, or emit a deterministic\n   fallback report.\n15. Print the final report, token usage summary, and optional ledger path.\n\n## Planning And Dependencies\n\nThe planner receives a compact task context manifest rather than unbounded raw\ntask text. Long prompts are converted into JSON fields such as objective,\nentities, constraints, deliverables, evidence requirements, decomposition\nhints, and a compact source brief.\n\nPlanner output is expected to be raw JSON:\n\n```json\n[\n  {\n    \"id\": \"S1\",\n    \"desc\": \"Inspect the first required technical area\",\n    \"depends_on\": [],\n    \"dependency_reason\": \"Independent evidence collection.\"\n  },\n  {\n    \"id\": \"S2\",\n    \"desc\": \"Prepare the requested final summary\",\n    \"depends_on\": [\"S1\"],\n    \"dependency_reason\": \"Summary depends on the inspection findings.\"\n  }\n]\n```\n\nThe dependency judge may remove unnecessary dependencies or add required ones,\nbut it must keep the existing subtasks and IDs. If dependency judgment fails,\nthe router keeps the planner dependencies and still validates them. If\nvalidation detects duplicate IDs, unknown dependencies, self-dependencies, or\ncycles, execution falls back to a serial dependency chain.\n\n## Complexity Scoring\n\nEach subtask is judged independently with the original task available as risk\ncontext. The judge returns:\n\n```json\n{\n  \"scores\": {\n    \"reasoning_depth\": 2,\n    \"code_change_scope\": 1,\n    \"ambiguity\": 1,\n    \"risk\": 0,\n    \"io_heaviness\": 0\n  },\n  \"suggested_route\": \"PRO\",\n  \"confidence\": 0.87,\n  \"reason\": \"Requires debugging and non-trivial code inspection.\"\n}\n```\n\nScore ranges:\n\n| Field | Range | Meaning |\n| --- | --- | --- |\n| `reasoning_depth` | `0-3` | Lookup or formatting through architecture/open-ended investigation. |\n| `code_change_scope` | `0-3` | No code change through broad refactor or migration. |\n| `ambiguity` | `0-2` | Clear through unclear or open-ended. |\n| `risk` | `0-2` | Low risk through high-risk or hard-to-reverse. |\n| `io_heaviness` | `0-2` | Little IO through mostly IO, reporting, or formatting. |\n\nThe aggregate `complexity_score` is:\n\n```text\nreasoning_depth + code_change_scope + ambiguity + risk\n```\n\nRouting guards then adjust or override the model suggestion:\n\n| Condition | Route |\n| --- | --- |\n| Summary, report, recap, or status update with no deep-work language | FLASH |\n| Diagnostic investigation, debugging, fixing, implementation, migration, refactor, or design work | PRO |\n| High-risk operational, financial, security, rollback, containment, or incident work | PRO |\n| High-risk evidence gathering that supports diagnosis or decision-making | PRO |\n| Judge confidence below `0.35` | PRO |\n| `complexity_score >= 5` | PRO |\n| Any of reasoning depth, code-change scope, or risk is at least `2` | PRO |\n| `complexity_score <= 2` and IO-heavy with high confidence | FLASH |\n| Boundary or unclear case | PRO |\n\nIf structured judge output fails, the router builds a heuristic assessment using\nthe same score fields, route decision function, and audit fields.\n\n## Dependency-Aware Execution\n\nExecution is wave-based:\n\n- `dependency_scheduler` computes completed subtask IDs and remaining work.\n- Ready subtasks are those whose `depends_on` IDs are all complete.\n- Ready subtasks are dispatched concurrently to `parallel_executor`, bounded by\n  LangGraph `max_concurrency`.\n- `dependency_execution_join` orders completed wave results, records progress,\n  and returns control to the scheduler.\n- `execution_finalize_join` creates the final ordered `results` list once all\n  subtasks are complete.\n\nExecutor prompts include only direct dependency results for the active subtask.\nThis keeps comparison, synthesis, and reporting steps from running before the\nevidence-producing branches they depend on.\n\nIf no subtask is ready while work remains, `dependency_deadlock` records\nfallback results for blocked subtasks, adds errors, and allows the finalizer to\nreport the dependency issue instead of crashing the graph.\n\n## FLASH Review And Escalation\n\nFLASH execution is accepted only when the output passes heuristic review.\n\nInfrastructure-style failures are retried until `ROUTER_FLASH_RETRY_BUDGET` is\nexhausted:\n\n- timeout\n- network failure\n- rate limit\n- connection reset or refused\n- service unavailable\n- transport or deadline errors\n\nCapability or quality failures escalate to PRO:\n\n- empty output\n- too-short output for a non-summary subtask\n- output that simply repeats the subtask description\n- output saying it cannot complete or needs more context\n- provider failure classified as capability or quality rather than\n  infrastructure\n\nIf FLASH retry budget is exhausted, the branch records a deterministic failure\nmessage and the graph continues.\n\n## Provider Selection\n\nModel names choose the transport:\n\n| Transport | Model-name match |\n| --- | --- |\n| Codex CLI | `codex/...`, bare `gpt-*`, bare `chatgpt-*`, or bare `o` plus digit names such as `o3` or `o4-mini`. Explicit `ollama/`, `claude/`, and `google-gemini-cli/` prefixes take precedence. |\n| Gemini CLI | `google-gemini-cli/...`, bare `gemini-*`, `auto`, `pro`, `flash`, or `flash-lite`. |\n| Claude Code CLI | `claude/...` or bare `claude-*`. |\n| Ollama HTTP | All other model names, including explicit `ollama/...`. |\n\nDefault role models:\n\n| Role | Default |\n| --- | --- |\n| Planner | `google-gemini-cli/gemini-3-pro-preview` |\n| Judge | `google-gemini-cli/gemini-3-flash-preview` |\n| PRO executor/finalizer | `google-gemini-cli/gemini-3-pro-preview` |\n| FLASH executor/finalizer | `google-gemini-cli/gemini-3-flash-preview` |\n\nUse one model for every role:\n\n```bash\nexport ROUTER_MODEL=gpt-5.5\n```\n\nOverride individual roles:\n\n```bash\nexport ROUTER_PLANNER_MODEL=google-gemini-cli/gemini-3-pro-preview\nexport ROUTER_JUDGE_MODEL=google-gemini-cli/gemini-3-flash-preview\nexport ROUTER_PRO_MODEL=google-gemini-cli/gemini-3-pro-preview\nexport ROUTER_FLASH_MODEL=google-gemini-cli/gemini-3-flash-preview\n```\n\nProvider fallback placeholders:\n\n```bash\nexport ROUTER_PRO_MODEL=google-gemini-cli/gemini-3-pro-preview\nexport ROUTER_PRO_FALLBACK_MODELS=<pro-fallback-1>,<pro-fallback-2>\n\nexport ROUTER_FLASH_MODEL=google-gemini-cli/gemini-3-flash-preview\nexport ROUTER_FLASH_FALLBACK_MODELS=<flash-fallback-1>,<flash-fallback-2>\n```\n\nCodex-specific settings:\n\n```bash\nexport ROUTER_MODEL=codex/gpt-5.5\nexport ROUTER_CODEX_CWD=/path/to/worktree\nexport ROUTER_CODEX_SANDBOX=read-only\n```\n\nThe router invokes Codex with `codex exec`, `--ephemeral`,\n`--skip-git-repo-check`, `--color never`, and `--output-last-message`. It\nintentionally does not pass `--ask-for-approval`, because some `codex exec`\nversions do not support that option.\n\nFor local large models, prefer a strong planner and a smaller judge, and\nserialize fanout:\n\n```bash\nexport ROUTER_PLANNER_MODEL=<strong-local-model>\nexport ROUTER_JUDGE_MODEL=<smaller-local-model>\nexport ROUTER_MAX_CONCURRENCY=1\n```\n\n## Environment Variables\n\nWhen running as an OpenClaw skill, set these in `~/.openclaw/.env` (one\n`KEY=VALUE` per line). When running standalone, either keep `~/.openclaw/.env`\nin place or export values in your shell.\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `ROUTER_TASK` | unset | Task text used when no positional CLI task is provided. |\n| `ROUTER_MODEL` | unset | Global model default for planner, judge, PRO, and FLASH roles. Role-specific variables override it. |\n| `ROUTER_PLANNER_MODEL` | `google-gemini-cli/gemini-3-pro-preview` | Model used for task decomposition. |\n| `ROUTER_JUDGE_MODEL` | `google-gemini-cli/gemini-3-flash-preview` | Model used for dependency judgment and complexity scoring. |\n| `ROUTER_PRO_MODEL` | `google-gemini-cli/gemini-3-pro-preview` | Primary PRO executor and PRO finalizer model. |\n| `ROUTER_FLASH_MODEL` | `google-gemini-cli/gemini-3-flash-preview` | Primary FLASH executor and FLASH finalizer model. |\n| `ROUTER_PRO_FALLBACK_MODELS` | unset | Comma-separated PRO provider fallback list. |\n| `ROUTER_FLASH_FALLBACK_MODELS` | unset | Comma-separated FLASH provider fallback list. |\n| `ROUTER_FLASH_RETRY_BUDGET` | `1` | Number of FLASH retries for transient or unknown failures before recording failure. |\n| `ROUTER_SKIP_WARMUP` | false | Skip planner and judge warmup pings when set to `1`, `true`, or `yes`. |\n| `ROUTER_RECURSION_LIMIT` | `128` | LangGraph recursion limit for the main graph. |\n| `ROUTER_MAX_CONCURRENCY` | auto | Max concurrent LangGraph branches. Auto resolves to `1` for large judge models and otherwise leaves LangGraph default behavior. |\n| `ROUTER_PLANNER_TASK_CHAR_LIMIT` | `6000` | Character budget for the compact planner context manifest. |\n| `ROUTER_PLANNER_MAX_OUTPUT_TOKENS` | `4096` | Planner JSON output token cap. |\n| `ROUTER_JUDGE_CONTEXT_CHAR_LIMIT` | `3000` | Character budget for judge context JSON. |\n| `ROUTER_EXECUTOR_CONTEXT_CHAR_LIMIT` | `8000` | Character budget for executor context JSON. |\n| `ROUTER_METADATA_OUTPUT_CHAR_LIMIT` | `6000` | Character budget for metadata extraction context and output excerpts. |\n| `ROUTER_FINALIZER_CONTEXT_CHAR_LIMIT` | `12000` | Character budget for finalizer context JSON. |\n| `ROUTER_JUDGE_TIMEOUT` | `6000` for large judge models, otherwise `300` | Timeout in seconds for dependency judge and complexity judge calls. |\n| `ROUTER_FINALIZER_TIMEOUT` | `6000` | Timeout in seconds for FLASH and PRO finalizer calls. |\n| `ROUTER_OLLAMA_URL` | `http://localhost:11434/api/generate` | Ollama generate endpoint. |\n| `ROUTER_CODEX_CLI` | first `codex` on `PATH`, else `codex` | Codex CLI executable path. |\n| `ROUTER_CODEX_CWD` | unset | Optional working directory passed to `codex exec --cd`. |\n| `ROUTER_CODEX_SANDBOX` | `read-only` | Sandbox mode passed to `codex exec --sandbox`. |\n| `ROUTER_GEMINI_CLI` | first `gemini` on `PATH`, else `/opt/homebrew/bin/gemini` | Gemini CLI executable path. |\n| `GEMINI_CLI_SYSTEM_SETTINGS_PATH` | platform default | Optional base Gemini CLI settings file. The router writes a temporary settings override per call to force temperature. |\n| `ROUTER_CLAUDE_CLI` | first `claude` on `PATH`, else `claude` | Claude Code CLI executable path. |\n| `ROUTER_DEBUG` | false | Print raw planner, judge, and provider diagnostic snippets when set to `1`, `true`, `yes`, `on`, or `debug`. |\n| `ROUTER_TOKEN_USAGE_LEDGER` | unset | Optional append-only JSONL path for per-call token usage records. |\n\nThe code-level PRO executor, FLASH executor, and finalizer defaults are\nconservative (`6000` seconds) for long-running model workflows. External shell,\nterminal, or process supervisors can still stop the process earlier.\n\nUnset judge, executor, metadata, and finalizer context limits are doubled for\nhigh-risk tasks. Explicit environment values are used as-is.\n\n## LangSmith Telemetry\n\nLangSmith tracing is optional and non-fatal. It is active only when the\n`langsmith` package is importable, tracing is requested, and an API key is\nconfigured.\n\nEnable tracing:\n\n```bash\nexport ROUTER_LANGSMITH_ENABLED=1\nexport LANGSMITH_API_KEY=<your-langsmith-key>\nexport ROUTER_LANGSMITH_PROJECT=super-router\nexport ROUTER_LANGSMITH_TAGS=local,openclaw\n```\n\nTracing can also be requested through `LANGSMITH_TRACING` or\n`LANGCHAIN_TRACING_V2` when `ROUTER_LANGSMITH_ENABLED` is unset. Set\n`ROUTER_LANGSMITH_ENABLED=false` to force tracing off.\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `ROUTER_LANGSMITH_ENABLED` | unset/false | Router-specific tracing toggle. |\n| `LANGSMITH_API_KEY` / `LANGCHAIN_API_KEY` | unset | API key used by the LangSmith client. |\n| `ROUTER_LANGSMITH_PROJECT` | `super-router` | Project name; falls back to `LANGSMITH_PROJECT`. |\n| `ROUTER_LANGSMITH_TAGS` | unset | Comma-separated tags appended to `super-router,langgraph`. |\n| `LANGSMITH_ENDPOINT` / `LANGCHAIN_ENDPOINT` | LangSmith default | Optional API endpoint. |\n| `LANGSMITH_WORKSPACE_ID` | unset | Optional workspace ID. |\n| `ROUTER_LANGSMITH_TRACE_PROMPTS` | false | Include compact prompt previews in custom model-call traces. |\n| `ROUTER_LANGSMITH_TRACE_OUTPUTS` | false | Include compact output previews in custom model-call traces. |\n| `ROUTER_LANGSMITH_HIDE_INPUTS` | false | Request SDK input hiding for graph traces. |\n| `ROUTER_LANGSMITH_HIDE_OUTPUTS` | false | Request SDK output hiding for graph traces. Token counts are retained when available. |\n| `ROUTER_LANGSMITH_FLUSH` | true | Flush traces before process exit. |\n\nThe graph run includes `super-router` and `langgraph` tags, role model names,\nfallback counts, retry budget, run ID, and task length. Raw provider calls are\ntraced as `Super Router Model Call` child runs with provider, transport,\ntimeout, token usage when available, and prompt/output lengths by default.\nPrompt and output text previews are opt-in.\n\n## Token Usage Accounting\n\nToken usage is tracked even when LangSmith is disabled. Each successful\nprovider call records:\n\n- run ID and call index\n- label, provider, model, and usage source\n- input, output, total, cached, candidate, thought, and tool tokens when\n  available\n- prompt and output character counts\n\nProvider sources:\n\n| Provider | Usage source |\n| --- | --- |\n| Ollama | `prompt_eval_count` and `eval_count` from `/api/generate`. |\n| Gemini CLI | `stats.models.*.tokens` when available, with `usageMetadata` fields as fallback. |\n| Claude Code CLI | `usage`, `model_usage`, or legacy total input/output token fields from JSON output. |\n| Codex CLI | Recorded as `usage_source=unavailable` unless the CLI output supplies token data in the future. |\n\nThe final state contains `token_usage` and `token_usage_summary`, and the CLI\nprints the same aggregate after the final report. Persist JSONL records with:\n\n```bash\nexport ROUTER_TOKEN_USAGE_LEDGER=~/.openclaw/super-router-usage.jsonl\n```\n\nEach JSONL line contains run metadata, the aggregate summary, and one\nprovider-call record.\n\n## CLI\n\n```text\nusage: router.py [-h] [--stream] [task ...]\n```\n\n| Argument | Meaning |\n| --- | --- |\n| `task` | Task description. Positional words are joined with spaces. If omitted, `ROUTER_TASK` is used. |\n| `--stream` | Emit node-level LangGraph progress updates while the graph runs. |\n| `-h`, `--help` | Show CLI help. |\n\n## Python API\n\nThe main programmatic entry point is `run_router_app()`:\n\n```python\nfrom scripts.router import run_router_app\n\nstate = run_router_app(\n    \"Inspect router state flow and summarize\",\n    planner_model=\"google-gemini-cli/gemini-3-pro-preview\",\n    judge_model=\"google-gemini-cli/gemini-3-flash-preview\",\n    pro_model=\"google-gemini-cli/gemini-3-pro-preview\",\n    flash_model=\"google-gemini-cli/gemini-3-flash-preview\",\n    max_concurrency=1,\n    stream=True,\n)\n\nprint(state[\"status\"])\nprint(state[\"final_report\"])\n```\n\nUseful lower-level helpers:\n\n| Helper | Purpose |\n| --- | --- |\n| `create_initial_state()` | Resolve models, fallback lists, retry budget, and initial graph state. |\n| `prepare_router_run()` | Build the graph and resolve graph config without invoking it. |\n| `build_router_graph()` | Compile the main LangGraph `StateGraph`. |\n| `generate_text()` | Dispatch one prompt to the provider inferred from the model name. |\n| `invoke_with_provider_fallback()` | Execute a provider candidate sequence through the nested fallback graph. |\n| `build_fallback_assessment()` | Build heuristic judge output when structured scoring fails. |\n| `verify_flash_output()` | Apply FLASH quality review. |\n| `build_fallback_report()` | Build the deterministic final report. |\n\n## Output State\n\n`run_router_app()` returns a JSON-serializable `RouterState`. Important fields:\n\n```json\n{\n  \"run_id\": \"uuid\",\n  \"task\": \"original task string\",\n  \"planner_model\": \"model used for planning\",\n  \"judge_model\": \"model used for dependency and route judgment\",\n  \"pro_model\": \"primary PRO model\",\n  \"flash_model\": \"primary FLASH model\",\n  \"pro_fallback_models\": [\"optional\", \"fallbacks\"],\n  \"flash_fallback_models\": [\"optional\", \"fallbacks\"],\n  \"planned_subtasks\": [\n    {\n      \"id\": \"S1\",\n      \"desc\": \"subtask text\",\n      \"depends_on\": [],\n      \"dependency_reason\": \"why this dependency shape is valid\"\n    }\n  ],\n  \"subtasks\": [\n    {\n      \"id\": \"S1\",\n      \"desc\": \"subtask text\",\n      \"depends_on\": [],\n      \"model\": \"PRO\",\n      \"assessment\": {\n        \"scores\": {\n          \"reasoning_depth\": 2,\n          \"code_change_scope\": 1,\n          \"ambiguity\": 1,\n          \"risk\": 0,\n          \"io_heaviness\": 0\n        },\n        \"complexity_score\": 4,\n        \"suggested_route\": \"PRO\",\n        \"final_route\": \"PRO\",\n        \"confidence\": 0.9,\n        \"reason\": \"Requires investigation.\",\n        \"judge_source\": \"structured_llm\"\n      }\n    }\n  ],\n  \"results\": [\n    {\n      \"step\": 1,\n      \"subtask_id\": \"S1\",\n      \"depends_on\": [],\n      \"planned_route\": \"FLASH\",\n      \"route\": \"PRO\",\n      \"model_name\": \"google-gemini-cli/gemini-3-pro-preview\",\n      \"desc\": \"subtask text\",\n      \"output\": \"model output\",\n      \"status\": \"executed\",\n      \"attempt_count\": 2,\n      \"retry_count\": 0,\n      \"escalated_from_flash\": true,\n      \"used_provider_fallback\": false,\n      \"flash_review\": {\n        \"decision\": \"escalate\",\n        \"failure_type\": \"capability_quality\",\n        \"reason\": \"FLASH output was too short for a non-summary step.\"\n      },\n      \"attempt_log\": [\"audit log entries\"]\n    }\n  ],\n  \"history\": [\"graph audit history and technical metadata blocks\"],\n  \"errors\": [\"fallback or failure messages\"],\n  \"final_report\": \"final report text\",\n  \"finalizer_outcome\": {\n    \"route\": \"FLASH\",\n    \"model_name\": \"google-gemini-cli/gemini-3-flash-preview\",\n    \"status\": \"finished\",\n    \"used_provider_fallback\": false,\n    \"reason\": \"Finalizer output passed heuristic verification.\",\n    \"attempt_log\": [\"audit log entries\"]\n  },\n  \"token_usage\": [],\n  \"token_usage_summary\": {\n    \"calls\": 0,\n    \"calls_with_usage\": 0,\n    \"calls_without_usage\": 0,\n    \"input_tokens\": 0,\n    \"output_tokens\": 0,\n    \"total_tokens\": 0\n  },\n  \"status\": \"finished\"\n}\n```\n\n## Development\n\nRun the full regression suite:\n\n```bash\npython -m unittest tests/test_router.py\n```\n\nUseful focused checks:\n\n```bash\npython -m unittest tests.test_router.RouterHelperTests\npython -m unittest tests.test_router.ProviderFallbackTests\npython -m unittest tests.test_router.FlashReviewAndMetadataTests\npython -m unittest tests.test_router.FinalizerTests\npython -m unittest tests.test_router.RouterGraphIntegrationTests\n```\n\nRegenerate the architecture diagram after changing graph nodes:\n\n```bash\npython scripts/render_super_router_diagram.py\n```\n\nThe renderer raises an error if `EXPECTED_GRAPH_NODES` in\n`scripts/render_super_router_diagram.py` is stale relative to\n`build_router_graph()`.\n\nCurrent tests cover:\n\n- environment parsing and default state construction\n- LangSmith configuration and trace redaction helpers\n- planner JSON extraction and subtask normalization\n- planner context compaction for long tasks\n- dependency judgment and DAG validation behavior\n- bounded context packs for judge, executor, metadata, and finalizer prompts\n- provider selection for Gemini, Codex, Claude, and Ollama\n- provider usage metadata extraction\n- provider fallback retry and capability-stop behavior\n- token usage tracking and JSONL ledger persistence\n- FLASH review, retry, and escalation guards\n- metadata extraction behavior\n- finalizer timeout, verification, and fallback behavior\n- full mocked graph success, FLASH escalation, dependency-aware concurrency,\n  dependency blocking, and streamed execution\n\nWhen changing router logic, add regression coverage for new route decisions,\nenvironment variables, graph nodes or edges, fallback order, token accounting,\nstream output, and finalizer behavior.\n\n## Troubleshooting\n\n### Task Description Required\n\nProvide a positional task or set `ROUTER_TASK`:\n\n```bash\nROUTER_TASK=\"Summarize the router graph\" python scripts/router.py\n```\n\n### Gemini CLI Executable Was Not Found\n\nInstall Gemini CLI or set:\n\n```bash\nexport ROUTER_GEMINI_CLI=/path/to/gemini\n```\n\n### Claude CLI Executable Was Not Found\n\nInstall Claude Code CLI or set:\n\n```bash\nexport ROUTER_CLAUDE_CLI=/path/to/claude\n```\n\n### Codex CLI Executable Was Not Found\n\nInstall Codex CLI or set:\n\n```bash\nexport ROUTER_CODEX_CLI=/path/to/codex\n```\n\n### Gemini Network Preflight Failed\n\nBefore invoking Gemini CLI, the router checks connectivity to required Google\nendpoints when no proxy is configured. If your environment requires a proxy,\nconfigure one of:\n\n```bash\nexport HTTPS_PROXY=http://proxy.example:8080\nexport HTTP_PROXY=http://proxy.example:8080\nexport ALL_PROXY=socks5://proxy.example:1080\n```\n\n### Unable To Reach Ollama\n\nStart Ollama and confirm the endpoint:\n\n```bash\nollama serve\nexport ROUTER_OLLAMA_URL=http://localhost:11434/api/generate\n```\n\n### Planner Or Judge Is Slow\n\nLarge local models can take minutes, especially on first load. Use streaming\nand serialize fanout:\n\n```bash\nexport ROUTER_MAX_CONCURRENCY=1\npython scripts/router.py --stream \"Analyze a complex task and draft a summary\"\n```\n\nSkip warmup pings during local iteration:\n\n```bash\nexport ROUTER_SKIP_WARMUP=1\n```\n\n### FLASH Keeps Escalating To PRO\n\nInspect `flash_review` in `state[\"results\"]`. Common reasons are empty output,\nvery short non-summary output, \"need more context\" style responses, or an\ninfrastructure failure that exhausted the retry budget.\n\n### Finalizer Uses The Deterministic Report\n\nInspect `finalizer_outcome`, `finalizer_error`, and\n`finalizer_attempt_log`. Common causes are provider timeouts, authentication\nfailures, short finalizer output, or FLASH and PRO resolving to the same\neffective model path after a non-capability FLASH failure.\n\n## Security Notes\n\n- Do not commit credentials, private endpoints, or provider authentication\n  artifacts.\n- Keep provider configuration in environment variables or `~/.openclaw/.env`.\n- Leave prompt and output tracing disabled for sensitive workloads unless you\n  explicitly need previews.\n- Treat model outputs as untrusted text; validate before automating\n  irreversible operations.\n- Keep tests offline by mocking provider calls.\n\n## Related Documentation\n\n- `SKILL.md` for OpenClaw-specific invocation guidance.\n- `references/` for supplemental operational notes.\n- LangGraph documentation: https://langchain-ai.github.io/langgraph/\n- Ollama documentation: https://ollama.com/docs\n- Gemini CLI headless JSON output: https://google-gemini.github.io/gemini-cli/docs/cli/headless.html\n\nFile v0.1.4:_meta.json\n\n{\n  \"ownerId\": \"kn71hy12wp4z8b19wb103v938d81yez7\",\n  \"slug\": \"super-router\",\n  \"version\": \"0.1.4\",\n  \"publishedAt\": 1782800984925\n}\n\nFile v0.1.4:references/background-artifact-launches.md\n\n# Background Router Artifact Launches\n\nUse this pattern when a user asks to run super-router in background mode and produce a durable artifact such as an HTML report.\n\n## Pattern\n\n1. Build small, auditable support files before launching:\n   - a source/context collection script, if the task depends on local code or data;\n   - a router prompt file for complex/multiline task text;\n   - a wrapper script that records `run_dir`, status, router stream log, final artifact path, and verification results.\n2. Launch the wrapper with `exec(background=true, notify_on_complete=true)`.\n3. If the launch succeeds, immediately poll once to verify the process is actually running or completed with useful output.\n4. The wrapper should tee router stdout/stderr to a log and preserve the exact prompt/context used for the run.\n5. For artifact-producing jobs, generate or finalize the artifact only from real collected context and router output. If router/provider execution fails, the artifact may still be created only if it truthfully records the failure/log tail and uses verified local context; never hide a failed router run behind a polished report.\n6. Verify the final artifact directly before claiming success, e.g. `wc -c`, section/card counts, and any required source-derived sections.\n7. If the command guard blocks the launch, do not retry, rephrase, or work around it. Report the prepared files and the exact blocked launch scope, then wait for user approval.\n\n## Wrapper skeleton\n\n```bash\n#!/usr/bin/env bash\nset -u\nSRC=\"$HOME/path/to/source\"\nRUN_DIR=\"$HOME/.openclaw/logs/task_$(date +%Y%m%d_%H%M%S)\"\nmkdir -p \"$RUN_DIR\"\nCTX=\"$RUN_DIR/source_context.md\"\nPROMPT=\"$RUN_DIR/router_prompt.txt\"\nLOG=\"$RUN_DIR/super_router_stream.log\"\nOUT=\"$HOME/path/to/output.html\"\nSTATUS=\"$RUN_DIR/status.txt\"\n\npython3 collect_context.py \"$SRC\" \"$CTX\" 2>&1 | tee -a \"$STATUS\"\n{\n  /bin/cat prompt_base.txt\n  printf '\\n\\n# Source-derived context\\n\\n'\n  /bin/cat \"$CTX\"\n} > \"$PROMPT\"\n\nROUTER_EXIT=0\n(\n  export ROUTER_TASK=\"$(/bin/cat \"$PROMPT\")\"\n  /opt/homebrew/Caskroom/miniforge/base/bin/python \\\n    \"$HOME/.openclaw/skills/super-router/scripts/router.py\" --stream\n) 2>&1 | tee \"$LOG\" || ROUTER_EXIT=${PIPESTATUS[0]}\n\npython3 generate_artifact.py \"$SRC\" \"$CTX\" \"$LOG\" \"$OUT\" 2>&1 | tee -a \"$STATUS\"\nBYTES=$(wc -c < \"$OUT\" | tr -d ' ')\nSECTIONS=$(grep -Eo '<section id=\"[^\"]+\"' \"$OUT\" | wc -l | tr -d ' ')\nprintf '[verify] html=%s bytes=%s sections=%s router_exit=%s\\n' \\\n  \"$OUT\" \"$BYTES\" \"$SECTIONS\" \"$ROUTER_EXIT\" | tee -a \"$STATUS\"\n```\n\n## Why this matters\n\nBackground router jobs otherwise become opaque: the user sees only that a process was launched, while the prompt, source evidence, partial provider output, and artifact verification may be scattered or lost. A wrapper turns the job into a reproducible run directory and makes blocked launches safe to report without pretending work is still running.\n\nFile v0.1.4:references/gemini-cli-ripgrep-path-fix.md\n\n# Gemini CLI ripgrep Detection Fix\n\n## Problem\nDuring super-router runs, the Gemini CLI repeatedly logs:\n> \"Ripgrep is not available. Falling back to GrepTool\"\n\nThis occurs even when ripgrep is correctly installed at `/opt/homebrew/bin/rg` and PATH is set in `~/.openclaw/.env`.\n\n## Root Cause\nThe Gemini CLI binary performs its own internal tool discovery for commands like `rg`. When invoked via `subprocess.run`, these child processes do not always inherit the environment variables (including PATH) that the router sets from `~/.openclaw/.env`.\n\n## Solution\nForce-prepend the required tool paths directly inside `invoke_gemini_cli()` before every subprocess call.\n\n### Patch Applied\n```python\n# Force inject ripgrep + common tool paths\nextra_paths = [\"/opt/homebrew/bin\", \"/usr/local/bin\"]\ncurrent_path = env.get(\"PATH\", \"\")\npath_parts = [p for p in extra_paths if p not in current_path.split(\":\")]\nif path_parts:\n    env[\"PATH\"] = \":\".join(path_parts + [current_path]) if current_path else \":\".join(path_parts)\n```\n\nThis replaces the previous conditional injection and ensures `rg` is always visible to Gemini's internal tools.\n\n## Verification\nAfter applying the patch, run any complex task through the router and confirm the \"Ripgrep is not available\" message no longer appears in the Gemini CLI stderr.\n\nFile v0.1.4:references/gemini-cli-token-recovery.md\n\n# Recovering Gemini CLI token usage when super-router ledger is unavailable\n\nUse this when any super-router process stops before the final token ledger is printed, but one or more underlying Gemini CLI calls completed. This includes planning-capture harness termination, manual kill, timeout, crash, interrupted executor fanout, metadata extraction failure, or finalizer failure. The recovery is phase-agnostic: recover every completed Gemini CLI call in the router process time window, then attribute calls to phases where possible.\n\n## Symptom\n\nA super-router run stops before emitting its normal token ledger / `Token Usage Summary`, for example:\n\n- planning-capture harness terminates after the streamed plan\n- user/manual kill\n- timeout\n- process crash\n- executor fanout interruption\n- metadata extractor/finalizer failure\n- any other incomplete router run\n\nThe router artifact may show token fields as `null` / unavailable, often with:\n\n```json\n\"usage_source\": \"unavailable: router terminated after streamed plan before final token ledger\"\n```\n\nThe router log may also contain no `Token Usage Summary` lines.\n\n## Recovery source\n\nGemini CLI persists session JSONL files under:\n\n```text\n~/.gemini/tmp/<user>/chats/session-*.jsonl\n```\n\nFor a run, filter by the router capture time window. Each relevant JSONL often contains a `tokens` object like:\n\n```json\n\"tokens\": {\n  \"input\": 16338,\n  \"output\": 306,\n  \"cached\": 0,\n  \"thoughts\": 3348,\n  \"tool\": 0,\n  \"total\": 19992\n},\n\"model\": \"gemini-3-flash-preview\"\n```\n\n## Procedure\n\n1. Determine the router process start/stop window from available evidence: wrapper JSON, terminal/process timestamps, router logs, output artifact mtimes, or shell history.\n2. Normalize the time window carefully. Gemini CLI `session-*.jsonl` filenames may align with UTC-like timestamps while terminal `date` output or user-facing run logs may be local time. If an initial local-time search finds zero token records, retry using the UTC timestamp from the run artifact.\n3. Read router artifacts for phase/model context: planner, judge, pro, flash, metadata extractor, and finalizer models when available.\n4. List Gemini CLI session files around that time:\n\n```bash\nls -lt ~/.gemini/tmp/$USER/chats/session-YYYY-MM-DDTHH-*.jsonl\n```\n\n4. Parse candidate files and extract nested objects containing `tokens.total`, `model`, and timestamps/snippets if present.\n5. Deduplicate by `(file, model, token-object)`.\n6. Attribute records whose timestamps overlap the router run window and whose models/prompts/snippets match expected router phases.\n7. Sum `input`, `output`, `cached`, `thoughts`, `tool`, and `total`; optionally group by model and inferred phase.\n8. Patch telemetry as recovered provider telemetry, not an estimate. If phase attribution is uncertain, label it `super_router_recovered_unattributed` rather than guessing.\n\n## Python snippet\n\n```python\nimport json, pathlib\nchatdir = pathlib.Path('~/.gemini/tmp').expanduser() / pathlib.Path.home().name / 'chats'\nfiles = sorted(chatdir.glob('session-YYYY-MM-DDTHH-*.jsonl'))\nrecords = []\nfor p in files:\n    for line in p.read_text(errors='ignore').splitlines():\n        try:\n            obj = json.loads(line)\n        except Exception:\n            continue\n        def visit(x):\n            if isinstance(x, dict):\n                if isinstance(x.get('tokens'), dict) and 'total' in x['tokens']:\n                    records.append({'file': p.name, 'model': x.get('model'), 'tokens': x['tokens']})\n                for v in x.values():\n                    visit(v)\n            elif isinstance(x, list):\n                for v in x:\n                    visit(v)\n        visit(obj)\nseen, uniq = set(), []\nfor r in records:\n    key = (r['file'], r.get('model'), json.dumps(r['tokens'], sort_keys=True))\n    if key not in seen:\n        seen.add(key)\n        uniq.append(r)\nsums = {k: sum(int(r['tokens'].get(k, 0) or 0) for r in uniq)\n        for k in ['input', 'output', 'cached', 'thoughts', 'tool', 'total']}\nprint(sums)\n```\n\n## Interpretation\n\n- `input`: prompt/context \n\nArchive v0.1.3: 16 files, 99490 bytes\n\nFiles: README.md (29883b), references/background-artifact-launches.md (2893b), references/gemini-cli-ripgrep-path-fix.md (1311b), references/gemini-cli-token-recovery.md (4675b), references/gemini-temperature-gap.md (1907b), references/linux-mm-source-html-example.md (4187b), references/long-running-quantitative-tasks.md (1508b), references/source-html-background-wrapper.md (4327b), scripts/render_super_router_diagram.py (21961b), scripts/router.py (215311b), skill-card.md (3359b), SKILL.md (22961b), templates/source-html-background-wrapper.sh (3244b), tests/__init__.py (1b), tests/test_router.py (60203b), _meta.json (131b)\n\nArchive v0.1.2: 7 files, 50228 bytes\n\nFiles: README.md (25237b), scripts/router.py (122250b), skill-card.md (2356b), SKILL.md (15685b), tests/__init__.py (1b), tests/test_router.py (19631b), _meta.json (131b)\n\nArchive v0.1.1: 6 files, 47667 bytes\n\nFiles: README.md (24675b), scripts/router.py (112679b), SKILL.md (15723b), tests/__init__.py (1b), tests/test_router.py (18899b), _meta.json (131b)\n\nArchive v0.1.0: 6 files, 45870 bytes\n\nFiles: README.md (24047b), scripts/router.py (110271b), SKILL.md (14954b), tests/__init__.py (1b), tests/test_router.py (17043b), _meta.json (131b)","readmeExcerpt":"Skill: Super Router Owner: fanyadan Summary: LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalat... Tags: latest:0.1.5, openclaw:0.1.5 Version history: v0.1.5 | 2026-06-30T07:36:35.571Z | user Document dependency DAG handling and runtime dependencies in SKILL.md. v0.1.4 | 2026-06-30T06:29:44.925Z | user Improve t","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"# Required: LangGraph\npip install langgraph\n\n# Optional: LangSmith telemetry\npip install langsmith\n\n# Optional: architecture diagram regeneration\npip install pillow"},{"language":"bash","snippet":"ROUTER_MODEL=gpt-5.5\n# Equivalent explicit form:\n# ROUTER_MODEL=codex/gpt-5.5"},{"language":"python","snippet":"exec(\n    command=\"/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py 'Analyze K8s YAML errors and rewrite config'\"\n)"},{"language":"python","snippet":"exec(command=\"/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py --stream 'Your complex task'\")"},{"language":"python","snippet":"exec(\n    command=\"/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py\",\n    env={\"ROUTER_TASK\": \"Your complex task description\"},\n)"},{"language":"python","snippet":"# Continue polling with process tool\nprocess(action=\"poll\", session_id=\"<session_id_from_exec>\")\n\n# Wait for completion\nprocess(action=\"wait\", session_id=\"<session_id_from_exec>\", timeout=300)"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: super-router\ndescription: \"LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalates failures, and records token usage for auditable runs.\"\nversion: 1.0.0\nauthor: Yadan Fan\nlicense: MIT\nmetadata:\n  openclaw:\n    tags: [model-routing, langgraph, task-decomposition, multi-model, complexity-scoring]\n    requires:\n      bins: [python]\n  related_skills: [btc_analyzer, api-tester, ddg-search]\n---\n\n# Super Router (LangGraph Edition)\n\nSuper Router decomposes complex work into dependency-aware subtasks, scores each branch for complexity and risk, and executes it on the right model role. It combines PRO/FLASH routing, provider fallback, FLASH retry and escalation, metadata extraction, LangSmith tracing, and token usage accounting into one auditable LangGraph workflow.\n\n## Mandatory OpenClaw Invocation\n\nFor any request to use `super-router`, `super_router`, or `走 super-router`, do this exact workflow:\n\n1. Use the OpenClaw `exec` tool to run:\n   `/opt/homebrew/Caskroom/miniforge/base/bin/python /Users/fanyadan/.openclaw/skills/super-router/scripts/router.py '<task>'`\n2. If `exec` returns `Command still running`, call the OpenClaw `process` tool with `action=\"poll\"` on the returned `sessionId` until the process exits.\n3. The next assistant message after completion must start with `Router result:` or `Router failed:` and must include a concrete detail from the router output.\n\nDo not run `openclaw super_router`, `openclaw super-router`, `openclaw skill`, `openclaw skills`, or a nested `openclaw agent` command to satisfy this skill. Those are not the router.\n\n## When to Use This Skill\n\nUse super-router when you need:\n- **Intelligent model routing** — automatically choose between heavy (PRO) and fast (FLASH) models per subtask\n- **Task decomposition** — break complex tasks into structured subtasks with independent routing\n- **Cost optimization** — use fast models for simple work, heavy models only when needed\n- **Configurable models** — use deterministic defaults, with environment-variable overrides for each role\n- **Failure escalation** — FLASH retry on infra failures, escalate to PRO on capability failures\n- **Audit trail** — full logging of planned vs actual routes, retries, and failure classifications\n\n**Not needed for:** Simple single-turn tasks, tasks where you already know which model to use, or when you want manual control over every routing decision.\n\n## Optimization for Parallelism\n\nTo achieve true parallel execution (when `ROUTER_MAX_CONCURRENCY > 1`), the Planner must be instructed to use **Atomic Decomposition**. \n\n- **Atomic Decomposition**: Breaking a task into the smallest possible independent units rather than grouped phases.\n- **Pitfall: Planner Grouping**: The Planner may occasionally group multiple entities into a single subtask, which kills true parallelism.\n- **Verification**: Always verify the `planned_subtasks` count matches the "},{"path":"README.md","content":"# Super Router\n\nSuper Router is a LangGraph-based task router that decomposes a user request,\njudges each subtask, and executes ready subtasks across PRO and FLASH model\nroles. It is built for workloads where some branches need stronger reasoning\nwhile others are simple reporting, formatting, or low-risk IO.\n\nThe current implementation supports planner and dependency fallback paths,\ndependency-aware executor fanout, provider fallback lists, FLASH retry and\nFLASH-to-PRO escalation, embedded technical metadata extraction, LangSmith\ntracing, and token usage accounting.\n\n## Workflow\n\n![Super-Router LangGraph Architecture](super-router.png)\n\n## What It Does\n\n- Compacts long task text into deterministic context manifests before planning,\n  judging, executing, metadata extraction, and finalization.\n- Plans atomic subtasks with stable IDs and optional `depends_on` edges.\n- Verifies and corrects the dependency DAG before execution.\n- Scores each subtask on reasoning depth, code-change scope, ambiguity, risk,\n  and IO heaviness.\n- Routes subtasks to `PRO` or `FLASH` using model scores plus deterministic\n  risk, summary, and confidence guards.\n- Schedules only dependency-ready subtasks, fans them out with LangGraph\n  `Send(...)`, joins completed waves, and repeats until the DAG is complete.\n- Executes model calls through Codex CLI, Gemini CLI, Claude Code CLI, or\n  Ollama, selected by model name.\n- Retries FLASH on transient infrastructure failures and escalates to PRO on\n  quality or capability failures.\n- Extracts compact \"technical gold\" metadata from successful executor outputs\n  inside each executor branch.\n- Produces the final report through a FLASH finalizer, then a PRO finalizer,\n  then a deterministic fallback report if model finalization fails.\n- Tracks provider token usage per run, prints an aggregate summary, and can\n  persist append-only JSONL records.\n\n## Repository Layout\n\n```text\n.\n|-- README.md\n|-- SKILL.md\n|-- super-router.png\n|-- references/\n|-- scripts/\n|   |-- render_super_router_diagram.py\n|   `-- router.py\n|-- templates/\n`-- tests/\n    |-- __init__.py\n    `-- test_router.py\n```\n\n| Path | Purpose |\n| --- | --- |\n| `SKILL.md` | OpenClaw skill contract, usage notes, architecture summary, and environment reference. |\n| `scripts/router.py` | Main LangGraph router, provider dispatch, fallback logic, telemetry, token accounting, and CLI. |\n| `scripts/render_super_router_diagram.py` | Deterministic diagram renderer; verifies the diagram node set against `build_router_graph()`. |\n| `super-router.png` | Current architecture diagram used by this README. |\n| `tests/test_router.py` | Offline regression tests using `unittest` and mocks. |\n| `references/` | Supplemental operational notes. |\n| `templates/` | Shell helper templates. |\n\n## Requirements\n\n- Python 3.10+.\n- `langgraph` for the runtime graph.\n- `langsmith` only when optional telemetry is enabled.\n- `Pillow` only when regenerating `super-router.png`.\n- At least one usable model provider:\n  "},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn71hy12wp4z8b19wb103v938d81yez7\",\n  \"slug\": \"super-router\",\n  \"version\": \"0.1.5\",\n  \"publishedAt\": 1782804995571\n}"},{"path":"references/background-artifact-launches.md","content":"# Background Router Artifact Launches\n\nUse this pattern when a user asks to run super-router in background mode and produce a durable artifact such as an HTML report.\n\n## Pattern\n\n1. Build small, auditable support files before launching:\n   - a source/context collection script, if the task depends on local code or data;\n   - a router prompt file for complex/multiline task text;\n   - a wrapper script that records `run_dir`, status, router stream log, final artifact path, and verification results.\n2. Launch the wrapper with `exec(background=true, notify_on_complete=true)`.\n3. If the launch succeeds, immediately poll once to verify the process is actually running or completed with useful output.\n4. The wrapper should tee router stdout/stderr to a log and preserve the exact prompt/context used for the run.\n5. For artifact-producing jobs, generate or finalize the artifact only from real collected context and router output. If router/provider execution fails, the artifact may still be created only if it truthfully records the failure/log tail and uses verified local context; never hide a failed router run behind a polished report.\n6. Verify the final artifact directly before claiming success, e.g. `wc -c`, section/card counts, and any required source-derived sections.\n7. If the command guard blocks the launch, do not retry, rephrase, or work around it. Report the prepared files and the exact blocked launch scope, then wait for user approval.\n\n## Wrapper skeleton\n\n```bash\n#!/usr/bin/env bash\nset -u\nSRC=\"$HOME/path/to/source\"\nRUN_DIR=\"$HOME/.openclaw/logs/task_$(date +%Y%m%d_%H%M%S)\"\nmkdir -p \"$RUN_DIR\"\nCTX=\"$RUN_DIR/source_context.md\"\nPROMPT=\"$RUN_DIR/router_prompt.txt\"\nLOG=\"$RUN_DIR/super_router_stream.log\"\nOUT=\"$HOME/path/to/output.html\"\nSTATUS=\"$RUN_DIR/status.txt\"\n\npython3 collect_context.py \"$SRC\" \"$CTX\" 2>&1 | tee -a \"$STATUS\"\n{\n  /bin/cat prompt_base.txt\n  printf '\\n\\n# Source-derived context\\n\\n'\n  /bin/cat \"$CTX\"\n} > \"$PROMPT\"\n\nROUTER_EXIT=0\n(\n  export ROUTER_TASK=\"$(/bin/cat \"$PROMPT\")\"\n  /opt/homebrew/Caskroom/miniforge/base/bin/python \\\n    \"$HOME/.openclaw/skills/super-router/scripts/router.py\" --stream\n) 2>&1 | tee \"$LOG\" || ROUTER_EXIT=${PIPESTATUS[0]}\n\npython3 generate_artifact.py \"$SRC\" \"$CTX\" \"$LOG\" \"$OUT\" 2>&1 | tee -a \"$STATUS\"\nBYTES=$(wc -c < \"$OUT\" | tr -d ' ')\nSECTIONS=$(grep -Eo '<section id=\"[^\"]+\"' \"$OUT\" | wc -l | tr -d ' ')\nprintf '[verify] html=%s bytes=%s sections=%s router_exit=%s\\n' \\\n  \"$OUT\" \"$BYTES\" \"$SECTIONS\" \"$ROUTER_EXIT\" | tee -a \"$STATUS\"\n```\n\n## Why this matters\n\nBackground router jobs otherwise become opaque: the user sees only that a process was launched, while the prompt, source evidence, partial provider output, and artifact verification may be scattered or lost. A wrapper turns the job into a reproducible run directory and makes blocked launches safe to report without pretending work is still running."},{"path":"references/gemini-cli-ripgrep-path-fix.md","content":"# Gemini CLI ripgrep Detection Fix\n\n## Problem\nDuring super-router runs, the Gemini CLI repeatedly logs:\n> \"Ripgrep is not available. Falling back to GrepTool\"\n\nThis occurs even when ripgrep is correctly installed at `/opt/homebrew/bin/rg` and PATH is set in `~/.openclaw/.env`.\n\n## Root Cause\nThe Gemini CLI binary performs its own internal tool discovery for commands like `rg`. When invoked via `subprocess.run`, these child processes do not always inherit the environment variables (including PATH) that the router sets from `~/.openclaw/.env`.\n\n## Solution\nForce-prepend the required tool paths directly inside `invoke_gemini_cli()` before every subprocess call.\n\n### Patch Applied\n```python\n# Force inject ripgrep + common tool paths\nextra_paths = [\"/opt/homebrew/bin\", \"/usr/local/bin\"]\ncurrent_path = env.get(\"PATH\", \"\")\npath_parts = [p for p in extra_paths if p not in current_path.split(\":\")]\nif path_parts:\n    env[\"PATH\"] = \":\".join(path_parts + [current_path]) if current_path else \":\".join(path_parts)\n```\n\nThis replaces the previous conditional injection and ensures `rg` is always visible to Gemini's internal tools.\n\n## Verification\nAfter applying the patch, run any complex task through the router and confirm the \"Ripgrep is not available\" message no longer appears in the Gemini CLI stderr."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalat... Skill: Super Router Owner: fanyadan Summary: LangGraph task router for OpenClaw that decomposes complex work into dependency-aware subtasks, routes each branch to PRO or FLASH models, retries or escalat... Tags: latest:0.1.5, openclaw:0.1.5 Version history: v0.1.5 | 2026-06-30T07:36:35.571Z | user Document dependency DAG handling and runtime dependencies in SKILL.md. v0.1.4 | 2026-06-30T06:29:44.925Z | user Improve t","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1646,"uniquenessScore":48,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-12T01:15:28.405Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-12T01:15:28.405Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-12T04:04:12.306Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}