bounce-cti: Instructions file for Claude Code

CLAUDE.md

bounce-cti CLAUDE.md is an instructions file for Claude Code from Iskandeur/bounce-cti. It costs 16,397 tokens per session, scanned A, original, Apache-2.0.

Project instructions for Claude Code in the bounce-cti repository. They describe the project, its layout, and development and backend guidance.

In plain words
What is it for?
Use it as a reference while developing or changing bounce-cti, including its backend and file structure.
Why use it?
It gives the coding agent project-specific context when working in that repository.

Instructions file for Claude Code

Written for Claude Code: the file is CLAUDE.md. Also seen: reads .claude/ paths; mentions CLAUDE.md; mentions Claude Code.

This is Iskandeur/bounce-cti's own configuration. It tells Claude Code how to work on bounce-cti itself, so it is not a mod to install elsewhere. Copy it as a starting point and replace the rules that are about this project. Everything bounce-cti configures →

Reuse

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.

Copy the file
curl -O https://raw.githubusercontent.com/Iskandeur/bounce-cti/main/CLAUDE.md
Clone the repo
git clone --depth 1 https://github.com/Iskandeur/bounce-cti

Made for: Claude Code.

Wrote 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.

agentmods badge for bounce-cti CLAUDE.md

README.md
[![agentmods](https://agentmods.dev/badge/instructions/iskandeur/bounce-cti/claude-md/github.svg)](https://agentmods.dev/instructions/iskandeur/bounce-cti/claude-md)
Your own site
<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.

agentmods 80×15 button for bounce-cti CLAUDE.md

Your own site · 80×15
<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>
Per session 16,397 This file is loaded in full into every session.
When invoked 16,397 The same file — it is already loaded in full.
Security scan A 1 finding. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

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.

ModelPer sessionOnce 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

Measured 8d ago against content hash 307a2f4e7b5e, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

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.
CLAUDE.md · 916 lines

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

Read the full file on GitHub · 916 lines

Changes

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.

  1. 8d ago Changed · +5 lines · +96 tokens per session 307a2f4e7b5e
  2. 9d ago Changed · +19 lines · +355 tokens per session 8f50366eefcf
  3. 10d ago Changed · +7 lines · +109 tokens per session aa4e290d70ae
  4. 12d ago Changed · +14 lines · +255 tokens per session dff408979495
  5. 13d ago Changed · +42 lines · +779 tokens per session fa19a3c2bfe7
  6. 14d ago Changed · +26 lines · +595 tokens per session cb7d872d805c
  7. 15d ago Changed · +11 lines · +231 tokens per session ae9beaa085f4
  8. 16d ago Changed · +6 lines · +118 tokens per session 9bc12b4e9bf2
  9. 18d ago Changed · +1 lines · +14 tokens per session e667c485b5df
  10. 20d ago First seen · 785 lines · 13,845 tokens per session scan A eff1f5fcf2de

Subscribe to this mod's changes

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.

Related

bounce-cti CLAUDE.md compared with instructions from other repositories

bounce-cti CLAUDE.md next to 6 instructions from other repositories
ModTypeStarsLast pushLicenceScanTokensWorks with
bounce-cti CLAUDE.mdIskandeur/bounce-ctiInstructions file54d agoApache-2.0A16,397Claude Code
vscode buildNext.instructions.mdmicrosoft/vscodeInstructions file195kyesterdayMITA9,719GitHub Copilot
next.js AGENTS.mdvercel/next.jsInstructions file143kyesterdayMITA7,461Codex, OpenCode
langchain AGENTS.mdlangchain-ai/langchainInstructions file149kyesterdayMITA4,680Codex, OpenCode
vscode oss-third-party-notices.instructions.mdmicrosoft/vscodeInstructions file195kyesterdayMITA5,516GitHub Copilot
vscode copilot-instructions.mdmicrosoft/vscodeInstructions file195kyesterdayMITA3,093GitHub Copilot
deepseek-harness AGENTS.mddeepseek-ai/deepseek-harnessInstructions file274k2d agoMITA4,313Codex, OpenCode