Inspiration
I design a suspension upright for a buggy in the evenings, with an AI agent. Generative geometry, meshing, finite elements, a fatigue criterion, a loop that resizes the part until it passes. One full run costs about two hours on my machine.
The expensive mistake is not a wrong result. It is a two-hour run that could never have concluded, because something it needed was not known yet. That happened to me ten times in a row before either of us had read the documentation the design required. Every one of those ten runs was dead before it started, and I only found out at the end.
So I asked my agent what it was missing, and it told me. That list is this project.
What it does
Most agent memories store what is known. This one stores what is not known at the same rank as what is — and that single decision changes what the agent can do.
UNDECIDABLE and NOT FOUND are values in a CHECK constraint on the requirement table, not
nulls and not absent rows. A requirement without a status is rejected by the database. So the
question "can this two-hour computation start yet?" stops being a judgement call and becomes a
join over computation × requirement × belief that answers in single-digit milliseconds.
The agent does three things with it:
- It refuses.
agent_loop.py --goal fea_runreads its own memory, finds one blocking requirement still undecidable, and printsI AM NOT RUNNING THISwith the reason and the cost it just avoided. It calls no language model to decide this — the verdict follows from stored state, so the same memory always yields the same decision. - It says where to look. Naming a gap does not close it. The same query continues laterally into a distributed vector index over my own engineering notes, from the belief's own position, and returns ranked passages with their similarity. I ask in English; my notes are in French; it finds them anyway. And when nothing in the corpus is close enough, it says so instead of ranking three weak passages to fill the slot.
- It takes correction, and only then it writes. A memory nobody can correct is a logbook. A
claim gets one of three answers, and only one of them writes. A vague claim is refused with the
shape it needs. A claim that settles an open belief with evidence triggers a revision: the old
belief is closed, the new one opened, and the note explaining why is stored — in one
transaction, all three or none. The blocked computation then moves to
CAN RUNon the same page, in the same second.
How I built it
CockroachDB is the whole memory layer, not a store bolted onto it:
- Bitemporal beliefs. Every belief carries the interval over which it was held and the evidence that ended it. Nothing is overwritten. 42 beliefs, 25 currently held, 17 revisions — and every one of those revisions is a mistake I made and had to correct.
CHECKconstraints carry the semantics. Undecidability is a first-class status, so an empty cell is impossible to leave by accident. This is the design decision the whole project rests on.- Distributed vector indexing in the same cluster as the transactional data. 171 indexed chunks of my real engineering notes. No separate vector store, no ETL, no consistency gap between a belief and the passages that support it — one query crosses both halves.
AS OF SYSTEM TIMEfor storage-level time travel, next to the modelled belief interval. The demo asks both the same question and shows where they diverge.- Row-level TTL on visitor-written beliefs, so anyone can try the demo and nothing a stranger writes can reach what the engineer wrote.
- Cloud Managed MCP Server — the schema, the migrations and the invariant checks were driven through MCP from my coding agent, in read-only mode with audit logging, with no custom proxy.
AWS carries the delivery: one Lambda function behind an HTTP API answers every view, and the demo page is a single object on S3. That is the whole stack.
Challenges I ran into
Bedrock was throttled to zero on a day-old account. The corpus had to be embedded with a local multilingual model instead. The consequence is honest and visible in the demo: the deployment cannot embed new text, because a query vector has to live in the same space as the corpus. The 41 pre-embedded questions answer for real; the page says so rather than hiding it.
My own tests accused the wrong component. Five invariant violations, all on the same key, and none was a database fault: it was the visitor overlay, which sits on top of an engineer belief without closing it. Two kinds of row do not obey the same invariant, and a test that conflates them blames the wrong one.
The live database and the repository disagreed. The project's own question, turned against
itself: part_thickness was 14.00 mm in the cluster and 12.74 mm in the repo. Caught by
invariant bench BT6, fixed by a targeted migration — not by replaying the seed, whose inserts are
unconditional and would have duplicated all 40 beliefs three days before the deadline.
Accomplishments that I'm proud of
59 test cases across three benches, zero crashes. One bench for what a judge might type, one for what a broken API might return, one for answers that are well-formed and wrong. The last one found the schema drift above. Output is byte-identical across runs, which is how a demo becomes repeatable rather than lucky.
And the thing I did not expect: the agent calls no model at all. The literature says production LLM applications are mostly deterministic code; this one takes that to its limit. An agent that reasons its way to a different answer on a Tuesday is not a memory, it is a mood.
What I learned
I am no engineer, and I don't have the specific terms. That is exactly why I make the machine prove everything — and it is the reason the memory stores what it does not know. Every one of the 17 revisions in this database is a moment where I was confidently wrong and the measurement said otherwise.
What's next
Closing the loop the other way: letting the FEA run write its own results back as beliefs, with provenance, so the memory learns from the computation it unblocked.
Built With
- amazon-web-services
- aws-lambda
- bitemporal
- cockroachdb
- javascript
- mcp
- pgvector
- postgresql
- python
- row-level-ttl
- sentence-transformers
- sql
- vector-search
Log in or sign up for Devpost to join the conversation.