Trust

How Krawl handles citation, verification, failure modes, refunds, and audit — the methodology page an autonomous agent's owner should read before wiring Krawl into a production pipeline.

Krawl is a deep-research API. The result is a cited markdown report. This page describes how we get there, where the failure modes live, and what we do when something goes wrong.

If a claim below contradicts what the engine actually does, treat the code as the source of truth and open a docs issue.

Methodology

What "deep research" means here

A deep run executes a recursive breadth × depth tree search:

  1. Plan (Sonnet 4.6). A structured research plan with topics and tasks.
  2. STORM perspectives (Haiku 4.5). 3–5 perspectives with key questions so the search tree explores multiple angles. Skipped for very short queries.
  3. Recursive tree (Haiku 4.5 for queries; Sonnet 4.6 for extraction and gap analysis). Generate N queries per depth level, execute in parallel across the enabled tools, extract structured learnings, deduplicate (Jaccard ≥ 0.7), detect gaps, recurse with depth - 1, breadth / 2.
  4. Verified synthesis (Opus 4.7, exactly one synthesis call). Built on a retrieve-then-cite block — source metadata distinguishes original text, excerpts, provider summaries and links without inspected content. A collected URL alone does not verify a claim.
  5. Gap check + review/revise (Sonnet 4.6 / Opus 4.7). The draft is scored 0–1 by an independent review pass; if < 0.8, one or two revision passes run. Hard cap: two revisions.

Full pipeline detail: Architecture.

What "cited" means

Every numeric [n] in the report is a citation pointer into the source list. The synthesis prompt enforces two rules that the engine then verifies:

  • Source-bounded: the model is given a <sources> block and may cite only those sources. A [n] outside the block is rejected and the chunk is re-asked.
  • Verified against text: each [n] is verified against the fetched source content. The verification stream emits a citation_verified event (verified: true|false) per citation; unverified citations trigger a re-pass.

A real source counter shows up in the result event under sources_used; if you see fewer sources used than were fetched, that's normal — only sources the model actually cited are surfaced.

What we don't claim

  • We do not claim every fact in the report is true. We claim each cited fact came from a source we retrieved on the call and was verified against that source's text. The source itself can still be wrong.
  • We do not pin a freshness guarantee on a deep run. The engine uses live search providers (Exa, Firecrawl, X, GitHub, CoinGecko, DeFi Llama, Semantic Scholar, PubMed, Reddit, HN, Wikipedia, Tavily, Serper, Brave, DuckDuckGo), but provider freshness varies. Where it matters, cross-check against the source link.
  • We do not guarantee determinism. Same query twice can land on different sources, and Opus's synthesis is sampled. If you need reproducibility, set seed (where supported) and pin the source list via output_schema.

Failure modes (named)

Knowing what can go wrong is half of trust. Krawl emits these as structured failure types — agents can branch on them.

FailureWhere it surfacesWhat it meansWhat to do
provider_4xxper-tool, in auditOne search provider rate-limited or refusedEngine retries on a different provider; report often still ships
provider_5xxper-tool, in auditProvider outageEngine fails over (Bedrock → Anthropic → cross-provider)
circuit_openerror eventBedrock circuit breaker tripped (3 fails)Anthropic direct fallback engages for 5 min
cost_ceiling_hitusage event (ceiling_hit: true)Per-request cost ceiling reached mid-synthesisReport finalises with whatever's gathered so far
gap_unresolvedgap_detected w/o subsequent node_completedA gap couldn't be filled before recursion exhaustedReport ships marked with gaps_unresolved > 0
citation_unverifiedcitation_verified: falseA [n] failed verification against source textEngine re-asks the surrounding chunk; if persistent, citation is stripped
review_below_thresholdreview_pass score < 0.8 after pass 2Two revisions still didn't clear the barReport ships with the best draft + a quality_flag
429_rate_limitedtop-level 429Caller hit the per-IP / per-key rate limitHonor Retry-After and back off (see Rate Limits)
402_payment_requiredtop-level 402x402 challengeSign + retry with X-PAYMENT (see x402)

The full audit trail of any specific run is at GET /audit/{result_id}.

Refund policy

x402 payments are pay-per-use and non-refundable once settlement succeeds. This is stated on the 402 challenge itself (description: "… (pay-per-use, non-refundable)") so an agent can decide before signing.

Two specific exceptions:

  • Pre-settlement 503. If the server is at capacity, the 402 response carries an empty accepts array and is rejected before the facilitator's /settle runs. No funds move.
  • Post-settlement engine failure. If a paid request settles and then the engine fails with a 5xx (not a 4xx your client caused), we'll credit the request manually on review — open a ticket with the transaction hash from X-PAYMENT-RESPONSE. We don't promise SLA-grade automation here; it's a goodwill credit.

API-key requests follow the plan's terms — see Authentication for plan-scoped quotas and overage behavior.

Audit and verification surfaces

Two product surfaces let an agent or operator verify a specific run:

  • Per-result audit log: GET /audit/{result_id} returns every search, browse, extraction, and synthesis step for the run — what got called, with what argument, what came back.
  • Citation verification events: the SSE stream emits citation_verified for every [n] in the report, with the source URL and the supporting excerpt. See SSE Events → citation_verified.

For benchmark transparency — public scores on third-party benches and the methodology behind the Krawl Crypto Research Bench — see Benchmarks.

Security and data handling

  • Auth: X-API-Key is HMAC-compared. Demo keys expire and are metered separately.
  • Headers: HSTS (2y, includeSubDomains), X-Frame-Options: DENY, X-Content-Type-Options: nosniff.
  • Body limits: 1 MB normal, 50 MB on /research/upload.
  • SSRF: webhook URLs are validated against an allowlist.
  • Document upload: uploaded files are processed in-memory and discarded after the run completes; we do not train on user content.
  • Logging: full request/response is sampled for ops and is purged on a 30-day rolling window. No prompts or reports are shared with third parties.

Reporting an incident

If you see a verified-true citation that misrepresents the source it points to — or any other behavior that breaks the contract above — open an issue at github.com/ravidsrk/krawl/issues or email team@krawl.sh. Include the result_id and the offending [n]; we'll attach the audit trail.

Evidence time and access

Research sources carry optional retrieved_at (UTC), published_date, updated_date, date provenance, access_status, source_record_id and temporal_status. Missing fields on older reports mean unknown; never assign export time as retrieval time. Access states are inspected_text, partial_excerpt, provider_summary, metadata_only, fetch_failed, or unknown. These describe available evidence, not claim support or truth. A recent fetch does not make an old article current. Summary/metadata-only results do not establish that the original text was read.

Optional source_policy.as_of sets a UTC evidence cutoff; dates after it are quarantined in quarantined_sources, outside synthesis. Without it the cutoff is research start. This is not a historical web archive; undated content remains uncertain. See evidence methodology.

Publication/update dates are provider assertions. Exa, Tavily, Serper, Brave, DuckDuckGo and TinyFish search results are labelled excerpts. Exa/Firecrawl extractions and capped HTTP pages remain excerpts. The X search overview is a provider summary; empty linked posts are metadata-only. Native X post bodies that fit in the content limit are inspected text. Academic abstracts are excerpts; Semantic Scholar year-only dates keep year precision. arXiv Atom published and updated are kept separately. GitHub repository updated_at is an update, not a publication date. Multi-provider crypto summaries do not establish that the linked page was inspected. Missing provenance stays unknown.

HTML, PDF, DOCX, slides, Markdown and JSON exports include source observation limits. Retained results store those fields under the same ownership, deletion and retention rules as the report. ZDR runs do not persist them.

CI uses a synthetic, frozen cutoff cohort (2026-10-01 UTC) with labelled old/new conflicts, false premises, missing dates and partial X access. It tests propagation and filtering, not model correctness. No live FreshQA score or improvement is claimed; a current live cohort needs separately approved budget and labels.

Evidence coverage

The optional evidence_coverage result field gives descriptive counts of unique exact URLs discovered, explicitly fetched, retained, referenced in outgoing model input, and cited. Stages overlap: a retained search snippet may never have had its original page fetched. It also reports explicit failed/unavailable fetches, unknown fetch/access states, retained-host concentration, missing publication dates and their known range. A model-input reference may contain only metadata or a short excerpt; a citation is not a support verdict.

These counts do not establish representative sampling or correct selection bias. Hostnames do not prove independent origins; mirrors may share a publisher. Old reports without this field have unknown coverage. No extra LLM call is made; the measured instrumentation overhead is reported as measurement_overhead_ms, not a guarantee of zero added latency. See evidence methodology.

Corroboration observations

Learning records may include corroboration text-reuse observations. Exact and near copies form candidate origin groups; these are not proven publishers or independent sources. Overlapping words can contradict one another. Both claim_support and independent_origins remain unassessed, and this heuristic does not increase confidence or reject a unique primary record. Comparison is bounded to 256 sources and 12,000 characters/1,000 tokens per source; a truncation flag exposes incomplete comparison. These observations are not a poison detector.

These checks detect possible text reuse only. Factual poisoning and instruction attacks require separate evaluation. The live paired cohort remains pending.

On this page