Operator attribution and digital evidence, specialised in the digital-advertising ecosystem
kwara demonstrates solid definition quality with 24 well-named tools following verb_noun conventions (list_cases, create_case, capture_snapshots). All tools have descriptions ranging 50 - 400+ chars, exceeding the 10-char minimum. Input schemas are present and typed for all tools. However, output schemas are entirely undocumented, no tool declares what fields it returns, forcing LLMs to infer structure. Parameter descriptions are present but often terse (e.g., 'case ID' vs. 'case ID (integer, required for all case operations)'). Error handling guidance is absent; tools do not explain recovery paths. Security is well-considered (no secrets in params, read-only vs. write risk labels), but composition could be tighter, some tools like snapshot_detail and url_detail overlap in scope.
Fetch and parse ads.txt from a domain.
Capture full evidence for pending URLs: screenshot, HTML, and HAR. Slow (Playwright, roughly a minute per URL) and it visits live sites, so `limit` is required and defaults to 5. Call it repeatedly to work through a backlog rather than asking for a large batch in one go. Uses the case's victim locale automatically.
Case detail plus progress counts: URLs, scanned, unscanned, pending snapshots.
Check if a domain serves different content by User-Agent (cloaking).
Operator groups and the shared signals linking domains together. Groups are formed from hard signals — the same tracking ID, TLS certificate, or ads.txt account across domains. Weak links are reported separately and should not be presented as evidence of a shared operator.
Open a new case. `locale_preset` (tw/us/uk/jp/kr/de) sets the browser locale and timezone used for screenshots, so captures show what a victim in that region actually saw rather than what the analyst's machine renders. Set it when the victim's region is known — geo-cloaked pages serve different content per region and getting this wrong makes the evidence misleading.
Output schemas completely undocumented. No tool declares what fields it returns (e.g., does list_cases return [case_id, title, url_count] or a richer structure?). LLMs cannot plan downstream tool calls or extract the right data without knowing response structure.
Error handling guidance absent. Tools do not explain what to do on failure (e.g., if capture_snapshots times out, should the agent retry with a smaller limit? Call a different tool?). No recovery paths or error categorization.
Parameter descriptions are terse. Many params lack format/range guidance (e.g., 'case ID' vs. 'case ID (integer, 1 - 999999, required for all case operations)'; 'limit' vs. 'limit (1 - 25, required to prevent unbounded crawls)'). LLMs cannot validate inputs without explicit constraints.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | 2026-07-28+ | v2 |
Characterise a domain list without writing into a case.
DNS records for a domain.
Export a case as a self-contained evidence pack: a ZIP with every snapshot, HTML, HAR, and metadata needed to review the case offline or hand to a third party.
Index a case into the cross-case signal index.
Search the cross-case signal index for a value.
Add suspicious URLs to a case. Pass `message` instead of `urls` to ingest a whole post body — URLs are extracted from it, and the original text is retained as provenance.
Rule-based case summary: headline, findings, risk flags, and evidence gaps.
List every investigation case with its URL and scan counts.
Full details of an operator: domains, signals, and cross-case recurrence.
Dry-run: report recovered captures that could be written into the database.
Signals that appear across multiple cases in the index.
Domains and the operators linking them, as a directed graph.
Cheap attribution pass over every un-scanned URL in the case. Follows redirect chains, fetches static HTML for embedded tracking IDs, pulls ads.txt, and enriches WHOIS/ASN — no browser, so it takes seconds per URL rather than minutes. This is the right first step: it populates the operator-clustering signals so groups and the relationship graph appear without the heavy capture step. Caveat worth passing on to the user: only STATIC, HTML-embedded tracking IDs are visible here. IDs injected by JavaScript (e.g. GA4 loaded through GTM) need capture_snapshots. Finding few or zero groups after this does NOT prove the domains are unrelated.
Fetch and analyse a batch of candidate domains. `limit` is required and defaults to 5 to prevent an agent from screening thousands of sites unattended. Call it repeatedly to work through a list.
Full details of a captured snapshot: screenshot, HTML, HAR, and metadata.
TLS certificate chain for a domain.
Full details of a URL in a case: all scan runs, snapshots, and signals.
WHOIS and ASN data for a domain.
Overlapping tool scope. snapshot_detail, url_detail, and operator_detail all return 'full details' of related entities. LLMs may conflate them or call multiple when one suffices. Composition could be tighter.
No pagination or result-limiting guidance in read-heavy tools. list_cases, clusters, relationship_graph do not document max result counts or pagination support. Large case datasets could blow context windows.