1. The headline finding
There is no open-source platform that does this. Custodial vaulting plus an order book plus title transfer for physical collectibles does not exist as a forkable project. Every operator running this model runs closed, proprietary software.
That is worth stating plainly because it reframes the question. "Fork the platform" is not available. What is available is forking the hard parts individually — and some of those parts are genuinely worth taking rather than writing.
Who already runs this model
The commercial operators confirm the model works and that none of it is open:
| Operator | What they do | Source |
|---|---|---|
| PWCC Vault | Long-running trading-card vault. Explicitly facilitates trading and transfers between vault clients — the same zero-movement settlement model. Free storage above a value threshold, insurance included. | Closed |
| Arena Club | Grading plus vaulting plus a marketplace where vaulted slabs are bought, sold and traded instantly. Accepts PSA, BGS, SGC, CGC and CSG slabs alongside its own. | Closed |
| eBay Vault, Goldin, Fanatics Collect | Vault-and-trade offerings attached to existing marketplaces. | Closed |
The one nominally adjacent open-source project — a self-hosted collectibles vault for comics and figures — is a personal inventory tracker with valuation lookups. It has no order book, no ledger, no custody model and no title transfer. It solves a different problem that happens to share a noun.
2. The pieces that are forkable
Decompose the product and each layer has mature open-source options. Licences below were read from each repository, not recalled — the difference between MIT and GPL decides whether a fork is viable for a commercial product at all.
| Layer | Project | Language | Runs on | Licence | Call |
|---|---|---|---|---|---|
| Ledger | tigerbeetle/tigerbeetlePurpose-built double-entry financial database. Deterministic execution, strict serializability, accounts that cannot go negative — enforced by the database, not by application code. |
Zig clients: Go, Java, Node, Python, .NET |
Single static binary own replication (VSR), no Postgres underneath |
Apache 2.0 | Adopt. Highest-value fork here. |
formancehq/ledgerProgrammable double-entry ledger. Immutable tamper-evident log, multi-asset, multi-ledger, Numscript DSL for modelling money movement. |
Go 1.26 | PostgreSQL via pgx; Docker image published |
MIT | Strong alternative. Easier to operate, less extreme guarantees. | |
| Matching engine | mzheravin/exchange-coreOrder matching plus risk control and journaling. ~2.6k stars, 972 forks. |
Java LMAX Disruptor, Maven |
JVM, in-memory event-sourced journal |
Apache 2.0 | Capable, but the layer least worth forking — see below. |
enewhuis/liquibookLow-level order matching components rather than a service. |
C++ | Library, embed it | None stated | No licence file in the repo. Hard no for a commercial fork. | |
| Warehouse | openwms/org.openwmsExtensible WMS with material flow control: locations, transport orders, put-away and picking strategies. |
Java Spring Boot, Maven |
Microservices RDBMS + message broker |
Apache 2.0 | Adopt. Enormous, boring, solved. |
| Storefront, identity, payments | medusajs/medusaHeadless commerce. Modular monorepo — take the auth, customer and payment modules without the storefront. |
TypeScript Node |
PostgreSQL + Redis | MIT | Good fit for accounts, KYC surface and checkout. |
vendure-ecommerce/vendureHeadless commerce, GraphQL-first, plugin architecture. |
TypeScript 5.8 NestJS, TypeORM, GraphQL 16 |
PostgreSQL / MySQL | GPL | Copyleft. Check before adopting, not after. |
Languages and datastores were read from each repository's build manifest —
build.zig, go.mod, pom.xml, package.json —
not recalled. Licences were read from the licence file at repository head. Both can change;
re-check before committing to a fork.
3. The recommendation
Write the matching engine
Counter-intuitive, but the engine is the cheapest layer here. Ours is a few hundred lines with price–time priority, partial fills, reservations and no self-crossing, and it is covered by tests. exchange-core is built for millions of orders per second on fungible instruments — we match slabs, in a market where a busy day is thousands of trades. Adopting it would mean running a JVM service to solve a problem we do not have.
Fork the ledger
The opposite call. A correct double-entry ledger under concurrency is genuinely hard, and getting it wrong is the failure mode that loses customer money silently. TigerBeetle enforces balance and non-negativity in the database, which no amount of application-level discipline matches. Our journal has the right shape — accounts, instruments, balanced entries — which makes it a migration, not a rewrite.
Fork the warehouse
Bin addressing, pick tasks, cycle counts, material flow. It is thousands of hours of unglamorous work that has been done well and permissively licensed. The only part worth writing ourselves is the custody state machine, because that is where our specific invariant lives: an item is tradable only when vaulted and unreserved.
The general rule this follows. Fork where correctness is hard and the domain is generic — ledgers, warehouses, payments. Write where the domain is specific and the code is small — the custody state machine, the SKU identity model, the swap semantics. The parts of TCG Keepr that would be hard to buy are exactly the parts that are cheap to write, and vice versa.
4. What migrating the ledger would involve
Our journal already uses the account and instrument shape these systems expect, which is why this is tractable:
// ours
{ account: "holder:usr_4f2a17", instrument: "ASSET:itm_c8a1f9", dr: 1 }
{ account: "cash:usr_9b71c4", instrument: "USD", dr: 42945000 }
// TigerBeetle: accounts are typed by ledger id, transfers are the entries
account { id, ledger: USD | ASSET, code: holder | cash | revenue, flags }
transfer { debit_account_id, credit_account_id, amount, ledger, code }
// The asset leg and the cash leg become linked transfers in one atomic
// batch — the same all-or-nothing property our tx() wrapper provides, but
// enforced by the database instead of by a JSON snapshot and a try/catch.
Two things would have to be rethought rather than mapped. The hash chain is ours and would stay ours — these ledgers give immutability and tamper-evidence, but the chained digest that lets an outside party verify history against a head they already hold is an application concern. And non-fungible assets are an unusual fit: a ledger built for currency balances has to model one specific slab as a one-unit account, which works but wants care.
What this page is not. A decision to migrate today. The in-browser engine is a complete, tested implementation of the semantics, and it is the right thing to keep while the semantics are still moving. This is the record of what we looked at, what the licences actually say, and which way we would jump when a real backend is written — so that decision gets made from research rather than from whatever is top of mind that week.
The engine this replaces is already running
Matching, reservations, the double-entry journal and the hash chain are live in the terminal, in about a thousand lines, with 119 assertions behind them.