Borrowing it
Nothing to install: this file belongs to Iskandeur/bounce-cti. Take a copy, put it at the same path in your own repository, and replace the rules that are about this project with yours.
curl -O https://raw.githubusercontent.com/Iskandeur/bounce-cti/main/CLAUDE.mdgit clone --depth 1 https://github.com/Iskandeur/bounce-ctiWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/instructions/iskandeur/bounce-cti/claude-md)<a href="https://agentmods.dev/instructions/iskandeur/bounce-cti/claude-md"><img src="https://agentmods.dev/badge/instructions/iskandeur/bounce-cti/claude-md/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/instructions/iskandeur/bounce-cti/claude-md"><img src="https://agentmods.dev/badge/instructions/iskandeur/bounce-cti/claude-md.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.16397 | $0.16397 |
| Opus 5.5 | $0.06559 | $0.06559 |
| Sonnet 5.5 | $0.03279 | $0.03279 |
| Haiku 4.5 | $0.01640 | $0.01640 |
Grade A, and why
bounce-cti CLAUDE.md scanned grade A with 1 finding against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 8d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Makes network callslowCapability
Not a fault in itself. Listed so you know the mod talks to something, and to what.
- For API endpoints: curl them or open them in a browser to verify the response. How it starts
The opening of the file, as written. The whole thing — 916 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Bounce-CTI — Agent Guide
What this is
Autonomous CTI (Cyber Threat Intelligence) investigation platform. A user submits a seed (domain / IP / hash / URL / JARM / ASN / command_line / executable_name / email / wallet_address / username / phone / company), the backend spawns a headless claude -p agent that queries ~50 public CTI source tools via MCP (commercial scanners + abuse feeds + the OpenCTI community knowledge graph), builds an infrastructure graph in SQLite, and streams it live to a React + Cytoscape frontend over WebSocket. Investigations are scoped to PIN-authenticated users, can be shared via signed links, and can be exported as PDF or STIX 2.1.
The executable_name seed type lets the analyst paste just the basename of a malicious binary (e.g. dropper.exe) without uploading the file or knowing its hash — the agent pivots via MalwareBazaar's get_filename query to recover sample hashes and then runs the standard hash workflow on the top hits for family attribution.
The email, wallet_address, and username seed types let the analyst start from an actor signal: a registrant / phishing-contact email triggers reverse-WHOIS over Whoxy + EmailRep reputation; a cryptocurrency wallet (auto-detected for ETH 0x…, BTC bech32, BTC legacy, XMR) cross-references ransomware IOC feeds; a forum / Telegram handle is graphed as an opaque identifier and probed against the community KG. None of these require dedicated chain-tracing — the value is graph-level correlation across the existing source pool.
Project layout
backend/
main.py # FastAPI app (REST + WebSocket + static file serving)
agent_runner.py # Spawns claude -p with MCP config, multi-phase workflow
# (main → hypothesis_write → followup → report_write), pumps events
graph_store.py # SQLite schema + CRUD (investigations, nodes, edges, events,
# cache, users, sessions, shares, pivot_tasks, quota_state)
# + per-investigation counters (get_counter/bump_counter,
# backed by the cache table so they survive the per-phase
# agent respawns), list_nodes_of_type, and
# set_node_tags_exclusive (the lead lifecycle is a state
# machine, not an accumulating tag bag)
config.py # Env var loading (API keys, paths)
seeds.py # Seed registry: single source of truth for per-seed-type
# behaviour (mandatory_tools + investigation_prompt +
# add_seed_block + pivot_block + followup_extra_steps +
# KNOWN_SEED_TYPES). Replaces the five seed_type if/elif
# ladders in agent_runner (now eliminated). Multi-
# vertical foundation (Phase 1).
verticals.py # Vertical registry: the CTI/OSINT/DD abstraction.
# Also CONTEXT_POOL_KEY/MODULE + CONTEXT_POOL_PROMPT_BLOCK
# (the lead-discipline rules C1-C6, appended by
# build_system_prompt only when the pool is mounted;
# explicitly AMENDS rule R3's "do not search the web").
# Vertical{name,label,agent_name,seed_types,
# source_pool,prompt_block} + VERTICALS (cti + osint
# lens [reuses cti pool] + dd [Due Diligence/KYB, own
# dedicated pool mcp__dd__*, company seed, GLEIF v1;
# legal guardrails baked in the prompt: ownership =
# ESTIMATED not authoritative UBO/RBE, no adverse-media])
# + get_vertical/normalise (unknown → cti fallback) +
# source pool selection (SOURCE_POOL_MODULES: cti→cti_mcp,
# dd→dd_mcp, consumed by agent_runner._write_mcp_config).
# {core}+{vertical} system-prompt builder
# (agent_runner.build_system_prompt)
# swaps agent_name + appends prompt_block — iso-
# functional for CTI. Multi-vertical foundation (Phase 1).
context_pool.py # The SECOND EPISTEMIC TIER: model parametric memory +
# open-web text. Everything entering through it becomes
# a `lead` node — never a typed IOC — with source=
# parametric_memory / web:<host>, confidence clamped to
# LEAD_CONFIDENCE_CAP (0.35) SERVER-SIDE, and a
# lifecycle tag (unverified → corroborated | refuted |
# unverifiable). A lead is excluded from every
# actionable export until a PRIMARY source tool
# ratifies it (is_actionable). Also holds the
# mechanical legal guardrails (claim_type_denied: DD
# adverse-media + special-category claims refused at
# the tool boundary, not by prompt), the anti-circular
# rule (is_primary_evidence_tool — memory may not
# corroborate memory), the SSRF guard (check_fetch_url
# / check_fetch_host_address), corroboration_stats (the
# measurable hallucination thermometer), the shared
# dossier renderers (split_leads /
# leads_markdown_section) and the enablement policy
# (context_pool_enabled — default ON for osint + dd,
# OFF for cti). Pure module, no I/O; locked by
# tests/test_context_pool.py.
sources/web_context.py# Open-web source behind mcp__ctx__web_search / web_fetch.
# Search backends: Brave → Serper → keyless DuckDuckGo
# HTML fallback. Everything cached in the `cache` table
# so an eval re-run replays byte-identical content
# instead of that hour's SERP. Fetch is SSRF-guarded
# (scheme allowlist + pre-DNS host check + post-DNS
# check on every resolved address + redirect re-check)
# and byte-capped.
auth.py # PIN-based auth, sessions, admin bootstrap + impersonation
defuse_lists.py # CDN/parking/sinkhole/blackhole/dyndns noise filters
# + LE-takedown registrant markers (sinkhole_kind)
refang.py # Defang→fang IOC normalisation (evil[.]com → evil.com)
pdf_import.py # Extract IOCs from an uploaded CTI report PDF
sample_import.py # Handle uploaded malware sample (any binary or script)
# + pasted command-line / script — hashes binaries,
# extracts IOCs from scripts, builds the command_line
# context node + report_context for the agent
action_exports.py # Operational deliverables for the Actions tab:
# NB: context-pool leads and any node still tagged
# unverified/refuted/unverifiable are excluded with NO
# analyst override (unlike include_defused) — a defused
# node is real-but-noisy, an unverified one may not exist.
# render_blocklist (plain/hosts/unbound/rpz/palo_edl/
# cisco_acl/csv), render_detection (sigma/snort/
# yara), render_takedown (per-host abuse email
# bundle: To/Subject/Body + mailto link). Filters
# out defused indicators by default so accidental
# CDN / Tor / sinkhole blocks don't leak into
# production drop-lists.
mitre_mapping.py # Heuristic MITRE ATT&CK technique mapper:
# TECHNIQUES catalog (44 enterprise techniques),
# _TAG_MAP (node-tag → technique candidates with
# rationale), _IMPORT_MAP (PE-import → technique).
# map_graph(graph) returns ranked candidates with
# merged rationales / evidence node IDs / confidence
# (low/medium/high based on signal count). Exposed
# to the agent as the mitre_attack_candidates MCP
# tool — the agent validates each candidate and
# writes the final report.metadata.mitre_attack_mapping.
sample_analysis.py # Pure-Python static-analysis pass run on uploaded
# binaries: Shannon entropy (overall + per-section),
# printable string extraction (ASCII + UTF-16LE,
# ≥6/≥4 chars, deduped + ranked + capped at 500),
# IOC harvesting from those strings, PE walker
# (machine, compile_timestamp, sections w/ entropy,
# import-DLL list, imphash-lite), ELF walker
# (ei_class, machine, entry). Zero new deps; runs
# in-process so the binary never leaves the host.
# Output lands on hash_node.metadata.static_analysis
osint_export.py # Render an OSINT investigation as a Markdown identity
# dossier (subject + accounts/handles + identifiers
# [emails/phones/wallets] + connections + provenance);
# identity-centric counterpart to action_exports.
# Pure render_dossier(graph, inv); served at
# GET /api/investigations/{id}/osint_dossier
dd_export.py # Render a DD investigation as a Markdown KYB dossier
# (sanctions exposure headline + company identity +
# corporate hierarchy + officers/PSC + provenance,
# with estimated-ownership + candidate-match
# disclaimers). Pure render_kyb_dossier(graph, inv);
# served at GET /api/investigations/{id}/kyb_dossier
pdf_report.py # Render an investigation as a downloadable PDF
stix_export.py # Render an investigation as a STIX 2.1 bundle.
# Pure build_stix_bundle(nodes,edges,inv,id,tlp=) +
# DB wrapper generate_stix_bundle. Conformance-hardened:
# no SDO-only common props on SCOs (confidence/labels/
# created/created_by_ref), RFC-valid email-addr only
# (invalid WHOIS hashes → report.x_bounce_unmodelled_
# observables), TLP marking on every object (default
# AMBER), spec-validated relationship pairs (reversed
# resolves-to flipped, out-of-spec → related-to keeping
# x_bounce_relation), malicious observables promoted to
# indicator SDOs w/ STIX patterns, report_types set.
# Locked by tests/test_stix_export.py
key_pool.py # API key rotation pool: round-robin, cooldown on 429,
# per-day quota tracking, graceful degradation
source_health.py # Short-TTL dead-source cache (auth_required /
# tier_restricted / quota_exhausted / zero_balance)
# backed by the cache table so both MCP processes see
# it; auto-enqueue skips pivots needing a dead source
fixtures.py # EVAL_PROTOCOL §4.C fixture capture + OFFLINE replay of
# source responses. Hooks graph_store.cache_get/
# cache_set (every source memoises there) + dns_tools
# (the one uncached source, via through()). Capture:
# BOUNCE_FIXTURE_CAPTURE_DIR (set per investigation by
# agent_runner from BOUNCE_FIXTURE_CAPTURE=1, or from
# investigations.fixture_capture = an admin's
# "capture": true at creation). Replay:
# BOUNCE_FIXTURE_DIR, served whatever the TTL, never
# written to the DB, network refused in the MCP
# process (install_offline_guard), misses logged per
# investigation. Secrets redacted to <secret:SOURCE>
# in key AND value before any write. Bookkeeping keys
# (BOOKKEEPING_PREFIXES: counter|, source_health|, …)
# are never captured. Stdlib only; off by default
demo_snapshot.py # Static demo snapshots (roadmap J3): from_view() turns
# graph_store.share_view(inv, graph+report+timeline)
# into the JSON the static demo renders, minus agent
# session/request ids, usage, local paths, thinking
# blocks, report chats; check() refuses a secret value
# or a forbidden word (named, never printed). Used by
# GET /api/investigations/{id}/demo_snapshot (owner)
# and eval/demo_export.py. Stdlib only
pivot_arm.py # The mechanical arm pivot-1 (EVAL_PROTOCOL §4.E rule 1): a seed's
# mandatory tools run on the seed alone, NO model, results read
# as nodes through the exports' own neutralisation. Behind
# POST /api/admin/eval/pivot; eval/prospective.py `pivot` fills
# the arm, `seal --arm pivot-1=<dir>` takes it (same hour)
eval_judge.py # Prospective cases, server side (EVAL_PROTOCOL §4.E):
# fresh_iocs (ThreatFox get_iocs → candidate seeds +
# the §4.E rules each breaks) and judge v2
# (otx+abusech/2: OTX keyed + ThreatFox + URLhaus +
# MalwareBazaar, exact match, live — never the cache —
# each listing's id/date/author) + entries (a seed's
# ThreatFox entry read by id, then searched back
# wildcard and exact_match: gone vs not returned yet).
# Behind the admin routes /api/admin/eval/fresh_iocs
# and /judge (+ "entries"), which use the server's own
# keys. Stdlib only
pivot_mapping.py # Per-node-type pivot rules + fan-out caps + global
# pending-queue ceiling (MAX_PENDING_QUEUE) + cloud
# ASN list + discriminating_marker() for convergence
# + noise pre-filters (cloud_platform_domain,
# is_role_mailbox, is_hex_serial) + KNOWN_BAD_MARKERS
# (positive default-fingerprint table) + ACTOR_HANDLES
# (tag→threat_actor promotion) + KIT_HANDLES
# (tag→phishing_kit promotion) + key_source_for_op +
# register_pivots()/known_pivot_types() (cross-vertical
# extension point: OSINT/DD modules add node-type pivots
# without editing the rules monolith)
mcp_servers/
graph_mcp.py # MCP server: graph CRUD (add_node, add_edge, tag_node,
# get_graph[+stats_only], get_node, get_report, defuse)
# + autonomy engine (next_pivot[+source_state],
# mark_pivot_done, queue_status, coverage_matrix,
# requeue_missing[+promote_deferred], gaps_report,
# quota_status). add_node auto-enqueues pivots per
# pivot_mapping rules (with noise-filter suppression +
# queue-ceiling deferral), auto-tags known-bad
# defaults, and promotes known actor-handle tags to
# threat_actor nodes (+ kit-handle tags to phishing_kit
# nodes). add_edge auto-stubs missing
# endpoints (phantom_autostub).
ctx_mcp.py # MCP server: the CONTEXT POOL (mcp__ctx__*), mounted
# ALONGSIDE the vertical's source pool so its calls are
# counted/budgeted separately from BOUNCE_TOTAL_CTI_BUDGET.
# recall_prior_knowledge (NO network, no cost — forces
# the model's prior knowledge out of the report prose
# and into an auditable, falsifiable, queued-for-
# verification lead; requires verifiable_by + falsifier),
# web_search / web_fetch (cached, budgeted, SSRF-guarded,
# returned with an untrusted-content warning),
# context_budget. Budget enforced server-side via a
# persisted counter so it survives per-phase respawns.
cti_mcp.py # MCP server: ~90 async CTI source tools
# (incl. internetdb_ip — keyless/creditless IP exposure,
# shodan_host_count — free cluster size + facets (the
# credit-free replacement for shodan_search),
# shodan_api_info — plan + remaining credits + policy,
# malwarebazaar_imphash — PE imphash cluster,
# username_enumerate — Sherlock-style profile sweep,
# gravatar_email — email→public profile / accounts,
# github_profile — GitHub user identity enrichment,
# github_commit_emails — handle→author email harvest,
# wallet_enrich — crypto wallet on-chain activity,
# phone_lookup — offline phone metadata,
# website_extract — page links/emails/social profiles)
dd_mcp.py # MCP server: Due-Diligence (KYB) source pool
# (mcp__dd__*), mounted for the `dd` vertical. Tools:
# gleif_lookup (company identity + Level-2 hierarchy),
# sanctions_screen (+ sanctions_screen_batch: OFAC +
# EU FSF + UK UKSL name screen, batch = one call/graph),
# companies_house_lookup (UK profile + officers + PSC),
# edgar_lookup (SEC EDGAR US-listed issuer identity),
# recherche_entreprises_lookup (FR company + dirigeants).
# Separate pool from cti (different domain + the
# monetisation boundary). Legal guardrails: ownership =
# ESTIMATED (not UBO/RBE), no adverse-media here.
sources/ # One file per CTI source (all async, all cached):
# Existing: crtsh, rdap, whois (RFC 3912 / port-43),
# dns_tools, virustotal,
# urlscan, onyphe, shodan (free-first + credit guard;
# see "Shodan is free-first" in Key conventions),
# internetdb (Shodan InternetDB — NO key, NO credits;
# ports/CPEs/CVEs/hostnames, ~weekly, no banners),
# otx, threatfox, wayback,
# ip_api, mnemonic, abusech (URLhaus+MalwareBazaar)
# Phase 2: fingerprints (favicon mmh3 hash, title
# SHA1, tracking IDs, form actions, wallets, JS hashes)
# Phase 3: abuseipdb, certspotter, netlas, whoxy,
# zoomeye, criminalip, openphish
# Community KG: opencti (GraphQL, read-only —
# score, malware-family labels, actor/campaign
# attribution, ATT&CK + linked report titles)
# Phase 4 (2026-05-21): dnsdumpster (passive subdomain),
# hackertarget (rev-IP / host search / geoip — free),
# leakix (exposed services + leak detection),
# pulsedive (risk-scored IOC enrichment),
# phishtank (URL verdict — independent of OpenPhish),
# circl_lu (CIRCL hashlookup NSRL + vuln-lookup),
# alienvault_rep (IP reputation feed, no auth),
# censys (Platform v3, JARM + cert search),
# emailrep (registrant-email reputation),
# project_honeypot (http:BL DNS lookup),
# tor_exits (live exit-relay list — auto-defuse),
# dnstwist (local typosquat enumeration),
# takeover (subdomain-takeover heuristic)
# OSINT (Phase 2): username_enum (free, no-key
# Sherlock-style profile sweep across ~49 public
# platforms; e_code/e_string/m_string detection
# manifest adapted COPY-DATA from blackbird +
# Sherlock, MIT — see THIRD_PARTY_LICENSES; anti-bot
# platforms (Instagram/TikTok/X/LinkedIn/Facebook)
# surfaced as `deferred` behind an Apify scraping
# seam, paid/not enabled). Shared into the cti pool
# so both the OSINT username seed and CTI actor-
# handle pivots use it.
# gravatar (free, no-key email→public profile:
# MD5(email)→display name + linked social accounts +
# URLs; email pivot, shared into the cti pool).
# github_profile (free, no-key GitHub user→identity
# enrichment: name/company/blog/twitter handle;
# username pivot, shared into the cti pool).
# wikidata (free, no-key, CC0 identity anchor:
# name→QID + description + official site + social
# handles [twitter/github/mastodon/…] with a citable
# QID URL; username pivot, shared into the cti pool).
# phone_enrich (offline, no-key phone metadata via
# libphonenumber/phonenumbers Apache-2.0: validity,
# country/region, carrier, line type, timezones;
# powers the new `phone` OSINT seed + phone pivot,
# shared into the cti pool).
# wallet_enrich (crypto wallet on-chain activity:
# BTC via blockstream.info no-key, ETH via Etherscan
# w/ optional ETHERSCAN_API_KEY — balance, volume,
# tx count, activity window, counterparty sample;
# concept ported from flowsint Apache-2.0, see
# THIRD_PARTY_LICENSES; wallet_address pivot, shared
# into the cti pool).
# website_enrich (free, no-key page extraction:
# title/text + outbound links/external domains +
# emails + social-profile handles via stdlib regex;
# concept ported from flowsint to_text/to_links
# Apache-2.0; url pivot, shared into the cti pool).
# DD (Phase 3): gleif (GLEIF/LEI company identity +
# Level-2 "who owns whom" hierarchy; free, no-key,
# CC0; powers the `company` seed via the dd pool. NB:
# Level-2 = ESTIMATED corporate ownership, NOT
# authoritative UBO/RBE).
# sanctions (name screening vs OFAC SDN + EU FSF +
# UK UKSL consolidated lists; free, no-key, all
# commercial-OK licences; header-tolerant parsers +
# normalised matcher; hits = candidates for review,
# not determinations. dd pool).
# companies_house (UK company profile + officers + PSC;
# free key, OGL v3.0; officers/PSC → person nodes →
# sanctions-screened. Graceful w/o key. dd pool).
# edgar (SEC EDGAR US-listed issuer identity: CIK,
# tickers/exchanges, SIC, state of incorp, former
# names; free, no key, public domain. dd pool).
# recherche_entreprises (FR company + dirigeants via
# gouv API; free, no key, Licence Ouverte 2.0;
# dirigeants → person nodes → sanctions. dd pool).
# Shared: http_client
tests/ # pytest suite (golden / regression tests, e.g.
# test_seeds.py locks the seed-registry output).
# Run: pytest backend/tests (deps: requirements-dev.txt)
frontend/
src/
main.jsx # React entrypoint
App.jsx # Main app (Cytoscape graph, sidebar, report/chat/node panels)
invUrl.js # Pure ?inv=<id> URL-sync helper (+ invUrl.test.js, node --test, run in CI)
Login.jsx # PIN login screen
AdminPanel.jsx # Admin dashboard (users, models, impersonation)
ShareModal.jsx # Build a share link (sections + expiry)
SharedView.jsx # Public/share-link viewer (read-only graph + import button);
# with demoSrc, the static demo viewer (no backend;
# demoCases adds a case picker when >1 snapshot)
demo.jsx # Entry of the static demo build
styles.css
demo/index.html # Static demo page (vite.demo.config.js). Opened from
# disk (file://) its module script never runs: a hint
# in #root, unhidden on file: only, says to serve it;
# a <noscript> if JS is off (test_demo_page_offline.py)
vite.config.js # Dev proxy: /api→:8001, /ws→ws://:8001
vite.demo.config.js # `npm run build:demo` → dist-demo/: SharedView + every
# eval/demo/*.json copied to data/, relative base (any
# static host). The app build is untouched by it.
# Open it served (python3 -m http.server --bind
# 127.0.0.1 --directory dist-demo), never from disk
data/ # Runtime data (gitignored)
bounce.db # SQLite database
secret.key # HMAC key for PIN auth
mcp-{id}.json # Per-investigation MCP configs (temporary)
mcp-launcher-*.log # Per-server launcher trace logs (debug)
fixtures/ # capture/<inv_id>/ (BOUNCE_FIXTURE_CAPTURE=1 or capture: true) and
# replay-misses/<inv_id>.jsonl (BOUNCE_FIXTURE_DIR)
runs/ # Archived eval-protocol scorecards (one folder per run)
eval/results_digest.py # Renders EVAL_RESULTS.md from runs/*/scorecard.md (stdlib,
# offline). Like-for-like trend on the fresh subset only;
# v2 Overall and v3 CAP never averaged together.
# `--check` exits 1 when the page is stale (also enforced
# by backend/tests/test_eval_results_digest.py).
EVAL_RESULTS.md # GENERATED published eval digest — re-run the script after
# adding a run under runs/ or eval/baseline/, never edit by hand
eval/baseline.py # Bare-model baseline (EVAL_PROTOCOL §4.D): run --arm memory|web
# gives each seed to the same model with no Bounce-CTI tool
# (empty cwd, no MCP, filtered env); compare scores every side
# with eval/scorer.py itself (score_case(case, out_dir)).
# run --seeds <batch>/seeds.json runs a prospective batch
# (each run.json says started_at / finished_at, UTC: seal
# checks rule 1 on it).
# Stdlib only
eval/baseline/<date>/ # Committed baseline results: results.json (scores, models,
# hosts the web arm read) + results.md. No raw answers
eval/prospective.py # Prospective cases (EVAL_PROTOCOL §4.E): seal <batch> freezes
# every arm's claims (what action_exports would ship, minus
# the seed) + the judge's answer at T into manifest.json, and
# commitment.json (sha256 + counts, no value: commit it at T);
# check after the horizon (exit 3 before, --early = provisional);
# score: known/ahead/unconfirmed/benign/undetermined per arm,
# pooled recall. Judge v1 = OTX pulses, keyless, a domain asked
# under hostname AND domain. Manifest not the committed one = exit 1;
# a lookup failed at T seals nothing (exit 4; OTX_API_KEY for a batch).
# --server/--cookies (admin session): `seeds` picks a batch from
# /api/admin/eval/fresh_iocs (pick/1, one per family, once),
# `preflight`, and seal/check under judge v2 via /judge, with a
# positive control (a seed must be listed in its own feed at T,
# else exit 4; one its search misses is read by id: still in the
# feed = late, accepted at T; gone = refused; strict at the check,
# where score refuses a blind search). An abuse.ch listing dated
# before the seal scores known (known_late), not ahead.
# Secondary horizon 30 days pre-registered.
# `bounce` fills the Bounce-CTI arm through the server: one
# investigation per seed (opus-5), ONE AT A TIME, resumed (≤2)
# after quota_exceeded / error: interrupted, graph written only
# when done, bounce.json recording each run at submission (rerun
# = pick up, never resubmit; exit 5 while a run is not done).
# seal reads each run's start (bounce.json, pivot-1.json, the
# web arm's run.json started_at) and refuses a start > 48 h after
# the seed's first_seen (rule 1 at run time), a run not done, a
# web run with no answer, an arm with no start times (unless
# --allow-unstamped, listed in the commitment). --drop
# LABEL=reason leaves a contaminated seed out at the seal:
# never edit seeds.json (its sha256 ties the stamped arms)
# backend/tests/test_sources_read_only.py: sources only read
deploy.sh # Auto-deploy script (callable on the VPS)
Dockerfile # Local one-image run (not used by prod): frontend build
# stage, then backend + claude CLI as non-root `bounce`
docker-compose.yml # `docker compose up -d --build`: .env bind-mounted read-only
# (never created), data/ in a volume, 127.0.0.1:8001 only
.dockerignore # .env, data/, .git stay out of every image. These three
# promises are pinned by backend/tests/test_docker_packaging.py
run_mcp.py # MCP server launcher (referenced by generated mcp.json configs)
mcp.json # Template MCP config (rendered per investigation at runtime)
EVAL_PROTOCOL.md # Active eval protocol (run on every non-trivial agent change)
PIVOT_MAPPING.md # Architecture spec for the autonomy engine refactor
eval/fixture_tool.py # promote <inv_id> <case> (a capture → eval/fixtures/<case>/
# + MANIFEST.md), verify (integrity + no secret: .env
# values and credential shapes; exit 1), stats
eval/fixtures/<case>/ # Committed fixture sets, one per eval case, one JSON
# file per source response (name = sha256 of the key)
eval/demo_export.py # <inv_id> <name> --db … --dotenv …: one investigation →
# eval/demo/<name>.json (backend/demo_snapshot.py rules).
# Source DB opened read-only, rows copied to a throwaway
# DB; exit 1 on a secret or --forbid word (nothing
# written), 2 if the --dotenv can't be read
eval/demo/ # Committed demo snapshots + README (how to make one, which
# run to pick). PUBLIC repo: check before committing
eval/drain_gate_replay.py # --db … [--seeds]: replays the pivot-drain gate
# (_concluded_benign) on every drain of a database, each
# graph rebuilt from its events as it stood at drain start.
# Read-only; seed values only with --seeds
.github/workflows/demo-pages.yml # Publishes dist-demo/ to GitHub Pages, by hand only
.github/dependabot.yml # Monthly grouped update PRs: actions, frontend, pip (never mcp>=2).
# Workflow invariants pinned by backend/tests/test_ci_workflows.py
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 8d ago Changed · +5 lines · +96 tokens per session 307a2f4e7b5e
- 9d ago Changed · +19 lines · +355 tokens per session 8f50366eefcf
- 10d ago Changed · +7 lines · +109 tokens per session aa4e290d70ae
- 12d ago Changed · +14 lines · +255 tokens per session dff408979495
- 13d ago Changed · +42 lines · +779 tokens per session fa19a3c2bfe7
- 14d ago Changed · +26 lines · +595 tokens per session cb7d872d805c
- 15d ago Changed · +11 lines · +231 tokens per session ae9beaa085f4
- 16d ago Changed · +6 lines · +118 tokens per session 9bc12b4e9bf2
- 18d ago Changed · +1 lines · +14 tokens per session e667c485b5df
- 20d ago First seen · 785 lines · 13,845 tokens per session scan A eff1f5fcf2de
bounce-cti CLAUDE.md is an instructions file published in the GitHub repository Iskandeur/bounce-cti (5 stars, last pushed 4d ago), licensed Apache-2.0. It adds 16,397 tokens to every session, about $0.0656 per session on Opus 5.5. A static security scan graded it A with 1 finding (makes network calls). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
bounce-cti CLAUDE.md compared with instructions from other repositories
| Mod | Type | Stars | Last push | Licence | Scan | Tokens | Works with |
|---|---|---|---|---|---|---|---|
| bounce-cti CLAUDE.mdIskandeur/bounce-cti | Instructions file | 5 | 4d ago | Apache-2.0 | A | 16,397 | Claude Code |
| vscode buildNext.instructions.mdmicrosoft/vscode | Instructions file | 195k | yesterday | MIT | A | 9,719 | GitHub Copilot |
| next.js AGENTS.mdvercel/next.js | Instructions file | 143k | yesterday | MIT | A | 7,461 | Codex, OpenCode |
| langchain AGENTS.mdlangchain-ai/langchain | Instructions file | 149k | yesterday | MIT | A | 4,680 | Codex, OpenCode |
| vscode oss-third-party-notices.instructions.mdmicrosoft/vscode | Instructions file | 195k | yesterday | MIT | A | 5,516 | GitHub Copilot |
| vscode copilot-instructions.mdmicrosoft/vscode | Instructions file | 195k | yesterday | MIT | A | 3,093 | GitHub Copilot |
| deepseek-harness AGENTS.mddeepseek-ai/deepseek-harness | Instructions file | 274k | 2d ago | MIT | A | 4,313 | Codex, OpenCode |