Douala — Ocheso’s API is the service behind its tournaments, its live games and Ocheso Agents, the human-like chess opponents that other platforms hire through an API. It is written in Python and hosted on Vercel. Its database is Postgres on Supabase, in Ireland. Until 22 October 2026, the API itself ran in Vercel’s Washington region.
So every time the API asked the database a question, the question crossed the Atlantic, and so did the answer. A single request often asks several. An agent’s move took between 1.1 and 1.7 seconds from request to reply, and most of that was the ocean. Every tournament request paid the same tax, less visibly.
Move the code to the data
We moved the API to Vercel’s Dublin region, next to the database. Measured end to end from our own machine, an agent’s move now takes 0.5 to 0.7 seconds, and about 0.45 seconds of that is the network between that machine and Dublin. Requests that read from the database went from about a second to between 0.5 and 0.9 seconds. Dublin is also nearer than Washington to the players we build for in Africa.
Don’t make a request wait for what it won’t use
The move fixed the steady cost. It didn’t fix the first request after a quiet spell, which could take around eight seconds.
The cause was weight. The API was one serverless function, and it carried everything the agents need: the Stockfish chess engine (98 MB), the Maia models that predict the moves people actually play, and the numerical libraries behind them. That came to 319 MB, past the size our host ships with a function, so the excess was installed each time the function started cold. A tournament page could wait for chess engines it would never use.
We split the API into two functions on the same domain:
- Core serves tournaments, play and accounts. Nothing heavy is even in its folder, and it weighs 14.9 MB.
- Agents serves the opponents and carries the engines.
A test checks that every route lives in exactly one function, and that the light one imports nothing heavy, so the split can’t quietly wear away.
Six residual blocks don’t need 73 MB
The agents function was still 260 MB, over the 225 MB line. The largest single piece was onnxruntime: 73 MB of native libraries to run Maia, a neural network of six residual blocks that reads an eight-by-eight board.
We rewrote Maia’s forward pass in numpy, using weights extracted once from the same model files, and compared the two before switching:
- the largest difference in any of the network’s outputs was 0.000012;
- the top move was the same in 270 of 270 test positions, across all nine rating bands;
- re-analysing 300 held-out positions, all 4,800 sampled decisions were identical.
Each evaluation takes 0.9 milliseconds. The agents function now ships whole, at 134 MB, and nothing is installed at a cold start. The original runtime stays in the repository as the reference the tests compare against.
The numbers
BeforeAfter
An agent’s move
Database reads
First tournaments request
| Measure | Before | After |
|---|---|---|
| An agent’s move, end to end | 1.1–1.7 s | 0.5–0.7 s |
| Requests that read the database | about 1.0 s | 0.5–0.9 s |
| First tournaments request after a deploy | 8.4 s | 1.3 s |
| First agents request after a deploy | not measured | 2.5 s, including starting Stockfish |
On the server, the engine’s own time per move is 0.23 to 0.6 seconds.
The same rule, twice
None of this is new. Run code next to its data, and ship only what a request needs. Both are now standards every Blacksilver company works to. Our second company made the same choice in its first week, with its database in Frankfurt beside the worker that writes to it.
None of these changes altered what an agent decides. That was the condition for shipping them.
Sources
Every figure in this post comes from our own engineering records.
- Ocheso API change log, 22 October 2026: “Run the API in Dublin, beside the database”; “Split the API into two functions: core and agents”; “Maia on numpy”.
- Ocheso build notes, 22 October 2026.
- Our second company’s deployment notes, August 2026.
Corrections
If we get something wrong, we correct it here and say what changed.