

AI Product Engineer · working remotely from Brazil
I build AI systems that take over the repetitive manual work a team does today.
ZapBeta is a multi-agent platform: several specialists running a company's departments over WhatsApp and the other tools. They answer, book appointments, put quotes together, close orders and charge for them, and when they need to, they call a person in right away. It's running in production.
I built a team of agents to build a multi-agent platform. I'm the only human on it: I direct it, I decide the architecture, I write the evals and I sign off on the result.
- Node.js
- TypeScript
- React / Next.js
- APIs
- Integrations
- Automation
- AI / LLM Systems
The office, live
I built this 3D scene so anyone can see what the system is doing without having to understand the tech. It's shaped like the company's own office and shows, in real time, everything going on inside it — including the customers already served today. Open it full screen, zoom in and move around.
02The whole system, one map
From the channel a customer messages on, down to the data it all stands on — and back up to everything the owner sees. Each case study above zooms into one of these boxes.
Channels
Where the customer comes in. It's the same conversation in all three: whoever answers on WhatsApp answers on the site chat and in the store.
Orchestration
Who reads the message and decides what happens to it. The router picks the specialist; the money supervisor checks anything with money in it before it goes out.
Specialists
Each one owns a department, with its own tools, rules and limits — instead of a single prompt trying to cover everything. That's what lets me test and lock down one of them without touching the others.
Capabilities
What the specialists can actually do: the tools they call, with real effect on the system.
Truth · data
What all of it stands on. One truth per thing, with tenant isolation enforced at the database door.
Surfaces
What the owner sees and uses day to day — and where the team takes over when a case calls for it.
03Simulated customers that actually hold a conversation
To test the specialists I release “little creatures”: fictional customers driven by a second model that gets an objective and reacts to whatever the agent replies. No script. One of them negotiates, picks a real slot, closes the order and stops on its own once it got what it came for.
Simulate customers
How many
Conversation length
How they behave
What language they speak
- objective
- the agent replies
- it reacts
- [END] once it's done
A model plays the customer
It gets an objective and a personality, reads the agent's last reply and writes the next message. It stops when it has done what it came to do, or at the turn ceiling I picked.
This is how I found the language bug
I released creatures in six languages and the specialist answered a German customer in Portuguese. No scripted test of mine would have caught that — I write my tests in Portuguese.
Nothing leaves the building, by construction
Their phone number has no digits in it at all, and every send strips non-digits before dialling. What's left is an empty string, so the send skips itself. I like the guarantee living in the shape of the data: nobody deletes an if by accident and leaks a message to a stranger. There's a test with a thousand samples on that.
In a simulation the Pix is a fake one
The payment code is generated statically and never touches the bank's API. A demo has no business creating a real charge.
04Numbers that are real
Each one measured with the command sitting right next to it in the source. Nothing estimated.
- 162,202
- lines of TypeScript
- generated database types excluded
- 219
- SQL migrations
- Postgres, row-level security throughout
- 84
- API route handlers
- Next.js App Router
- 35
- function-calling tools
- what the agents can actually do
- 26
- scripted eval conversations
- the most critical ones run more than once, because the model varies
- 767
- commits
- small slices, straight to production
Measured on 2026-07-25. No team: architecture, database, agents, front end and infrastructure are my call — and so are the evals that hold all of it to account.
05Take a closer look at what I built
Each one follows the same template: the problem, the constraints, the architecture, the part that was actually hard, the trade-offs, and what I'd do differently.
- 01Testing non-deterministic systems: a 26-conversation eval suite
- 02Multi-agent routing and the supervisor that guards the money
- 03Turning agent traces into a live 3D office
- 04A 134-agent adversarial security audit of my own code
- 05Tracing an LLM agent: debugging what the model actually did
- 06Passing a conversation to a person without the customer repeating anything
- 07One domain model for scheduling, sales and delivery
- 08Scheduling against the real world
- 09Compliance that distills itself
- 10Building a product catalog from barcodes
06How I work
This is the order I work in, from the first file to after the code has shipped. I didn't design it — I noticed I kept repeating the same sequence, and every step in it came out of a mistake that cost me time. It holds for the agents working with me too: who does the work changes, the method doesn't.
- 01
Before I integrate, I look at what the API actually returns
When I'm about to plug in a new API, I wire the flow in n8n before writing any code: fire the call, look at the real payload and find out what the docs don't say. Then I implement it straight in code, which is where it's going to live.
- 02
A rule lives in one place
If the same rule has to hold in two places, I don't copy it. It becomes one parameter, or one function, with a test on it. A copy never tells you it's drifting — by the time you notice, it drifted a while ago.
- 03
Comments point at the code, not at the number
A comment that repeats a value lies the first time the value changes. Nobody goes back to fix prose. Nobody.
- 04
Where a mistake is expensive, more than one lock
Each lock catches a different way of getting it wrong, so leaking takes more than one failing at once. And if the risk is a silent one I put an indicator on the screen, because a quiet panel tells me nothing: could be fine, could be the alarm broken.
- 05
I test what the agent can never do
You can't hold a model to exact words. What it must never do, you can: invent a price, confirm a slot that doesn't exist, promise a refund, ignore compliance or the company's own rules. It's a suite simulating 26 conversations around those points, about five minutes, and it runs before every deploy that touches the agent.
- 06
I check the real system, not just the test
A unit test proves the logic. It doesn't prove the data gets there. I've had a rule with everything green that never ran for real, because the query wasn't bringing the column.
- 07
Before it ships: run it, trim it, look at the screen
Local commit, tests, cut whatever got fat — 500-line ceiling per file — and then I open the screen and look at the front end and the responsive layout with my own eyes. Only then it goes.
- 08
After the review, the mistake becomes a rule
It's not fix it and move on. I write down what caused it, because otherwise a month from now I pay the same rework again — and that time isn't only mine, it's the reviewer's too.
- 09
At the end, the module gets a folder, a diagram and a markdown
I write down how it works and draw the flow, so the next person gets it without reading all the code. Markdown on purpose: people skim it, and an AI reads the whole thing in one go.
07Technical decisions
The choices that shaped the system, and what I was avoiding with each one. All of them cost me something on the other side.
Why several specialists instead of one prompt
A prompt that does everything grows until nobody can change it without breaking something else. I split it by domain: each specialist has its own tools, rules and limits, and a router decides who answers. That way I can test and lock down one without touching the others.
Why business rules live on the server, not in the prompt
Dates, prices, availability and discounts are resolved in code; the agent only states the intent. That's what killed the chain of "wrong time" bugs — while the model was adding days, every release brought a new way to get it wrong.
Why RAG instead of an ever-growing prompt
Stuffing the whole knowledge base into the prompt costs on every single turn and drowns what matters in the middle of everything else. The material stays in the database, searched by similarity, and only the passage that answers that question makes it into the prompt.
Why tenant isolation lives in the database
If it lives in application code, one query forgetting its filter is enough. In the database, the row simply doesn't come back. That rule holds across 219 migrations, and it's exactly what the adversarial audit went through with a fine-tooth comb.
Why an allowlist and not a denylist on the public page
With a denylist, a new field on the type reaches production on its own and nobody notices until it turns up as a finding. The public scene builds its response field by field: phone numbers, WhatsApp ids and emails never leave, even if the three locks in front of them fail.
08Security, testing by attacking
I write real attack tests, playing the intruder. And even when they come back green I run the counter-check, going through by hand to see why they passed. It works better that way.
- 01
I recruited 134 agents to attack my own code
134 agents hunting for problems in my code in parallel, and every finding had to get past three skeptics whose only job was to prove it wrong. Twenty made it through, and once I merged the ones that were the same bug seen twice, they turned into 17 fixes. The worst one let anyone, no login at all, write an appointment straight into another company's calendar — I closed it in the database, with a rule so it can't come back. It was the third time.
- 02
When a scan comes back clean, I get suspicious
I ran a scan across every endpoint and it came back with zero findings. Zero. That's not a relief to me, it's a red flag right away. So I went through them by hand, one by one, and found a public endpoint that would sign any storage key against the private bucket: one customer could pull another one's files. The scan had tossed it out on its own. Stuff like this can't slip through.
- 03
I tested the agent like I was trying to scam it
I built a set of tests that try to hijack the agent: leak its system prompt, force a discount, turn it into some other bot with no rules. It caught the agent admitting it was "a virtual assistant" — the one thing the brand can't say. I fixed it with a rule no customer message can override, and ran it three times before shipping.
- 04
A log doesn't need to keep everything forever
The traces kept the customer's name, phone and everything they typed, forever. Now it goes in masked: the first name stays, the rest of the personal data is blurred. Personal data sitting in a log nobody will open is risk for nothing. It doesn't help anyone.
Let's talk
I'm open to remote work building with LLMs: agents, evals, tooling, the whole product around them. I'd be glad to show you a lot more on a call. Just reach out.