Router candidates triage
Operator walkthrough for /dashboard/router-candidates — frontend-only triage UI for the LLM-classified rail-candidates report. Filter, claim, defer, reject, export.
Router candidates triage
The /dashboard/router-candidates page is the operator's triage surface for new rails to add to the meta-tool router. It consumes the markdown report produced by the offline classifier (scripts/classify-meta-tool-candidates.ts) and lets you mark each candidate as claimed, deferred, or rejected — then export the claimed subset as JSON for hand-curation.
The page is fully frontend-only. Nothing the operator drops on the page leaves the browser; there is no server round-trip and no telemetry. This matters because the classifier output may include unredacted tool descriptions and fragments of the catalog that should not flow through the standard logging path.
Use this page after running classify-meta-tool-candidates.ts against the live mcp_tools catalog. Without a fresh markdown report, the page renders an empty triage state and a link back to the script docs.
Generating the report
The classifier is a one-shot operator script. It walks the entire mcp_tools catalog (~2,200 rows in production), and for each tool asks Claude Haiku whether the tool is a routing candidate for one of the 9 meta-tools — and at what confidence.
# from codespar-enterprise
npm run classify:meta-tool-candidates -- \
--output scripts/meta-tool-candidates.mdThe output file at scripts/meta-tool-candidates.md is gitignored. A full run against the 2,200-row catalog costs roughly $0.50 in Anthropic API spend and takes 15–30 minutes wall-clock. Re-run when the catalog grows materially or when you add a new meta-tool that needs back-fill.
Triaging
Drop the markdown file onto the page (or use the file picker). The browser parses it via parse-candidates.ts and renders one row per candidate with these controls:
- Filter by meta-tool. Limit the view to candidates for a single meta-tool —
codespar_pay,codespar_charge,codespar_invoice,codespar_notify,codespar_ship,codespar_crypto_pay,codespar_kyc,codespar_discover,codespar_manage_connections. - Filter by confidence. The classifier emits a 0–1 confidence per candidate. Hide low-confidence rows when you are sweeping for obvious wins.
- Filter by vertical. One of the 9 verticals — payments, banking, crypto, communication, ecommerce, erp, fiscal, fraud, identity.
- Sort by any of the columns (meta-tool, confidence, provider, vertical).
Per row, three actions:
| Action | Meaning |
|---|---|
| Claim | You will hand-curate the to_canonical / from_canonical transforms for this candidate and add it to META_TOOL_CATALOG. |
| Defer | Plausible but not next-batch. Revisit on the next sweep. |
| Reject | Clearly wrong classification — the tool does not belong on this meta-tool. The exporter excludes rejected rows. |
State persists in localStorage keyed by the report's checksum, so a reload (or a closed-tab-by-accident) does not erase your triage progress. Drop a fresh report and the keys reset.
Exporting
The Export claimed button downloads a JSON file containing only the claimed candidates. Shape:
[
{
"meta_tool": "codespar_charge",
"provider_id": "stone",
"tool_name": "STONE_CREATE_CHARGE",
"confidence": 0.94,
"vertical": "payments",
"rationale": "Direct inbound Pix-or-card charge endpoint…"
}
]Take the JSON to catalog/<provider>.json and hand-write the to_canonical / from_canonical transforms. Add the row to META_TOOL_CATALOG once the transforms pass dry-run-meta-tools.ts --ci. The classifier suggests; you author.
Why frontend-only
The triage report is sensitive enough that round-tripping it through the backend would create a meaningful logging surface. Frontend-only avoids that:
- No request is made to
api.codespar.devwith the report contents. - No analytics event captures the rows.
- The exporter writes to the user's download directory; the backend never sees the claimed list.
If the operator wants to share triage state across machines, they export the JSON and check it into a private operations repo by hand. There is no CodeSpar-hosted sync.
Next steps
Last updated on
Health rollup
Operator walkthrough for /dashboard/health — 30s polling rollup of /v1/health, /v1/meta-tools/stats, and /v1/connections with degraded/recovered alerting.
Async settlement
Why charges settle asynchronously — and the correlation chain (idempotency_key ↔ external_reference ↔ tool_call_id) that lets you poll or stream until terminal.