BankWeave

io.github.LSUDOKO由 GitHub 帳號 LSUDOKO 發布v3.0.1更新於 Oct 26, 2026

Read-only FalkorDB tools for cross-bank AML investigations: rings, money paths, echo-proof claims.

已驗證Streamable HTTP可網頁執行資料庫金融資料與分析

概覽

AI 產生的概覽

供跨行反洗錢調查使用的唯讀 FalkorDB 工具:集團環、資金路徑、告警、案件與可溯源結論。

可以做什麼
  • 了解與檢視圖資料庫:引擎健康狀態、圖清單與單一圖的結構
  • 瀏覽調查案件、告警與其分診決定,並進行即時複核
  • 分析帳戶:跨行鄰域、共用身分、行為相似帳戶、客戶模糊搜尋
  • 追蹤資金:跨行最短路徑、洗錢集團環、PageRank 樞紐、連通分量
  • 解釋結論的置信度,並引用洗錢類型知識庫中的指引
  • 作為最後手段,在單一圖上執行受保護的唯讀 Cypher
適用情境
適合讓助理探索以 FalkorDB 為後端的反洗錢資料集:分診告警、跨行追蹤資金、找出集團環與樞紐,或查核某項結論為何具有該置信度。它是專案自帶示範資料上的唯讀分析層,並非連接真實銀行的即時資料。
執行需求
可使用託管的 Streamable HTTP 端點,或以容器映像在本機透過 stdio 執行(需 Docker)。MCP 伺服器本身未宣告任何 API 金鑰、環境變數或請求標頭。託管執行個體位於閒置即休眠的免費方案,首次請求可能需約一分鐘。
安裝前請注意
17 個工具皆為唯讀,引擎會拒絕寫入,但受保護的 Cypher 工具仍可在所指向的圖上執行任意讀取查詢。託管端點是未宣告驗證的公開示範執行個體,請將送出的內容視為公開。資料為 IBM 公開的反洗錢基準資料集加上合成身分層,並非真實客戶紀錄。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 BankWeave,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。

交給代理程式安裝

把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。

閱讀 https://sourceweft.com/mcp/io.github.LSUDOKO%2Fbankweave/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。

檢視代理程式所依據的安裝指南

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。

{
  "mcpServers": {
    "bankweave": {
      "type": "http",
      "url": "https://bankweave-api.onrender.com/mcp"
    }
  }
}

README

[BankWeave logo: a blue B whose bowls are split by one thread]

BankWeave

[CI] [Release] [Live] [MCP: hosted HTTP] [API image] [MCP image] [FalkorDB Cloud] [License: MIT]

Many banks, one ring, every claim proven.

[Each bank sees only its piece; FalkorDB's consortium graph sees the ring; agents prove every claim]

BankWeave is a team of AI agents that investigates money-laundering alerts across several banks, with FalkorDB as its shared brain. It clears innocent alerts fast, exposes laundering rings that no single bank can see, and backs every conclusion with a graph path you can click through. It also knows how many independent reasons it has for each belief, notices when one of them dies, and refuses to file a report it can't prove.

  • Tracks: 01 Agents That Act on Connected Data (primary), 02 Agent Memory and Coordination, Best blog post
  • Live deployment: https://bankweave.vercel.app (UI on Vercel) · API https://bankweave-api.onrender.com/docs (Render) · graph: FalkorDB Cloud (ap-south-1)
  • MCP Registry: published as io.github.LSUDOKO/bankweave (v3.0.0, streamable HTTP)
  • Use it from Claude: claude mcp add --transport http bankweave https://bankweave-api.onrender.com/mcp, or as a stdio package: claude mcp add bankweave -- docker run -i --rm ghcr.io/lsudoko/bankweave-mcp (17 read-only FalkorDB tools, each returning the Cypher it ran; docs/MCP.md)
  • Proof in FalkorDB's own browser: screenshots and a recording of the ring, PageRank, card taps, SAR provenance and vector search running on our Cloud instance
  • Understand it in five minutes: the 3D explainer (eight scenes, each one FalkorDB call) and the graph explorer (twelve presets, run live)
  • Demo video: watch on YouTube, on the landing page or download the MP4 (narrated, captions burned in): a whiteboard explainer of the problem, the problem film's close, then the live product on FalkorDB Cloud, the hardware edge, MCP and FalkorDB's own browser. Build it yourself: video/build.py --long
  • Blog post: docs/BLOG.md

Running now on real data. The production instance on FalkorDB Cloud holds IBM's labelled AML transactions for 6 banks: 3,024 accounts, 24,990 transfers, 36 graphs (6 bank graphs, the consortium graph with 10,178 nodes and 37,448 edges, 27 case graphs, agent memory and the typology knowledge base). The agents have triaged 1,208 alerts: 1,113 cleared with a stated reason and 95 escalated into cases, each case with claims, evidence, the Cypher behind every piece of evidence, a provenance-gated report and a signed Merkle seal.

BankWeave is an independent project built for FalkorDB Graph Hacks. It is not a FalkorDB product and is unrelated to FalkorDB's QueryWeaver or Weights & Biases Weave.


The problem

  1. Alert fatigue. Rule-based transaction monitoring flags single signals without context; industry sources put 85-95% of alerts as false positives.
  2. Fragmented visibility. A bank only sees transactions that touch it. Laundering schemes spread across institutions, so each bank's slice looks innocent.
  3. Unprovable reports. A suspicious activity report (SAR) has to justify itself, and today that justification is assembled by hand.

What BankWeave does

  1. Loads IBM's public AMLworld laundering dataset into one isolated FalkorDB graph per bank plus a consortium graph that links them with salted, hashed account ids.
  2. A team of agents (Orchestrator, Triage, Investigator, Skeptic, Reporter with a separate Auditor, Archivist) works the alert queue through a task blackboard stored in the graph, calling native FalkorDB algorithms as tools (also served over MCP).
  3. Innocent alerts are cleared in milliseconds with a reason; suspicious ones become cases, each in its own case_<id> graph, where claims are linked to evidence and the query that produced it.
  4. A trust layer built from three 2026 papers keeps the agents honest (below).
  5. Humans approve every action. Everything is measured against IBM's labels on a scoreboard.

What's new in 3.0

AreaWhat you can doWhere
ConsoleA sidebar listing all fourteen pages with live counts, Ctrl K search over pages and cases, and one card system across every page: stat cards from live queries, status chips, rounded chartsevery page
DashboardOpen cases, alerts decided, independent claims, actions awaiting a human; claim support for the latest cases; the next approval; the agent team; an alert-triage gauge; FalkorDB Cloud latency, graphs and memory/command
Graph explorerA FalkorDB-browser-style page: pick a graph, write Cypher (GRAPH.RO_QUERY, writes rejected by the engine), see an Obsidian-style force graph with labels, hover neighbourhoods and a property panel. Twelve presets, each a FalkorDB feature on our data: cross-bank ring, algo.pageRank, algo.labelPropagation, algo.wcc, algo.SPpaths, Double Metaphone full-text, HNSW vector KNN, shared identity, the agents' alert-to-claim chain, a SAR's provenance, the typology KB, learned procedures/explorer
3D explainerScroll through eight scenes on a three.js stage: six bank slices and per-graph ACL, hashed ids stitching the consortium, algo.wcc clearing an alert, the ring one bank sees 37.5% of, PageRank hub and algo.SPpaths, six paths collapsing to four origins, a KYC cascade, a Merkle root signed by a hardware key. Every number comes from the API; each scene shows the Cypher it ran/explainer
Hosted MCPclaude mcp add --transport http bankweave https://bankweave-api.onrender.com/mcp: 17 read-only tools (cases, echo-proof claims, money paths, rings, hubs, components, vector and phonetic search, triage, typologies, guarded Cypher), 3 prompts, 2 resources/mcp, docs/MCP.md
LandingCentred hero over glossy blue bubbles with word-by-word type, the live console rising out of it, a "what's new" bento, the evaluation shown as highlighted screenshots of the live page, the real-tool recordings and the FalkorDB Browser proof/
Real tools, recordedThe ESP32 sketch running in Wokwi posts a real card tap to the live API, and EMVLab decodes the field 55 it printedHardware Lab, below
LandingDashboard
[圖片][圖片]
Graph explorer: cross-bank ring on the consortium graph3D explainer: the ring as one bank sees it
[圖片][圖片]
Graph explorer: algo.pageRank hubs (hover focuses one community)3D explainer: six bank slices, each sees only its own graph
[圖片][圖片]
Alert queueCase workspace
[圖片][圖片]
ApprovalsHardware Lab
[圖片][圖片]

Proof in the official FalkorDB Browser

The same data the agents use, opened in FalkorDB's own browser (browser.falkordb.com, connected to our FalkorDB Cloud instance: FalkorDB v4.22, 36 graphs, about 81 MB). Every query below is read-only and was typed into the browser; the timings are the engine's own RT readout. The connection bar with the instance hostname is cropped out.

[Running BankWeave's queries in the FalkorDB Browser]

QueryWhat it proves
Cross-bank ring: the case spanning the most banks, its accounts, banks and transfers (12 nodes, 166 edges, 1.85 ms)one Cypher query sees the whole ring that no single bank graph contains
CALL algo.pageRank('Account','TRANSFERS') top 12 (3.55 ms)the hub detection the Investigator calls is native GraphBLAS, not Python
(:Account)-[:CARD_TXN]->(:Terminal) (5 nodes, 29 edges, 0.41 ms)the POS/ATM taps, including the one sent from the Wokwi ESP32, are real edges in the consortium graph; the Terminal node carries POS-MUM-…, Mumbai, GPS 19.076, 72.8777
(:SAR)-[:CONTAINS]->(:Sentence)-[:CITES]->(:Claim)-[:SUPPORTED_BY]->(:Evidence) in case_C-70431130 (0.61 ms)every report sentence cites a claim, and every claim rests on evidence: the provenance gate is a graph pattern
db.idx.vector.queryNodes('Account','behavior_vec',10, …) (0.36 ms)HNSW vector search finds behaviour twins at five different banks
Accounts at different banks sharing a Device or IP (291 nodes, 220 edges, 2.79 ms)the identity links the consortium uses to join bank slices
Cross-bank ringalgo.pageRank
[圖片][圖片]
Card taps into terminals (the Wokwi tap included)The Mumbai POS node and its properties
[圖片][圖片]
SAR → sentence → claim → evidenceHNSW vector KNN
[圖片][圖片]
Shared devices and IPs across banksFalkorDB Cloud console: the instance (Free tier, ap-south-1, v4.22.0, healthy)
[圖片][圖片]

Hosted MCP, called live (no install, plain HTTP):

$ curl -s -X POST https://bankweave-api.onrender.com/mcp -H 'Content-Type: application/json' \    -H 'Accept: application/json, text/event-stream' \    -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'17 tools: engine_overview, list_graphs, graph_schema, list_cases, get_case, explain_claim,account_network, trace_money_path, find_rings, top_hubs, connected_components, similar_accounts,search_customers, list_alerts, triage_alert, typology_guidance, run_readonly_cypher
$ ... "method":"tools/call","params":{"name":"top_hubs","arguments":{}}{"graph": "consortium", "result": [{"account": "e8ccd1faa8d3a4ba", "bank": "001", "score": 0.0027...}, ...

The top account matches row 1 of the PageRank query in the FalkorDB Browser above.

What's new in 2.0

AreaWhat you can doWhere
Command CenterLive alerts, open cases, independently supported claims, evidence awaiting review, FalkorDB health (memory, graphs, engine) in one view/
Golden scenariosA: an innocent alert cleared by algo.wcc. B: a ring across 4 banks (best single bank holds 50% of it; E2: 43.8% on average, 0% of rings whole). C: a shared 200-unit building behind a claim, with the cascade a KYC update would trigger. Computed live; bundled snapshots load instantly when the free-tier API sleeps/scenarios
Mode badgeEvery page says whether it is live with LLM agents, live with deterministic agents, or a seeded replayrail, page headers
FalkorDB LabEvery graph with counts, indexes and GRAPH.MEMORY USAGE; 17 one-click runs (10 algorithms, phonetic and stemmed full-text, vector KNN, JS UDFs, FLEX, a tri-modal query); a read-only GRAPH.PROFILE/GRAPH.EXPLAIN inspector; the MCP tool explorer with schemas, live payloads, the Cypher each tool ran and an Engine X-Ray of it; per-bank ACLs; procedural memory as a graph/lab
Case workspaceEvidence Independence Explorer ("15 paths → 12 origins"), revoke any evidence and watch the cascade, provenance DAG (React Flow), Replay Investigation, bi-temporal time machine, Simulate Freeze on a GRAPH.COPY sandbox, sanctions screening, crypto off-ramp linking, agent trace waterfall/cases/<id>
Signed exportsFinCEN-style SAR XML and a printable audit dossier: every sentence, the evidence it cites, each query with an execution hash, and an Ed25519-signed Merkle root over the case/cases/<id>/dossier
3D consortiumBank slices walled in by external stubs, the consortium where they join (flow particles, PageRank hub), cases and claims on top; fly-through, echo collapse, invalidation shockwave, kill-and-resume with a heartbeat countdown/consortium-3d
EvaluationE2 hero, E1 table plus a threshold explorer, E6 scorecard, E3-E5 with misses labelled, E7 badged as a local benchmark/evaluation
Hardware Lab (device twins, real cryptography)POS/ATM digital twin emitting ISO 8583 with real EMV TLV into the graph; a Wokwi ESP32 terminal; approvals signed with WebAuthn or a virtual security key over the Merkle root ("Merkle seal broken" if evidence changes later); an enclave with PCR attestation that quarantines itself when tampered with; ECDH-PSI between banks/hardware-lab, hardware/wokwi/
IntegrationsOpenSanctions screening (live with an API key, bundled sample list without one), on-chain wallet facts, OpenTelemetry-shaped spans with OTLP export/integrations/*, case tabs

The card terminals, enclave and security key run as software device twins (the ESP32 terminal in Wokwi), producing real EMV/ISO 8583 data, real signatures, real key exchange and real graph writes through the same API a physical device would call.

Screenshots from the live site

Captured on https://bankweave.vercel.app against the Render API and FalkorDB Cloud (ap-south-1), agents on Groq's free tier; the mode badge reads "Live · LLM + FalkorDB".

Golden scenarios: A cleared by algo.wcc, B the ring across banks, C the cascadeBank vs consortium: one bank's fragments against the consortium
[圖片][圖片]
CasesCase workspace: evidence independence ("15 paths → 14 origins")
[圖片][圖片]
Provenance DAGSimulate Freeze on a GRAPH.COPY sandbox
[圖片][圖片]
Agent trace waterfall (OpenTelemetry-shaped spans from the live agents)Sanctions screening and crypto off-ramp bridge
[圖片][圖片]
The SAR: every sentence cites its evidenceAudit dossier with the signed Merkle root
[圖片][圖片]
Trust layer: echo-proof confidence and the cascade3D consortium
[圖片][圖片]
FalkorDB Lab: graphs, nodes, edges, memoryAlgorithms and indexes, one click each
[圖片][圖片]
GRAPH.PROFILE / GRAPH.EXPLAIN inspectorMCP tools with live payloads and the Cypher each ran
[圖片][圖片]
Engine features: JS UDFs, tri-modal query, per-bank ACLEvaluation
[圖片][圖片]

Measured, with the evidence highlighted. The landing page's "The numbers, not the pitch" shows these captures of the live Evaluation page:

E2: best single bank 43.8%, rings seen whole 0 of 36, consortium 100%E1: calibrated graph score F1 0.205 vs 0.063 escalating everything
[圖片][圖片]
E6: 27.8% echo caught, 25 of 28 SARs through the gate, 100% cascade recallE7: vector KNN 0.4 ms, PageRank over the whole consortium 57.5 ms
[圖片][圖片]

Hardware trust layer (device twins, real cryptography)

Banks don't let software act alone: terminals produce the device evidence, HSMs and enclaves guard identity hashing, and a human signs off with a security key. BankWeave runs all three as device twins in software and wires each into FalkorDB.

Recorded on the real tools. The sketch in hardware/wokwi/ running in the Wokwi ESP32 simulator: it joins Wokwi-GUEST, Card A is tapped on the Mumbai POS, the board posts it over HTTPS to the live API, which answers 00 APPROVED, writes the CARD_TXN edge into FalkorDB Cloud and returns the ISO 8583 field 55 printed on the serial monitor. EMVLab.org then decodes that exact TLV (amount, currency, IFD serial D0006301, ATC, cryptogram, PAN).

Wokwi ESP32 → live API → FalkorDBEMVLab decodes the tap's field 55
[圖片][圖片]

The Hardware Lab on the live site:

Terminals: POS and ATM twins with their last taps, EMV TLV, verify on EMVLabSecurity key: sign the case's Merkle root with WebAuthn or the virtual VaultKey
[圖片][圖片]
Enclave: attestation document, PCRs, HSM signer, bank linksESP32 on Wokwi: the real sketch, diagram and live serial log
[圖片][圖片]
ECDH-PSI between two bank graphs (X25519)Wokwi tap as an edge in FalkorDB Cloud (FalkorDB Browser)
[圖片][圖片]

What each device twin produces:

PieceReal outputRuns as
Card terminalsBER-TLV encoding (verified by EMVLab), ISO 8583 field layout, graph writes (CARD_TXN, USES_DEVICE {emv_atc, terminal_id, gps, nfc_uid}), alerts the agents triage, impossible-travel and ATC-replay detectionthe terminals and cards; 9F26 is an HMAC, not a chip's 3DES/AES MAC
Wokwi ESP32the circuit runs in Wokwi and makes real HTTPS postsESP32 board in the Wokwi simulator
Approval keysWebAuthn ES256 verification, signature counter, Merkle root over claims/evidence/sentences, seal break on revocationVaultKey is a WebCrypto key in the tab
Enclave / HSMHMAC-SHA256 blinding, SHA-384 PCRs, ES384-signed Nitro-style document, (:EnclaveAttestation) nodes, ingestion refused with 423 while quarantinedno TEE hardware or AWS Nitro PKI chain
PSIX25519 scalar multiplication, commutative blindingboth banks run in one process

External verifiers: EMVLab TLV decoder · EMVLab cryptogram tool · WebAuthn.me debugger · Chrome virtual authenticator · Wokwi ESP32 · OpenSanctions · FalkorDB Cloud.

Why FalkorDB is essential

Turn FalkorDB off and BankWeave can't do any of its core work:

Without the graph…because
no ring is visiblethe ring only exists as a path between banks; the consortium graph is where it connects (see E2)
triage can't clear anythingcomponents, motif scores, cross-bank links and shared identity are all graph queries
no claim has evidenceevidence is a path, an algorithm score or a shared attribute in the graph, stored with its query
confidence can't be computedecho-proof confidence counts distinct origins over SUPPORTED_BY edges
invalidation can't cascadedependencies are typed edges (SUPPORTED_BY, DERIVED_FROM, JUSTIFIED_BY, CITES)
agents can't coordinate or resumetasks, heartbeats and the case timeline live in the graph

FalkorDB features in use: multigraph (per-bank, consortium, per-case, procedures, typology KB graphs in one instance), native algorithms (algo.wcc, algo.labelPropagation, algo.pageRank, algo.betweenness, algo.HarmonicCentrality, algo.SPpaths, algo.SSpaths, algo.maxFlow, algo.bfs, algo.MSF), full-text indexes with Double Metaphone phonetic matching and English stemming, a vector index (HNSW) on behaviour profiles, JavaScript UDFs (FalkorDB's FLEX library and our own aml_temporal), GRAPH.COPY sandboxes, GRAPH.PROFILE/GRAPH.EXPLAIN, GRAPH.MEMORY USAGE, ACLs scoped to one graph, and the Redis protocol for live pub/sub.

Proof: every FalkorDB feature BankWeave uses

FeatureWhere in the codeEvidence it runs
Multigraph (isolated graphs in one instance)consortium, bank_<id>, case_<id>, procedures, typology_kb (backend/app/db.py)Browser shows 43-188 graphs during a run; FalkorDB Cloud holds consortium + 6 bank graphs + typology_kb
algo.wccprecompute component sizes; triage islands (detection/precompute.py, detection/algorithms.py)E7 timing; triage reasons "isolated cluster" in the alert queue
algo.labelPropagationcommunities (detection/precompute.py)Account.community on every account
algo.pageRankhub finding in case graphs; SPNSA intermediaries[hub] on FalkorDB Cloud (3.55 ms); E7 timing
algo.betweenness (seeded)mule bridges; SPNSA[betweenness]
algo.HarmonicCentralityorchestrator candidatesfind_orchestrator tool, rebuttal rounds
algo.SPpathsmoney paths: the primary evidence of a claimpath evidence in every case, with its query
algo.SSpaths, algo.bfsreach, bfs_reach tools (case graph)available to the Investigator and over MCP
algo.maxFlowmoney at risk over collapsed FLOWS edgeshub claims cite max-flow evidence
algo.MSFbackbone tool: a ring's spanning backboneavailable to the Investigator, Reporter and over MCP
Full-text index + Double MetaphonePerson.name, Company.name (detection/identity.py)test_identity.py: a spelling variant finds its original identity
Full-text index + English stemmingtypology knowledge graph (knowledge/typology_kb.py)cited answers; abstains on unrelated questions
Vector index (HNSW, cosine)16-dim behaviour profiles (app/services/loader.py)behavior_neighbors, triage features, clue expansion
Range indexes incl. relationship property indexTRANSFERS.ts (the txn_id edge index was dropped in 2.0: nothing looks it up, and it cost ~8 MB)CALL db.indexes()
JavaScript UDFs (GRAPH.UDF LOAD)aml_temporal.timeRespectingReach walks TRANSFERS with getNeighbors, following only later transfers (backend/udf/aml_temporal.js)test_lab.py::test_udf_libraries_load_and_run; Lab → Engine features
FLEX (FalkorDB's UDF library, vendored 1.0.1)flex.text.jaroWinkler, flex.text.levenshtein for names, flex.sim.jaccard for shared identity attributesLab runs flex_names, flex_jaccard
GRAPH.COPYSimulate Freeze copies the case graph, deletes the account in the copy, reruns algo.maxFlow + algo.wcc (app/routers/workspace.py)test_workspace.py: flow 80 → 0, sandbox deleted
GRAPH.PROFILE / GRAPH.EXPLAINread-only inspector and Engine X-Ray per tool call; a query must pass GRAPH.RO_QUERY first (app/services/engine.py)test_lab.py::test_inspect_refuses_writes
GRAPH.MEMORY USAGEper-graph memory in the Lab and Command Center; capacity guard for the 100 MB cloud tier (app/services/capacity.py)/lab/graphs
ACL (~graph key patterns, ACL LOG)a bank user that can only GRAPH.RO_QUERY its own graph (/lab/acl-demo)consortium, other banks and writes denied, logged (screenshot above). The FalkorDB Cloud user cannot manage ACLs, so this runs on Docker
Several CALLs in one querytri-modal query: phonetic full-text → HNSW vector twins → algo.SPpaths over FLOWSLab trimodal (about 10 ms)
Parameterised Cypher, ro_query for readsevery query (docs/QUERIES.md: 204 registered + 67 inline)read-only MCP tool cypher_readonly
Concurrent writers on one graphtask blackboard (agents/blackboard.py)test_blackboard.py: 6 threads, 20 tasks, each claimed once
FalkorDB Browservisual inspection of every graphscreenshots below
FalkorDB Cloudlive instance (ap-south-1) seeded with the IBM slicescripts/make_slice.py + seed log

Proof from the live FalkorDB Cloud instance

Screenshots from FalkorDB Browser connected to the production instance the live site uses (docs/img/cloud/):

WhatScreenshot
Multigraph: consortium, six bank graphs and case graphs in one instance[圖片]
Index types in use: 1 vector (HNSW), 2 full-text (phonetic), 14 range[圖片]
Every index, by label and property[圖片]
algo.pageRank on the consortium (4.3 ms)[圖片]
Vector similarity over behaviour profiles (0.5 ms)[圖片]
Double Metaphone full-text: "Hana Sharma" finds "Hannah Sharma"[圖片]
A ring the live agents opened: one hub paying accounts at four banks (consortium graph, 0.98 ms)[圖片]
That case's own graph: claims, SUPPORTED_BY and Skeptic CHALLENGED_BY evidence; SAR, Sentence, Event and Action live here too[圖片]

Proof from local runs on the IBM data

The consortium ring in FalkorDB BrowserA case graph: claims and their evidence
[ring][claims]
Bank vs consortium on the live siteGolden scenario B: the ring one bank holds 37.5% of
[network][scenarios]
Alert queue on real IBM dataCase workspace
[queue][case]

Architecture

[Architecture: Next.js console, MCP clients and card terminals into the FastAPI service and agent worker; Cypher and algo.* into FalkorDB Cloud]

mermaid
flowchart TB  UI[Next.js UI: queue, network weave, case workspace, SAR, trust, approvals, scoreboard] -- REST / WebSocket --> API  API[FastAPI + WebSocket bridge] --> W  subgraph W[Agent worker: LangGraph flow]    O[Orchestrator] --> T[Triage] --> I[Investigator] <--> S[Skeptic] --> R[Reporter] --> A[Auditor]    H[Human approval] --> AR[Archivist]  end  W -- tools --> TOOLS[Tool registry]  MCP[MCP server: 34 tools] --> TOOLS  TOOLS -- Cypher / algo.* --> F[(FalkorDB: consortium, bank_*, case_*, procedures, typology_kb)]  TOOLS -- SQL --> PG[(Postgres KYC)]  W -- events --> RD[(Redis pub/sub)] --> API  W -- LiteLLM --> LLM[Groq free tier: writer qwen3.8-27b + different, larger auditor gpt-oss-120b]

The LLMs plan, choose tools and write prose. Cypher and algo.* do the computation. With no API key the agents run a deterministic policy (labelled as such in the UI), so the system is always runnable.

Graph model

[Graph model: bank graphs, the consortium graph and case graphs, with their labels and relationships]

Full schema: docs/GRAPH_MODEL.md. In short:

  • consortium: Account (hashed id, bank, degrees, PageRank, component, community, motif score, pass-through stats, 16-dim behaviour vector) -[:TRANSFERS]-> Account, a collapsed -[:FLOWS]-> edge per account pair, the identity layer (Person/Company -[:OWNS]->; USES_DEVICE, USES_IP, REGISTERED_AT), Alert, Decision, blackboard Task, case mirrors.
  • bank_<id>: the bank's own Accounts plus ExternalAccount stubs; only transfers touching the bank.
  • case_<id>: Claim -[:SUPPORTED_BY|CHALLENGED_BY]-> Evidence {origin, cypher}, Claim -[:DERIVED_FROM]-> Claim, Action -[:JUSTIFIED_BY]-> Claim, SAR -[:CONTAINS]-> Sentence -[:CITES]-> Evidence|Claim, Evidence -[:SUPERSEDES]-> Evidence, Case -[:HAD_EVENT]-> Event -[:NEXT]-> Event.

Cypher queries and algorithms

Every query the product runs is listed in docs/QUERIES.md, generated from the code. A few that carry the product:

cypher
// echo-proof confidence: count independent origins, not pathsMATCH (c:Claim {id:$id})-[:SUPPORTED_BY]->(e:Evidence)WHERE e.state IN ['active', 'needs_verification']RETURN count(e) AS paths, count(DISTINCT e.origin) AS independent_sources
// money path between two accounts: the primary evidence for a claimMATCH (s:Account {id:$src}), (d:Account {id:$dst})CALL algo.SPpaths({sourceNode:s, targetNode:d, relTypes:['TRANSFERS'],                   maxLen:$max_len, pathCount:$path_count, relDirection:$direction})YIELD path, pathWeightRETURN [n IN nodes(path) | n.id] AS accounts, [t IN relationships(path) | t.txn_id] AS txn_ids
// money at risk: max flow from flagged accounts to the hub (collapsed FLOWS edges)CALL algo.maxFlow({sourceNodes:srcs, targetNodes:tgts, relationshipTypes:['FLOWS'],                   capacityProperty:'capacity', nodeLabels:['Account']})YIELD maxFlow, edges, edgeFlows
// premise check: does this action rest on overturned evidence?MATCH (a:Action {id:$id})-[:JUSTIFIED_BY]->(c:Claim)OPTIONAL MATCH (c)-[:SUPPORTED_BY|DERIVED_FROM*1..5]->(e:Evidence {state:'superseded'})RETURN c.id, collect(e.id) AS stale

Things FalkorDB doesn't ship natively, done in plain Cypher (and said so): degree (precomputed), time-ordered cycles (iterative time-respecting expansion, one query per hop), 3-cycles (motif score), eigenvector centrality (PageRank used instead in SPNSA).

Agents and MCP tools

[The agent pipeline and the live counts on FalkorDB Cloud]

AgentDoes
Orchestratorturns open alerts into blackboard tasks, resets stale claims
Triageclears an alert with a reason, or opens a case graph
Investigatorchooses graph tools (LLM) or follows a learned procedure; writes evidence-linked claims; cites named typologies
Skepticargues the innocent explanation with KYC facts and attribute-sharing context; at most 2 rounds
Reporter + AuditorSAR through the provenance gate; a different, stronger model audits
Archivistsaves the tool sequence that worked (procedural memory), closes the case

Hosted MCP (read-only, no install): claude mcp add --transport http bankweave https://bankweave-api.onrender.com/mcp. It serves 17 read-only tools over Streamable HTTP from the same Render API; every tool runs through GRAPH.RO_QUERY and returns the graph, Cypher, parameters and time. Install lines for Claude Desktop and Cursor, the tool table and a real transcript are in docs/MCP.md.

The full local MCP server (python -m mcp_server.server, stdio or --http PORT) exposes all 34 tools (32 agent tools plus cypher_readonly and list_graphs), including trace_flow, find_hub, find_bridges, money_at_risk, typology_patterns, passthrough_check, clue_expand, hunt_regions, resolve_entity, behavior_neighbors, kyc_lookup, kb_query, echo_check, invalidate_evidence, premise_check, plus cypher_readonly and list_graphs. Every result includes the Cypher it ran.

Claude Desktop config:

json
{ "mcpServers": { "bankweave": {  "command": "/path/to/BankWeave/backend/.venv/bin/python",  "args": ["-m", "mcp_server.server"], "cwd": "/path/to/BankWeave/backend" } } }

The trust layer

[Echo-proof confidence, cascading invalidation and the provenance gate, with measured results]

FeatureFailure it preventsSource
Echo-proof confidencecounting one fact many times because many paths lead to itGraphEcho, arXiv 2609.17695
Cascading invalidation + premise checkacting on beliefs whose evidence was overturnedPACMI, arXiv 2610.05732
Provenance gate + divergence reporta fluent report inventing agreement the evidence doesn't supportActive Provenance Gate, arXiv 2609.31422
  • Every Evidence carries an origin (e.g. attr:D00063, flow:a->b, typ:cycle:a). Confidence is computed over distinct origins; a 200-unit building address is down-weighted. The UI shows "N paths, K independent sources" and the naive figure beside it.
  • Superseding evidence never deletes it. Dependents move along a validity lattice (active < needs_verification < historical_only < superseded); actions resting on stale evidence need an explicit override note to approve.
  • The SAR is drafted from a closed bundle. Code checks run first (cited ids exist, are active, belong to the case); a different model then judges entailment per sentence. It publishes only at provenance fidelity >= 0.95, after at most 3 repairs; otherwise it writes a divergence report with the Investigator's and Skeptic's positions side by side. A recommendation can't rest on a claim below 0.5 echo-proof confidence.

Memory and coordination (Track 02)

  • Shared state: the blackboard is Task nodes; claiming is one atomic query (verified with 6 concurrent workers, each task done exactly once).
  • Kill and resume: workers heartbeat; stale claims are reset and any worker continues from the graph. Demo control has a Kill button; the case page has "Resume from graph".
  • Episodic: each case's Event timeline (HAD_EVENT, NEXT), replayable in the UI.
  • Semantic: claims and evidence with validity states and history (beliefs_as_of).
  • Procedural: the procedures graph stores tool sequences that led to approved outcomes.
  • Cross-case recall: claim summaries mirrored into the consortium (Account <-[:ABOUT]- Claim).
  • Isolation: per-bank and per-case graphs in one FalkorDB instance.

Evaluation

[Measured results: E2, E1, E7 and FalkorDB Cloud timings]

E1: alert triage (IBM HI-Small, 20-bank consortium)

4,000 alerted accounts from the later half of the period (129 illicit, base rate 3.2%); weights and thresholds from the earlier half only.

MethodPrecisionRecallF1Accounts escalatedAlerts not escalated
Rule-based: escalate everything3.2%100.0%0.0624,0000.0%
Rules without the graph (≥3 rules)33.3%7.8%0.1263099.2%
BankWeave graph score, hand weights (no labels)18.9%14.0%0.1619597.6%
BankWeave graph score, calibrated on dev split17.8%24.0%0.20517495.7%

eval/results/E1_alert_triage.json, commit 49f9388, HI-Small_Trans.csv (20 banks, graph prefix 'ibm_')

E2: no bank can see the ring alone

Across 36 laundering groups that span banks (on average 3.5 banks each), the best-placed single bank holds 43.8% of the ring's accounts and holds a whole ring in 0.0% of cases. It does observe 95.7% of the laundering transfers, but most counterparties are other banks' customers it can't investigate. The consortium graph holds 100% of every ring.

eval/results/E2_consortium_vs_single_bank.json, commit 49f9388, HI-Small_Trans.csv (20 banks, graph prefix 'ibm_')

E3: hunt mode (SPNSA reproduction, k=200, r=1)

Seed feedSubgraph accountsIllicit ratioPaper (HI-Small)
Random (mean of 10)2503.4%2.4%
Degree imbalance33617.0%13.7%
Motif-coherent (paper parameters)2807.5%22.6%
Motif, no degree penalty (post-hoc ablation)37811.6%—

Base rate in this graph: 2.5%. We did not reproduce the paper's ranking: with its parameters the degree penalty inverts the motif score on our 20-bank slice (account-level AUC 0.3743, vs 0.638 without the penalty), so degree imbalance wins here. All feeds beat random.

eval/results/E3_spnsa_hunt.json, commit cc7037a, HI-Small_Trans.csv (20 banks, graph prefix 'ibm_')

E4: pass-through matching

708 accounts flagged; 4.8% of them illicit vs a 2.5% base rate. Chain-deduplicated value: 74,961,854,871 (IBM amounts are in many currencies, so this is a raw sum, not a USD figure).

eval/results/E4_passthrough.json, commit 154672b, HI-Small_Trans.csv (20 banks, graph prefix 'ibm_')

E5: clue-guided recovery

From 2 clue members of 12 laundering groups: best round 2 reaches precision 33.3%, recall 3.4%. This is weak; the graph-signal version (no GNN) mostly finds the clue's immediate partners.

eval/results/E5_clue_expansion.json, commit 706ae01, HI-Small_Trans.csv (20 banks, graph prefix 'ibm_')

E6: trust layer on the agents' real cases

Over 28 cases the agents built from the live IBM slice:

  • Echo: 27.8% of 510 evidence items repeated an origin already seen; 37 of 101 claims had more supporting paths than independent sources. Mean confidence 41.7% echo-proof vs 48.8% counting paths.
  • Provenance gate: 25 of 28 SARs published, 3 ended as divergence reports; mean provenance fidelity 0.988; 26 needed at least one repair round.
  • Cascading invalidation: affected-node recall 100.0% and precision 100.0% over 50 scripted dependency graphs.
  • Stale approvals: 0 actions approved on overturned evidence without an override.

eval/results/E6_trust_layer.json, commit f3cff38, IBM_SLICE_Trans.csv (6 banks, graph prefix '')

E7: speed (one local machine)

Consortium graph: 28,307 accounts, 1,315,597 transfers.

OperationMedian95th percentile
expand neighborhood3.1 ms6.1 ms
typology patterns12.5 ms674.0 ms
cross bank links0.6 ms0.9 ms
shared identity0.7 ms0.9 ms
behavior neighbors0.4 ms1.0 ms
passthrough check2.8 ms10.5 ms
triage signals hub accounts1.1 ms2.3 ms
triage signals regular accounts15.4 ms58.0 ms
pagerank consortium57.5 ms
wcc consortium39.5 ms

eval/results/E7_performance.json, commit b8a1292, ibm_

Deployment (live)

PieceWhereHow
Graph databaseFalkorDB Cloud, AWS ap-south-1seeded with scripts/make_slice.py + scripts/seed_all.sh (real IBM slice: 24,990 transactions, 6 banks)
API + agent workerRender web service bankweave-api (Singapore)root Dockerfile; created with the Render CLI; agents run in the API process
Live eventsin-process event bus (no Redis needed on a single service)backend/app/events.py
KYC PostgresNeon (aws-ap-southeast-1)python -m app.services.kyc_synth --postgres-only
UIVercel bankweave.vercel.appvercel deploy --prod from frontend/
LLMsGroq free tier (writer qwen/qwen3.8-27b, auditor openai/gpt-oss-120b), OpenRouter free models as fallbackbackend/agents/llm.py

Render's free plan sleeps after 15 minutes idle; the first request wakes it (about a minute) and the agents resume from the graph blackboard. A GitHub Actions job pings /health every 10 minutes to keep it warm, and while it wakes the main pages stay available from captured real API responses (scripts/capture_snapshots.py), labelled on screen.

FalkorDB Cloud's free tier has 100 MB and noeviction. Since 2.0 the graphs load in compact form (KYC_ARGS=--compact, no unused txn_id edge index, no id indexes on ~100-node case graphs), /health reports used memory, and scripts/cloud_reseed.sh rebuilds the cloud graphs while keeping pinned cases. Old case graphs are pruned automatically only when CAPACITY_PRUNE=true.

Optional environment variables: OPENSANCTIONS_API_KEY (live sanctions screening), HELIUS_API_KEY (Solana wallet lookups), EVM_RPC_URL, OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS (export agent spans to Langfuse, Jaeger or any OTLP collector), DOSSIER_SIGNING_KEY (hex Ed25519 seed for dossier signatures), PINNED_CASES, CAPACITY_PRUNE.

Run it locally

Prebuilt API image: docker pull ghcr.io/lsudoko/bankweave-api:latest (published on every release).

bash
docker compose up -d                       # FalkorDB (6390, Browser 3030), Redis (6391), Postgres (5440)cp .env.example .env                       # add GROQ_API_KEY (free) for LLM agents (optional)cd backend && uv sync && cd ..scripts/seed_all.sh                        # sample dataset -> bank graphs, consortium, identity, precomputecd backend && uv run python -m app.services.baseline && uv run uvicorn app.main:app --port 8000cd frontend && pnpm install && pnpm dev -p 3001

Open http://localhost:3001, go to Demo control and press Start agents (the agents begin triaging alerts and opening cases; the dashboard updates live).

IBM data for evaluation: scripts/download_ibm.sh (Kaggle token) or the public mirror hf.co/datasets/eexzzm/IBM-Transactions-for-Anti-Money-Laundering-HI-Small-Trans, then GRAPH_PREFIX=ibm_ scripts/seed_all.sh data/raw/HI-Small_Trans.csv --top-n 20 and GRAPH_PREFIX=ibm_ eval/run_all.sh.

Tests: cd backend && uv run pytest (55 tests, against the local FalkorDB).

Hardware: the ESP32 terminal in hardware/wokwi/ runs in Wokwi and posts card taps over HTTPS to POST /hardware/pos-tap (see its README).

Data

  • IBM Transactions for Anti-Money Laundering (AMLworld, HI-Small), the standard labelled AML benchmark, which IBM generated with a multi-agent world model because real bank transactions cannot be published: 5,078,345 transactions, 5,177 labelled laundering transfers, 8 laundering typologies. Labels are used only in eval/. The live instance runs a 6-bank slice of it (3,024 accounts, 24,990 transfers).
  • Identity layer (backend/app/services/kyc_synth.py, seed 42): people, name variants, devices, IPs, addresses and a Postgres KYC table. Generation rule, reported so leakage can be audited: attempt members share a device with P=0.40, innocent accounts with P=0.03; 6% of innocent accounts share a family address/IP; one 200-unit building (A-77) houses about 15 accounts including some attempt members.
  • Sample dataset for local setup (data/demo, seed 42): IBM-format transactions with innocent background and 16 cross-bank laundering schemes in the 8 IBM shapes.
  • No personal data of real people anywhere, as AML compliance requires for a public project.

AI tools disclosure

Built with help from Claude Code (Anthropic), which wrote much of the code under the team's direction; every module was reviewed and is understood by the team. At runtime the agents use free-tier LLMs through Groq (writer qwen/qwen3.8-27b, auditor openai/gpt-oss-120b, a different and larger model from a different vendor), with OpenRouter free models as fallback.

Scope and design notes

  • Data is IBM's AMLworld benchmark plus a documented identity layer; connecting a bank's own feed means loading it in the same graph model (scripts/seed_all.sh takes any IBM-format CSV).
  • Without IBM's Patterns file, laundering attempts are approximated as connected groups of laundering transfers (stated in each result file).
  • Clue-guided recovery uses graph signals, not the paper's GNN.
  • Consortium ids are salted hashes. The ECDH-PSI handshake is real X25519 arithmetic; in this deployment both banks' sides run in one service, and in production each side runs at its own bank.
  • The enclave, card terminals and VaultKey run as software device twins (the ESP32 in Wokwi) with real cryptography (HMAC, SHA-384 PCRs, ECDSA P-384/P-256, Ed25519, X25519); physical HSMs, terminals and keys plug into the same endpoints. The EMV application cryptogram (9F26) is an HMAC.
  • The SAR export is FinCEN-style XML for review, not a BSA E-Filing submission.
  • Sanctions screening uses live OpenSanctions with an API key and a bundled sample list without one; name-only matches are confirmed with date of birth or country.
  • The threshold explorer on the Evaluation page runs on the live slice, which overlaps the model's training data, so its numbers are optimistic; the held-out result is E1's table.

License

MIT, see LICENSE.

來源:README.md,提交 f6259e9

工具

17

engine_overview

Health and size of the whole system: FalkorDB memory/version, graphs (banks, cases), consortium size (accounts, banks, transfers) and the alert queue by status (open / case / cleared). Call this first to orient yourself. FalkorDB features: INFO memory, GRAPH.LIST, GRAPH.RO_QUERY aggregations.

無需輸入參數。

list_graphs

List every FalkorDB graph BankWeave keeps, grouped by kind: the consortium (cross-bank, hashed), one graph per bank (that bank's partial view), one graph per case, the typology knowledge base. Use graph_schema(graph) for labels, relationship types and indexes.

無需輸入參數。

graph_schema

Schema of one graph: node labels, relationship types, property keys and indexes with their kind (RANGE, FULLTEXT, VECTOR). graph: 'consortium', 'bank_<id>', 'case_<id>' or 'typology_kb'. FalkorDB features: db.labels, db.relationshipTypes, db.propertyKeys, db.indexes.

輸入參數graph

list_cases

List investigation cases (newest first) with status, title, seed account, number of alerts/accounts, the banks involved and whether its case graph is loaded. Use a case id with get_case. FalkorDB features: GRAPH.RO_QUERY over the consortium graph.

輸入參數limit

get_case

Everything about one case from its own case graph: header, claims (each with naive vs echo-proof confidence, paths vs independent_sources, state, supporting/challenging evidence ids), evidence (kind, origin, state active/needs_verification/superseded, summary), proposed and approved actions with the claims that justify them, and SAR status. case_id like 'C-44c08392'. FalkorDB features: one graph per case, GRAPH.RO_QUERY.

輸入參數case_id必填max_evidence

explain_claim

Why a claim has the confidence it has (GraphEcho echo-proof scoring). Groups supporting and challenging evidence by ORIGIN: many paths that lead back to the same origin count once. Returns paths vs independent origins, naive (path-counting) vs echo-proof confidence, each origin group with its multiplicity and weight, which origin kinds were never explored, and the derived-claim / evidence chain with the Cypher each evidence item ran. Pure read: the score is recomputed in memory, nothing is written. FalkorDB features: GRAPH.RO_QUERY, variable-length DERIVED_FROM traversal.

輸入參數case_id必填claim_id必填

account_network

An account's cross-bank neighbourhood in the consortium graph: its scores (pagerank, motif score, community, WCC component size, pass-through pairs), shared identity (device, IP, address with how widely each is shared), cases and alerts on it, counterparties held at OTHER banks (count and volume) and its bounded 1-2 hop neighbourhood with the banks it spans. A bank alone only sees its own side of these links. FalkorDB features: GRAPH.RO_QUERY, bounded undirected expansion.

輸入參數depthaccount_id必填

trace_money_path

Shortest money paths from one account to another, hop by hop with transaction ids, amounts and the bank of every account on the path, so you can see the money cross banks. Without case_id it searches the consortium along outgoing transfers; with case_id it searches that case graph in both directions. No path = no claim. FalkorDB features: algo.SPpaths.

輸入參數dst必填src必填case_idmax_lenpath_count

find_rings

Candidate laundering rings: communities of accounts that trade mostly among themselves, found by label propagation on the transfer graph. Cross-bank rings (members at more than one bank) come first, since no single bank can see them whole. Pass account_id to return only the ring that contains that account. FalkorDB features: algo.labelPropagation.

輸入參數graphlimitmax_sizemin_sizeaccount_id

top_hubs

Accounts where money pools: PageRank over TRANSFERS, highest first, with bank ids. graph: 'consortium', 'bank_<id>' or 'case_<id>'. FalkorDB features: algo.pageRank.

輸入參數graphtop_k

connected_components

Weakly connected components of the transfer graph (largest first): size, number of banks, a sample of members, plus how many components are tiny 'islands' that triage clears instantly. graph: 'consortium', 'bank_<id>' or 'case_<id>'. FalkorDB features: algo.wcc.

輸入參數graphlimit

similar_accounts

Accounts whose behaviour (activity, amounts, timing, degree profile) is closest to this one, by cosine distance over Account.behavior_vec (lower = more alike), with their banks. Useful to find mule accounts that act like a known one at other banks. FalkorDB features: HNSW vector index, db.idx.vector.queryNodes.

輸入參數kaccount_id必填

search_customers

Fuzzy name search over customers (Person) or businesses (Company) across all banks, with the accounts and banks each one owns. Tokens are OR-ed, so partial names work. FalkorDB features: full-text index, db.idx.fulltext.queryNodes.

輸入參數kname必填label

list_alerts

The alert queue with counts by status. status: 'open', 'case' (escalated into a case) or 'cleared'; omit for all. Each alert has its rule, reason, account, bank, case id and the recorded clearing reason. Use an alert id with triage_alert. FalkorDB features: range indexes on Alert.status, GRAPH.RO_QUERY.

輸入參數limitstatus

triage_alert

Why an alert was cleared or escalated into a case. Returns the alert, the triage decision and its reason, the graph signals the triage agent recorded (component size, motif score, cross-bank counterparties, typologies, shared identity, prior cases), and a LIVE re-check: the account's weakly connected component size (islands smaller than the configured threshold clear instantly) and its motif score components. FalkorDB features: algo.wcc, GRAPH.RO_QUERY.

輸入參數alert_id必填

typology_guidance

Laundering typology guidance (e.g. 'fan-out then fan-in through mules', 'structuring below reporting threshold') from BankWeave's typology knowledge graph, with citations. Abstains when nothing matches well. FalkorDB features: full-text index on the typology_kb graph.

輸入參數question必填

run_readonly_cypher

Last resort: run your own read-only Cypher on one graph. Runs as GRAPH.RO_QUERY (the engine rejects writes) after a guard: one statement, no CREATE/MERGE/SET/DELETE/REMOVE/ DROP/FOREACH/LOAD CSV, CALL only for algo.* and the db.* read/index-query procedures, LIMIT appended when missing, at most 200 rows, 10 s timeout. graph: 'consortium', 'bank_<id>', 'case_<id>' or 'typology_kb' (see graph_schema for labels and properties).

輸入參數graphlimitcypher必填

版本歷史

1
  1. v3.0.1最新Oct 18, 2026

評分

已滿足適用檢查項的 100%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分