What the honeypot toolset does, how to read its status surface, how to trigger its actions, and how to call its agent (MCP) and partner (public) verbs. The terminal-friendly mirror lives at docs/HONEYPOT_GUIDE.md. Everything below is generated from the live capability catalog and manifest, so it stays in lock-step with the real surfaces.
The honeypot is a multi-tenant capture net for hostile and agentic traffic. It verifies and persists capture events, computes a deterministic 0-100 reputation score per request fingerprint, auto-tarpits repeat offenders, clusters attackers for triage, issues canary tokens and records their echoes in the wild, and exports blocklists / CSVs / a live SSE stream / an embeddable badge for downstream consumers. It watches its own tenants via heartbeats and evaluates operator-defined alert rules. 21 capabilities ship today; the full honest reference is below and in docs/honeypot-capabilities.md.
Runtime note. The honeypot telemetry database is currently suspended in production. Every DB-backed surface degrades to a typed echoatlas-honeypot-db-unavailable.v1 503 (routes) or a yellow substrate-unavailable notice (pages) rather than crashing; the capability catalog and these docs need no database and remain available at all times.
The overview at /observatory/honeypot folds the same envelope the honeypot.status.get verb returns into three tiles. Each tile carries a traffic-light dot:
| tile | reads | indicator |
|---|---|---|
| captures (24h) | Total capture events across all tenants in the window. | green = a capture landed within the last hour; yellow = last capture is older but still inside the window; red = the newest capture predates the whole window; idle = nothing captured yet. |
| last capture | ISO-8601 UTC timestamp of the most-recent capture (or never), with its age in hours. | Shares the capture freshness indicator above. |
| tenant heartbeat | How many onboarded tenants the heartbeat job flags silent, and how many of those are unacknowledged. | green = all reporting; yellow = one or more silent but acknowledged; red = unacknowledged silence — investigate. |
If the tiles are replaced by a yellow Telemetry substrate unavailable banner, the telemetry database is suspended or unmigrated — status and recent captures resume automatically once it is restored; no telemetry is lost.
The single typed source of truth for what the toolset can do, mirrored byte-for-byte by honeypot.capabilities.list.
| key | capability | status | model |
|---|---|---|---|
| capture-ingest | Capture ingest pipeline Webhook-verified POST that persists a capture event, computes and stores the fingerprint reputation score, evaluates auto-tarpit triggers, and records ingest + replay samples. | implemented | HoneypotEvent |
| reputation-scoring | Fingerprint reputation scoring Deterministic 0-100 reputation score computed and persisted per fingerprint on every ingest, driving blocklist and tarpit decisions. | implemented | FingerprintReputation |
| fingerprint-clustering | Fingerprint clustering Groups capture events into attacker clusters keyed by request fingerprint for operator triage. | implemented | Fingerprint |
| echo-sighting | External echo sighting recording CRON_SECRET-authed recording of trap-marker echoes observed off-platform (canary tokens surfacing in the wild). | implemented | EchoSighting |
| canary-tokens | Canary token registry Issues and tracks canary tokens embedded in bait content so their later appearance can be attributed. | implemented | CanaryToken |
| live-stream | Live event stream (SSE) Backfilled server-sent-events feed of new capture events for real-time operator dashboards. | implemented | HoneypotEvent |
| landing-summary | Public landing aggregate Windowed public capture aggregate (1-720h) powering the Landing hero, with no per-request PII. | implemented | HoneypotEvent |
| content-digest | Weekly content digest ISO-week human/JSON digest summarizing capture activity for a period (content summary, not a determinism hash). | implemented | HoneypotEvent |
| capture-badge | Embeddable capture badge Embeddable SVG badge rendering the current capture count. | implemented | HoneypotEvent |
| blocklist-export | Blocklist export Plaintext blocklist export of high-risk fingerprints/IP hashes derived from reputation scores. | implemented | FingerprintReputation |
| events-export | Events CSV export CSV export surface of capture events for offline analysis. | implemented | HoneypotEvent |
| tarpit-lookup | Tarpit state lookup Internal bridge-token server-to-server lookup of active auto-tarpit state for a fingerprint/ASN. | implemented | TarpitState |
| rate-limit-policy | Per-ASN rate-limit policy Internal bridge-token lookup of the per-ASN token-bucket window/limit policy applied to callers. | implemented | RateLimitPolicy |
| verified-vendors | Verified vendor allowlist Allowlist of verified legitimate crawlers used to suppress false-positive captures. | implemented | VerifiedVendor |
| investigation | Fingerprint investigation Per-fingerprint drill-down with persisted operator investigation notes. | implemented | InvestigationNote |
| tenant-fleet | Tenant fleet registry Multi-tenant registry and fleet overview across all onboarded honeypot tenants. | implemented | Tenant |
| heartbeat-alerts | Tenant heartbeat alerting Evaluates per-tenant self-observability heartbeats and raises alerts when a tenant goes silent. | implemented | TenantHeartbeat |
| alert-rules | Alert rule evaluation Evaluates operator-defined alert rules against the capture stream and fires configured notifications. | implemented | AlertRule |
| datadog-push | Datadog metrics push Pushes capture-rate and ingest-health metrics to Datadog for external observability. | implemented | IngestSample |
| pii-retention | PII retention rotation Rotates/expires PII fields on aged capture rows per the retention policy (GDPR data-minimization). | implemented | HoneypotEvent |
| replay-comparator | Replay determinism comparator Compares recorded ingest replay envelopes to prove deterministic parity of the capture pipeline. | implemented | IngestSample |
| mcp-namespace | honeypot.* MCP namespace Read-only agent verbs (honeypot.status.get, honeypot.capabilities.list) at /api/mcp/v1/honeypot.* — scaffolded via this catalog kernel but NOT yet exposed as endpoints (Phase T.5). | stub | — |
Each operator surface below is a real page or authed action — nothing is a placeholder. The one POST rebuilds the persisted metrics on demand (never a cron — Pillar 4).
| surface | method | where |
|---|---|---|
| Investigate a fingerprint Per-fingerprint drill-down with persisted operator investigation notes. | GET | /observatory/honeypot/investigate |
| Reputation & blocklist Top-scored fingerprints over 7d driving the blocklist and tarpit decisions. | GET | /observatory/honeypot/reputation |
| Alert rules Operator-defined alert rules evaluated against the capture stream. | GET | /observatory/honeypot-alerts |
| Rebuild honeypot metrics On-demand authed action that rebuilds the persisted honeypot metrics (never a cron — Pillar 4). | POST | /api/actions/system/build-honeypot-metrics |
Read-only, agent-discoverable verbs under /api/mcp/v1/honeypot.*. Auth is session-or-bearer; each needs the scope shown.
| verb | method | path | scope |
|---|---|---|---|
| honeypot.capabilities.list | GET | /api/mcp/v1/honeypot.capabilities.list | read:dashboard |
| honeypot.status.get | GET | /api/mcp/v1/honeypot.status.get | read:dashboard |
| honeypot.events.recent | GET | /api/mcp/v1/honeypot.events.recent | read:events |
curl -sS \ -H "Authorization: Bearer $ECHOATLAS_OBSERVATORY_TOKEN" \ "$OBSERVATORY_BASE_URL/api/mcp/v1/honeypot.capabilities.list"
Export $OBSERVATORY_BASE_URL and $ECHOATLAS_OBSERVATORY_TOKEN first (the token is a session bearer or a scoped API key — never commit a real one). honeypot.events.recent also accepts ?tenant=<slug> and ?limit=1..100.
Metered partner mirrors under /api/public/v1/honeypot/*. Auth is a partner token (eatpub_*); each needs the public.read:honeypot scope. Both are content-addressed — a strong ETag over the body plus If-None-Match → 304.
| verb | method | path | scope |
|---|---|---|---|
| public.honeypot.capabilities | GET | /api/public/v1/honeypot/capabilities | public.read:honeypot |
| public.honeypot.status | GET | /api/public/v1/honeypot/status | public.read:honeypot |
curl -sS \ -H "Authorization: Bearer $ECHOATLAS_PARTNER_TOKEN" \ -H "If-None-Match: \"<etag-from-a-prior-200>\"" \ "$PUBLIC_API_BASE_URL/api/public/v1/honeypot/capabilities"
Drop the If-None-Match header on the first call; use the ETag from that 200 response on the next to get a cheap 304 when nothing changed.
The honeypot toolset is pinned by a determinism digest (schemaVersion 1) — a single sha256-hex over three registries:
Canonicalization: each registry row is projected to a tab-delimited, section-tagged line; the full line set is sorted by UTF-16 code unit; the digest is sha256 over the newline-joined lines with a trailing newline. Because it reads only const registries — no clock, DB, random, or env — it regenerates byte-identically on every platform. The kernel is src/lib/honeypot-observatory/honeypot-digest.ts and the checked-in pin lives in src/lib/honeypot-observatory/honeypot-digest.test.ts.
When a registry legitimately changes, the pin test fails. To regenerate and verify:
OBS_HONEYPOT_DIGEST_REGEN=1 \ npx vitest run src/lib/honeypot-observatory/honeypot-digest.test.ts # copy the printed digest into the PIN constant, then re-run # without the env var to confirm it matches: npx vitest run src/lib/honeypot-observatory/honeypot-digest.test.ts
See docs/HONEYPOT_GUIDE.md for the full grep-friendly walkthrough.