eqlx.org / eqlx-aml
Python library · MCP server · v0.1 · Apache-2.0
Find money-laundering patterns. Show the rows that prove them.
eqlx-aml reads a file of money transfers and finds the shapes launderers use to hide where money came from. Every alert names the accounts, the dates and the exact rows, and AI agents use it read-only.
What goes in, what comes out
Nobody can read millions of transfers by hand, and a language model left alone with a large table miscounts. So the agent decides what to look at; the tool does the counting.
You give
- a file of transfers
- who paid whom, when, how much
- the patterns to look for
- your limits, or the defaults
eqlx-aml computes
- every match of each written rule
- the accounts in each match
- the rows that form it
- where the money went next
You get
- alerts, one per match
- accounts, dates and totals
- the exact rows as evidence
- the same answer every time
No model inside. Banks and payment companies must report suspicious transfers (in Türkiye, to MASAK); an investigator has to be able to point at the evidence.
One alert, start to finish
The made-up sample file that ships with the tool: 4,034 transfers between 452 accounts, 5 January to 1 February 2026, all in EUR.
1You give the file
One row per transfer. Two of the 4,034 rows matter here; nothing marks them.
| Row | Time | From | To | Amount |
|---|---|---|---|---|
| 1758 | 16 Jan 23:56 | ACC-0245 | ACC-0025 | 1,327.80 |
| 1759 | 17 Jan 00:00 | SG-A | SG-M0 | 7,000.00 |
| 1760 | 17 Jan 00:00 | ACC-0349 | ACC-0223 | 220.31 |
| … 166 rows … | ||||
| 1927 | 17 Jan 23:52 | ACC-0120 | ACC-0007 | 337.78 |
| 1928 | 18 Jan 00:00 | SG-M0 | SG-B | 6,900.00 |
| 1929 | 18 Jan 00:33 | ACC-0337 | ACC-0000 | 648.17 |
2You ask for a pattern
Here scatter-gather, with its default rule.
| Pattern | scatter-gather |
| A pays several accounts, each then pays the same B | at least 3 |
| All of it within | 7 days |
| Skip middle accounts busier than | 50 transfers |
aml scan demo.csv --pattern scatter_gather
3It finds the shape
SG-A pays five accounts on 17 January. Each pays SG-B a day later.
4It lists the rows
Ten transfers, in pairs: money in from SG-A, money out to SG-B.
| Middle account | In, 17 Jan | Out, 18 Jan |
|---|---|---|
| SG-M0 | 7,000 row 1759 | 6,900 row 1928 |
| SG-M1 | 7,050 row 1772 | 6,950 row 1937 |
| SG-M2 | 7,100 row 1789 | 7,000 row 1950 |
| SG-M3 | 7,150 row 1803 | 7,050 row 1963 |
| SG-M4 | 7,200 row 1827 | 7,100 row 1975 |
5Where the money ended up
Added up from the ten rows, in EUR.
6Trace it back from SG-B
Only along payments made before the money arrived.
| 1 step back | SG-M0 … SG-M4 |
| 2 steps back | SG-A |
| Transfers on the trail | 6 |
aml trace demo.csv SG-B --backward
What comes back
"SG-A sent money through 5 different accounts that each passed it on to SG-B within 7 days"
Accounts SG-A, SG-B, SG-M0, SG-M1, SG-M2, SG-M3, SG-M4 · From 17 Jan 00:00 to 18 Jan 08:00 · Total moved 70,500.00 EUR
rows 1759, 1772, 1789, 1803, 1827, 1928, 1937, 1950, 1963, 1975
Every figure above is the tool's output on this file. The same scan returns one more scatter-gather: three ordinary accounts that happen to form the shape. An alert is a reason to look.
What it looks for
Seven patterns from FATF typologies and monitoring practice. Each is an exact rule; the defaults look within seven days.
Loop
Money returns to where it started.
Moderate signalScatter-gather
A splits money across middle accounts; each pays the same B.
Strong signalGather-scatter
One account collects from several and pays out to several.
Weak to moderate signalFan-out and fan-in
One account pays many, or is paid by many. So does every payroll and shop.
Weak signal on its ownPass-through
An account sends on 90 to 100 % of what it received, within a day.
Weak signal on its ownStructuring
Several deposits, each just under a reporting limit you set.
Depends on the limit you set (not in the IBM data)Accounts with more than 50 transfers in the week are not followed as middle accounts of loops and scatter-gather. It is a setting.
How an agent uses it
Point the MCP server at one folder of transfer files. The agent can read and analyse them, and nothing else.
pip install "eqlx-aml[mcp]"
claude mcp add aml -- aml mcp --root /path/to/transfers
A real run
Claude Code got only this server and the sample file above, and was asked in Turkish to separate suspicious activity from ordinary business.
How it was tested
Two questions: does each detector do exactly what its rule says, and does that rule catch planted laundering?
1. Exactly what the rule says
2. On IBM's public laundering data
A simulated world of banks, people and companies (Altman et al., NeurIPS 2023). No real people, so it can be used openly. Every detector ran with its default settings.
Did it find the planted attempts? 140 of the 144 big enough to match a rule.
The three loops it missed run through a busy account or have payments out of time order: what the rule leaves out.
How many alerts are real? It depends on the shape.
Share of each detector's alerts that are about an account taking part in laundering. Only 1.2 % of all accounts do: the black line is what picking accounts at random would give.
Stricter settings give fewer, better alerts and miss small schemes. The full table of settings is in the repository, and the script reproduces it from your own copy of the data.
What it does not do
pip install "eqlx-aml[mcp]"
aml sample demo.csv # synthetic transfers with hidden patterns
aml scan demo.csv