Macrae
Updated 2026-10-08 21:10 CEST (Central European Summer Time) · status: live on Cloudflare · live traces, costs and "Frankenstein" in progress
A voice agent for the Jungwirth group at the IOCB (Institute of Organic Chemistry and Biochemistry of the Czech Academy of Sciences, Prague). You chat with it, by voice or by typing, and it answers from the group's papers with citations. When you start a task, it does real computational chemistry on cloud hardware and shows you every paper it read and every calculation it ran.
1 · The pieces
Everything public sits behind one Cloudflare Worker (a small program on Cloudflare's network) at one
address. The Worker serves the page and hands the browser a short-lived voice session. It forwards
/api calls to the backend, adding a secret header the browser never sees. The backend is a
Cloudflare Container, owned by a Durable Object: a named Cloudflare object that keeps exactly
one instance and decides when it sleeps. The backend answers paper questions from its own index and runs tasks
as agent-runner flows. Harbor starts each agent step in a sandbox on Modal and keeps the full
trace. Runs, traces and the paper index are mirrored to R2, Cloudflare's object storage.
Abbreviations in the diagram: API = application programming interface · LLM = large language model · RAG = retrieval-augmented generation (search the papers first, answer only from what was found) · BM25 = "Best Match 25", a keyword-ranking formula · vCPU = virtual processor core · GiB = gibibyte · CPU / GPU = central / graphics processing unit · PySCF = Python-based Simulations of Chemistry Framework · BFF = BayesicForceFields (Bayesian force fields, the group's code) · GROMACS = GROningen MAchine for Chemical Simulations · ATIF = Agent Trajectory Interchange Format (Harbor's trace file).
2 · Status
As of 2026-10-08, 21:10 CEST.
| state | what | when |
|---|---|---|
| live | Site on the Worker "macrae": the page, the /api
proxy and /voice/signed-url. | 2026-10-08 |
| live | Page: dark/light chat with Jarvis, the macrae orbit logo, and a right panel "Tasks & runs" (tasks, live run trace, recent runs). | 2026-10-08 |
| live | Backend: one Cloudflare Container (standard-1: ½ vCPU, 4 GiB). It sleeps after 2 h unless a run is going, and syncs its state (runs, Harbor traces, paper index) to the R2 bucket "macrae-data". Health: ok. Modal: connected. | 2026-10-08 |
| live | Voice: ElevenLabs agent "macrae", voice "Jarvis", Claude
Sonnet 5.5 through ElevenLabs. Server tools search_papers, start_task and
run_status are webhooks to the Worker. Page tools: show_citations,
open_run. | 2026-10-08 |
| live | AWS (Amazon Web Services) is no longer used: the Cloudflare Container replaced it. | 2026-10-08 |
| verified | A real Claude Code agent run on Modal through Harbor
(local test). It computed the Na+–water binding energy with DFT (density functional theory) in PySCF:
B3LYP functional (Becke 3-parameter, Lee–Yang–Parr), def2-TZVP basis set (triple-zeta valence with polarisation), counterpoise correction. Result:
−25.5 kcal/mol at 2.2 Å, reward 1, 34 trace events (search, cite, read, calc, write, result). It took 9 min: 170 s for the first image build on Modal, the agent installing PySCF itself, and a 4-min sleep. That is to be optimised. | 2026-10-08, 20:18 |
| verified | Tests: 277 Python tests and 57 Node tests pass. They cover the Worker → container path, the R2 sync, and draining runs on restart. | 2026-10-08 |
| in progress | First cloud run (container → Modal): the K+ small calculation. | started 21:02 |
| in progress | Two BFF research tasks, approved by the owner, being turned into clickable tasks (section 6). | started 20:34 |
| in progress | v2: live traces (the sandbox streams each step), costs in money (section 5), a planner that decides what to run and where (shown first in the trace), and "Evolution": lessons distilled from each trace feed the next run, plus a tools library and a fine-tuning dataset export. | started 20:43 |
| in progress | Frankenstein (v3): a capability lifecycle (create → test → install → use again) with fixed authority, and raw Harbor traces downloadable from the page (section 7). Queued after v2. | queued 21:08 |
| in progress | Video: a 90 s film celebrating Pavel Jungwirth's research, plus a 20–25 s accelerated demo. ElevenLabs music and narration. | started 21:07 |
| waiting on owner | Paper PDFs (Portable Document Format). Until they arrive the RAG index is empty, and Jarvis says the papers here don't cover the question. | open |
| waiting on owner | A fresh Claude API key to replace the current one. | open |
3 · What happens when you…
- By voice: the mic button asks the Worker for a signed URL (a short-lived link; URL = uniform resource locator), and the ElevenLabs session starts in the
browser. Typed, outside a call: the text goes straight to
POST /api/search. - The voice agent calls
search_papers. That webhook goes to the Worker, then through the Durable Object to the container. - RAG returns the best passages, numbered
[1] [2], each with title, authors, page and DOI (Digital Object Identifier). - Jarvis answers only from those passages and names the source ("Košťál 2026, page 3"). With no PDFs indexed yet, it says the papers don't cover the question.
show_citationsadds numbered source chips under the answer. Clicking[n]opens that source's card.
POST /api/tasks/{id}/startreturns arun_id. Jarvis posts a run chip in the chat, and the panel opens the live trace.- v2 A planner first decides what to run and on which hardware, and the page shows that decision as the first card.
- Script steps pull paper passages from RAG. Agent steps run in Modal sandboxes through Harbor.
- The page polls
/api/runs/{id}/eventsevery 1–2 s. Each tool call becomes a timeline row (📄 read, 🔎 search, 🧮 calc, ✍️ write, ✅ result). - A
check:verifies the output (e.g.result.jsonhas numbers) and gives a reward. The container pushes the run's state to R2 at every step. - When the run ends, Jarvis posts the outcome with the papers it cited.
4 · Where the traces are
A trace is everything one run did: every message, tool call and result. The same trace appears in three places, from the most readable to the most raw.
| where | what you find | how to get it |
|---|---|---|
| 1 · The page timeline | One row per event (status, read, search, calc,
write, think, cite, result, error), with a short
human title, details, and source cards. The server builds it from the run's state.json, the step
logs and each Harbor trial. While a step is still running it reads the live claude-code.txt
instead. |
Panel "Tasks & runs" → a run; or GET /api/runs/{id}/events |
2 · R2 bucket macrae-data |
state/runs/<run_id>/: the flow's state.json, step logs, outputs.state/jobs/<run_id>/…: Harbor trial folders, i.e. the full agent traces.state/macrae/: the server's event logs and run → task records.index/: the paper index.The container pushes changes at every step and every 60 s, and restores them when it starts. At most about 60 s can be lost if a host dies without warning. |
Cloudflare dashboard (owner only) |
3 · Harbor trajectory.json |
Inside each trial folder: agent/trajectory.json in ATIF (steps with source, message, tool calls
and their outputs), agent/claude-code.txt (Claude Code's raw stream), the reward, and the files the
agent changed. |
In R2 under state/jobs/.
v3 "Download trace" (zip) and "Open raw trajectory" on each run. |
v2, in progress A wrapper around Claude Code inside the sandbox
forwards each step to POST /api/live/{run}/{step}, at most 1 s late, with a per-run token. The server
stores these lines in <run>/live/<step>.jsonl, so the timeline fills in while the agent
works instead of when the step ends. Lines are de-duplicated against the final trajectory.json.
5 · Costs in progress (v2)
The page shows what each run costs in money, growing live while it runs. This is the design from the v2 addendum of the build contract. It is being built and is not on the live site yet.
Numbers known so far:
- A BFF research run: about 10–14 min and about $0.40 of Modal compute on a 32-CPU box (estimate).
- Hosting: standard-1 container about $29/month if it never sleeps, about $4–5/month at about 4 h/day. That is on top of the $5 Workers Paid plan. R2 stays in the free tier. An open, visible browser tab checks health every 20 s and keeps the container awake.
- Building Macrae itself: see section 10 ($23.90 API-equivalent for the first six modules).
6 · Research tasks with BFF in progress
BFF (BayesicForceFields) is the group's open-source code for Bayesian learning of partial charges (Košťál, Shanks, Jungwirth, Martinez-Seara, JCTC (Journal of Chemical Theory and Computation) 2026). It fits force-field charges to ab initio molecular dynamics (AIMD) references through a Gaussian-process surrogate and MCMC (Markov chain Monte Carlo) sampling. The result is a probability distribution of charges, not a single best guess. Agents scouted the group's papers and the BFF code, proposed ideas, and had them critiqued by a simulated chemist and a compute engineer. The owner approved two, which are now being turned into clickable tasks. Each one runs in Harbor on Modal, so every stage is traced.
Is 0.8 the right charge-scaling factor? A Bayesian answer with BFF
The group scales ionic charges by about 0.8 with the ECC (electronic continuum correction), to account for electronic polarisation. Here BFF learns acetate's charges at several ECC factors between 0.70 and 0.90. It then compares 0.80 against 0.75 with a Bayes factor: how much better the reference data supports one than the other.
Ca2+–acetate binding with error bars: from the BFF charge posterior to experiment
BFF gives a range of plausible charges (the posterior), not one set. This task carries that uncertainty through umbrella-sampling PMFs (potentials of mean force: the free-energy profile of calcium binding to acetate). That gives a binding free energy with error bars, which it compares with Raman spectroscopy data.
Both: about 10–14 min and about $0.40 per run on a 32-CPU Modal box, with BFF and GROMACS preinstalled in the image, so the agent never spends time installing. The agent is told to poll, not sleep. Until they ship, the panel shows the two current tasks: "Methods card for a group paper" and "Ion–water binding, computed live" (DFT on Modal).
7 · Frankenstein: an agent that builds itself in progress (v3)
The hackathon brief: "By dawn, show a creature that learned to do things it could not do at dusk." Macrae notices a capability it is missing, creates it, tests it, installs it, and uses it again in later runs. Its capabilities may evolve; its authority may not. This is designed and queued behind v2. Nothing below is live yet. (SHA-256 = Secure Hash Algorithm, 256-bit: a fingerprint that changes if a single byte of the tool changes.)
- Capabilities are versioned, tested tools with a manifest: name, purpose, inputs/outputs, tests,
SHA-256 fingerprint, the run that created it, created/tested/installed/last-used times and
a use count. The registry lives under
evolve/capabilities/and is synced to R2 with the rest of the state. - Dusk → dawn ledger:
GET /api/capabilitieslists every event (gap, create, test, install, use, rejected) since the session began. The page shows it as a timeline, with one card per capability and a fixed "Authority" card. - Demo plan: run 1 needs something it lacks, e.g. a radial distribution function, or a block-averaged error bar from a molecular dynamics trajectory. It creates, tests and installs the tool. Run 2 uses it without re-creating it. A manifest that asks for a secret is rejected.
- Raw traces: each run gets "Download trace" (a zip of its Harbor job folders, state and live logs) and "Open raw trajectory".
8 · Code map
| folder | what's in it | status |
|---|---|---|
data/, scripts/ | 479 group publications (titles, authors, DOIs) from the IOCB site | done |
web/ | Chat with Jarvis: a thread with mic and composer, [n] citations
opening source cards, typed questions that search the papers even without voice. Right panel "Tasks &
runs": task cards, the live run timeline (📄🔎🧮✍️✅⚠️), counters, cited papers, recent runs. Offline state,
light/dark, a bottom sheet on phones. | live v2/v3 views |
cloudflare/ | Worker macrae (index.js + worker.js):
serves the page, sends /api through the Durable Object to the container, ElevenLabs signed URL, rate
limits, admin status/restart, and the container's R2 endpoint. wrangler.toml, deploy.sh,
a local dev server and a mock backend. | live |
server/ | FastAPI (a Python web framework): tasks, runs, trace events (tool calls → read / calc / write…), search, ElevenLabs tools, draining on restart. | live v2: live, costs, planner |
rag/ | PDF → clean pages (headers, hyphenation and reference lists removed) → chunks;
BM25 + bge-small embeddings (BAAI General Embedding, by the Beijing Academy of Artificial Intelligence), fused
ranking; [n] citations with page | built needs PDFs |
tasks/ | "Methods card for a group paper" and "Ion–water binding, computed live" (DFT with PySCF on Modal), plus Modal support in agent-runner. The two BFF tasks are being added. | live BFF tasks |
voice/ | ElevenLabs agent "macrae" (voice "Jarvis", Claude Sonnet 5.5 through ElevenLabs, cites every claim): three server tools and a setup script | live |
deploy/ | Backend Dockerfile (Harbor uses Modal, so there is no Docker inside),
start.py (supervises the server, drains runs on restart), r2sync.py (R2 mirror), the
secret checker, docs | live |
evolve/ | Lessons distilled from traces, a tools library, a fine-tuning dataset export, then the capability registry | v2 → v3 |
research/ | Scouting notes on the group's papers and the BFF code, behind the two research tasks | done |
9 · Where it runs: all on Cloudflare
The page, the Worker and the backend live on one Cloudflare account and one address, deployed with
cloudflare/deploy.sh (which runs wrangler deploy). The backend is a Cloudflare
Container, built from the same Docker image, and the Durable Object MacraeBackend owns it. It
sleeps after 2 hours without use, but never while a run is going. Its disk is temporary, so the paper index is
baked into the image, and everything the backend writes is mirrored to R2. The container reaches R2 through
the Worker at a private address (r2.macrae), so it needs no S3 (Simple Storage Service) keys. On a
restart, task starts pause and running flows get up to 14 minutes to finish. Edits to the page alone don't restart
the backend. The heavy work (agents, calculations) runs in Modal sandboxes. AWS was the first plan and is no longer
used.
10 · How it was built
With agent-runner itself. A written contract (CONTRACT.md) fixed every interface. Then six Claude
Opus 5.5 agents (high effort) built their modules at the same time across three Claude accounts, each in its own
container. All six passed their checks on the first attempt.
| module | time | cost (API-equivalent) |
|---|---|---|
| web + Worker | 18.5 min | $5.24 |
| server | 14.4 min | $3.86 |
| rag | 15.6 min | $3.41 |
| tasks + Modal | 16.5 min | $4.95 |
| voice | 10.2 min | $2.99 |
| deploy | 15.7 min | $3.44 |
| total | ~19 min wall clock | $23.90, on Claude subscriptions |
Later flows on 2026-10-08 used the same method (Claude Opus 5.5, high effort, through agent-runner and Harbor): an integrator that fixed the seams and tested end to end; the move of the backend into a Cloudflare Container with R2; the chat redesign; the BFF research ideas; and now v2, Frankenstein (v3) and the video.
11 · What the owner provides
| item | status |
|---|---|
| ElevenLabs API key | provided live |
| Claude login for the agents | provided waiting a fresh key to replace it |
| Modal token (for the container) | provided connected |
| Paper PDFs | waiting indexed on the server, never published |
| Research tasks | approved two BFF ideas, being built |
| Hosting | live Cloudflare |
Glossary
| RAG | Retrieval-augmented generation: find the relevant passages first, answer only from them, cite them. |
| Worker | Small program on Cloudflare's network that serves the site and forwards API calls. |
| Durable Object | A named Cloudflare object with its own storage. Here it owns the single backend container and decides when it sleeps. |
| Container | The backend's Docker image, run by Cloudflare on demand. |
| R2 | Cloudflare's object storage (files in a bucket). Holds the index, runs and traces. |
| Harbor | Open-source harness that runs an agent in a sandbox and saves its trajectory, reward and files. |
| Modal | Cloud that starts sandboxes/containers on demand, CPU or GPU, billed per second. |
| Trace / trajectory | Every message, tool call and result of one agent run (ATIF format in trajectory.json). |
| Signed URL | A short-lived link (URL = uniform resource locator) that lets the browser open a voice session without seeing the API key. |
| BFF | BayesicForceFields: Bayesian learning of force-field partial charges from reference simulations. |
| ECC | Electronic continuum correction: scaling ionic charges (about 0.75–0.8) to mimic electronic polarisation. |
| Capability | A tool the agent wrote, tested and installed for itself. Authority (what tools may do) stays fixed. |