# Léonard Henriquez

> Co-founder & CTO of Topo (YC W24). I build the infrastructure AI agents run on: durable execution, context, search and orchestration.

- Current role: Co-founder & CTO, Topo (YC W24), since 2022 (https://www.topo.io)
- Highlight: Our AI SDR went from $0 to $1M ARR in three months.
- Location: Paris, France
- Focus: Durable execution, Context, Search, Orchestration
- Contact: LinkedIn (https://www.linkedin.com/in/leonard-henriquez/)
- GitHub: https://github.com/leonard-henriquez
- Website: https://hqz.me/

## About

I like to see the whole landscape (market, architecture, team) before choosing the path through it. Before Topo I was Head of Engineering at Manda, where I ran a team of about ten developers, after starting there as a product manager. MSc in Data Analytics and AI from EDHEC.

My work sits underneath AI agents, in the parts nobody demos. Durable execution that survives a crash at 3 a.m. Search built for machines that read faster than we do. Control planes that keep a fleet of coding agents honest.

Full career: LinkedIn (https://www.linkedin.com/in/leonard-henriquez/).

## Key figures

- **Y Combinator W24**: Co-founded Topo as CTO, selected for the winter 2024 batch
- **$1M ARR in 3 months**: AI SDR built from zero; customers incl. Air France, Aircall
- **×4 merged PRs/month**: Coding-agent harness, with 63% fewer bugs per PR

## Projects

11 projects, 2012–2026. Each one also has its own file, listed in https://hqz.me/llms.txt.

### Topo

> AI agents for B2B outbound sales, used by 150+ customers including Air France and Aircall. I designed the platform: durable agent workflows on Temporal, the Playbooks engine, a search index of about a billion profiles, and an MCP server with 170+ tools.

- Status: Released
- Period: 2022–present
- Role: Co-founder & CTO
- Results: $0 → $1M ARR in 3 months; 10M+ agent actions a month; 1,205 merged PRs
- Stack: Temporal, Elasticsearch, PostgreSQL, MCP
- Tags: YC W24
- Links: [topo.io](https://www.topo.io)

#### The problem

Outbound sales for mid-market B2B companies is a long chain of small judgments. Which accounts fit, who to contact there, why now, what to say, how to answer the reply. Each step is easy for a person to do once and expensive to do a thousand times a week.

Topo's bet was that agents could run that chain end to end for a sales team. The condition was that the platform underneath them had to be built like infrastructure. An agent that writes a good email in a demo is easy. An agent that sends the right email to the right person, exactly once, after waiting four days for a reply, on behalf of a customer like Air France, is a distributed system.

#### What I built

##### A durable agent platform

Every agent run at Topo is a durable workflow on Temporal. A run calls slow models and unreliable third-party APIs, sleeps for days between sequence steps, and must survive deploys and crashes without sending anything twice. Durable execution gives us retries, idempotent steps and replay. On top of it, a person reviews and approves before anything leaves on a customer's behalf, and progress streams to the product in real time so users see agents working. The platform now executes more than ten million agent actions a month.

##### Agents that do the sales work

Agents for account discovery, enrichment, personalized outreach, reply handling and in-product chat. Most of the quality gains did not come from prompt wording. They came from what the model sees: the CRM history of the account, transcripts of past calls, and the right tools at the right step. Evals told us whether a change actually helped.

##### Playbooks, a workflow engine for go-to-market

Customers kept asking for the same shape of automation: when something happens, find the right people, enrich them, write to them. Playbooks is the engine for that. A playbook chains signals, agent steps and sequences, with versions, test runs and rollback.

The design rests on one split. A model is good at discovery, when nobody knows the steps in advance. A deterministic engine is good at execution that is repeated, irreversible and audited: enrolling contacts, sending messages. A playbook is a recipe that was discovered, then frozen into a versioned, typed and durable unit. AI decides to run it and powers specific model steps with typed outputs. It never drives the sequencing once the recipe is frozen.

I applied a strict simplicity rule to the spec. Before building, I scored 20 candidate workflows from real customer requests. Hiring-signal outbound, always-on prospecting against the ideal customer profile, and closed-lost revival came out on top, and the engine was shaped around what those needed.

##### An MCP server with 170+ tools

Customers increasingly run their own agents. The Topo MCP server exposes the product to them: lead search, signals, playbooks, sequences, tasks, replies. Tools that spend credits, contact prospects or switch on automations ask for explicit confirmation.

##### Search at scale

Everything starts with finding the right people, so the data layer matters. Topo's search index holds about a billion documents, with hybrid search and ranking, fed by durable enrichment pipelines.

We started on Quickwit, which stores its index on S3 and is very cheap to run. We moved to Elasticsearch when the product needed things an append-only engine does not do: upserts by deterministic ID, index aliases for an atomic swap during monthly re-indexing, and an enrich processor to join company data at ingest. At the time of the migration the people index alone held 416 million documents, about 2.5 TB.

##### Ready for enterprise customers

Selling to companies like Air France meant CRM integrations, SAML single sign-on, security reviews, and a SOC 2 Type 2 audit, which I led.

##### The team

As CTO I hired and led the engineering team and stayed its top committer, with 1,205 merged pull requests. In 2025 and 2026 I rebuilt how the team ships around coding agents, which is a story of its own: [Self-driving engineering](/projects/self-driving-engineering/).

#### What it taught me

- **Agents are distributed systems.** A run is a long-lived workflow calling slow models and flaky APIs. It needs durable execution, retries, idempotent steps and replay, from the first version.
- **Context beats prompts.** The biggest improvements came from giving the model the right history, transcripts and tools at each step. Evals are how you know a change helped.
- **Keep humans where mistakes are expensive.** Review before every send cost little and bought customer trust. Everything that can be checked automatically should be.

### Self-driving engineering

> Rebuilt how a five-person team releases software around coding agents: a harness that lets agents install, run, test and observe the whole product, strict CI gates, and a path from customer feedback to a preview, a demo video and a one-click release.

- Status: Released
- Period: 2025–2026
- Role: Architecture & rollout, at Topo
- Results: Merged PRs a month 80 → 318; Bugs per PR −63%; CI failures 15.7% → 2.4%; Feedback to production < 10 h at p80
- Stack: Claude Code, Codex, Cursor, OpenCode, Temporal, GitHub Actions

#### The problem

Topo's engineering team was five people serving a product that was growing fast. Hiring more reviewers would not have kept up. Customer feedback took too long to turn into shipped code, and human code review had become the bottleneck.

Coding agents could write code faster than we could read it. The question was how to let them do more of the work without letting quality slide. My answer was to stop treating the agent as the product and invest in what surrounds it: the environment it runs in, the checks it must pass, and the proof it must bring back.

#### Two connected systems

##### A self-driving codebase

The goal was simple to state: an agent can install, run, test and observe the whole product on its own, then correct its own work against fast automated checks.

- **Reproducible environments.** One command brings up the full stack, locally or in a sandbox, so an agent never has to guess how to run something.
- **Instructions in the repo.** `AGENTS.md` files describe conventions where the code lives, so every harness (Claude Code, Codex, Cursor) reads the same rules.
- **Observability agents can read.** Logs, traces and errors an agent can query, plus browser-based testing, so it can see what its change did instead of assuming.
- **Feedback moved left.** Fast mechanical checks run in hooks before a commit. AI review in CI only covers what tools cannot check. Strict CI gates became the definition of done.
- **Auto-fix loops.** When CI fails, an agent reads the logs and pushes a fix through GitHub Actions. A daily triage job does the same for production errors from Sentry and Datadog.

##### From customer feedback to production

The second system closes the loop with customers. Feedback goes in one end, and an engineer gets a change they can judge by its behavior at the other.

1. Customer feedback
2. Checked against product direction
3. Agent builds the change in a sandbox
4. Preview, screenshots, demo video
5. Engineer inspects
6. One-click release

At p80, feedback reached production in under ten hours.

Background agents ran on our own infrastructure: Temporal as the control plane, OpenCode as the agent server, sandboxed runs, and an always-on machine for headless agents. Each proposed change came with a preview URL and a recorded demo, so routine human code review became optional. Review did not disappear. It moved from reading diffs to checking behavior.

#### Results

With the same team, merged pull requests went from about 80 to 318 a month. Bugs per pull request fell by 63%, and the share of failing CI runs dropped from 15.7% to 2.4%. More code and fewer bugs came from the same change: agents got feedback early and often instead of humans catching problems late.

#### What I learned

- **The harness does the work.** Model upgrades helped, but environments, checks and instructions made the difference between an agent that guesses and one that verifies.
- **Autonomy is earned with feedback.** Every check an agent can run on itself is a review a human no longer needs to do. Strict gates gave us more freedom, not less.
- **Route models, don't trim steps.** When I analysed a month of background-agent sessions, cost grew linearly with the number of steps for any given model, but the cost per step varied about 25 times between models. Long sessions only looked like they compounded because they were mostly run on the most expensive model. Choosing the model per task is the lever.

This work is the starting point of two later projects: the [Agent Control Plane](/projects/agent-control-plane/), which generalizes the background-agent platform, and the [Company Brain](/projects/company-brain/), which gives agents the business context the code does not hold.

### Company Brain

> A shared Markdown memory that the team and its agents both read and write. At Topo: a Go daemon syncing to S3, compare-and-swap writes, LLM-resolved merges and an MCP server. As a product: provenance, review and permissions for every fact.

- Status: Released
- Period: 2026
- Role: Built at Topo, now a product spec
- Stack: Go, S3/R2, SQLite, MCP, Temporal
- Tags: agent memory

#### The problem

Topo's agents needed business context that no codebase holds: who the customers are, what was decided and why, what was said on calls, what worked last quarter. Wikis and RAG tools keep that knowledge in their own databases, behind an API. Coding agents work on files, so for them the knowledge might as well not exist.

The first spec made a Git repository of Markdown files the source of truth. It broke down quickly. The ingestion server would have had to clone the repo for every write. Raw material such as call transcripts grows without limit and ends up on every laptop. People and agents edit the same files at the same time, and a line-based merge is too coarse for that. When a design needs that many workarounds, the primitive is wrong.

#### The approach

Keep Markdown files on disk as the source of truth, in the "LLM wiki" pattern: an `AGENTS.md` at the root, conventions for structure and frontmatter, and an MCP server so any agent can query and edit the brain. Replace Git as the sync layer with something built for continuous writes from many sources.

Scheduled jobs on Temporal ingest meeting transcripts and compact the brain overnight. Through loop engineering, agents turn what they learn on the job into knowledge and reusable skills that the next agent reads.

#### How sync works

A small Go daemon watches the local folder and syncs it with an S3 or R2 bucket, so every teammate and every agent sees the same tree. Local state lives in SQLite. The write path is where the design choices are:

1. File saved locally
2. Hash compared, no-op if unchanged
3. Conditional PUT on the ETag
4. On conflict, three-way merge
5. LLM resolves the rest
6. Quarantine if still unsure

- **Compare-and-swap on object storage.** Each upload carries `If-Match` with the ETag the edit was based on. If someone wrote in between, S3 answers 412 and we know there was a concurrent edit instead of guessing. This replaces a rejected `git push`.
- **The ancestor is always recoverable.** With bucket versioning on, the version the local edit started from can be fetched by ID. That gives the common ancestor for a real three-way merge with `git merge-file`, and clean context for the model when the merge needs judgment.
- **Nobody's edit is lost silently.** When neither the merge nor the model resolves a conflict cleanly, the user's file is left untouched and the other version is written next to it as a `.conflict` file, with a notification. The same rule Syncthing follows.
- **Safe by construction.** Local writes go to a temporary file and are renamed atomically, so a crash never leaves a half-written note. Hash-based idempotence stops sync loops when an editor touches a file without changing it.
- **A full audit log.** Every resolution records the path, the three hashes, the result, who resolved it (merge, model or person) and the diff size, stored in the bucket. When an agent merges badly, you can trace it back.

The design is sized for what the brain really is: up to about a hundred users, with most files append-only. That is what makes a simple daemon on top of object storage enough, without a CRDT engine or a virtual file system.

#### From internal tool to product

Running it at Topo showed what a team needs before it trusts a shared memory written partly by agents. The product version of the Company Brain adds three things to every fact: where it came from, who reviewed it, and who may read it. Provenance, review and permissions are what turn a pile of notes into something a team can rely on.

### Software Factory

> Turns websites and apps without APIs into read-and-write MCP tools for agents. A pipeline captures how a site behaves, distills it, generates the connector, runs it, and heals it when the site changes.

- Status: Building
- Period: 2026
- Role: Founder
- Results: Goal: 2nd connector in < 2 days, 3rd in < 1
- Stack: TypeScript, Zod, MCP, Temporal
- Tags: connectors

#### The problem

Agents can only act where there is an API. Many of the tools people work in every day have none, or only a read-only slice: social networks, vertical SaaS, internal portals, legacy back offices. Agent builders end up writing fragile scrapers by hand, one site at a time, and fixing them every time the site changes.

The Software Factory treats the process of building those connectors as the product. Give it a site, and it produces a typed, tested tool that agents can call over MCP, for writes as well as reads, and repairs it when the site changes.

#### Three products in one

"Software factory" covers three things with different lifecycles. Mixing them up is the first architectural risk: you end up with a runtime that generates code, or a factory that has to run in production.

- **The factory.** Development tooling run by coding agents: capture, distillation, generation, evals, repair. It lives in the monorepo and CI and is never on the path of a customer request.
- **The catalog.** Versioned connector packages, one per target site, produced by the factory and reviewed by a person. Each connector is readable code, not an opaque generated blob.
- **The runtime.** The multi-tenant platform that executes capabilities: sessions, rate budgets, execution tiers, secrets, observability, and the MCP and REST surface customers see. No model inference on the critical path.

#### The pipeline

1. Capture
2. Redact secrets
3. Distill
4. Generate
5. Replay evals
6. Run
7. Heal

The only arrow that goes back is drift: when a site changes, healing re-enters the pipeline at capture.

**Capture** records network traffic and UI actions in the same session, and correlates them. One recording feeds two implementations of each capability: a fast HTTP path and a slower browser path. The fallback stops being a separate project and becomes a by-product of capture.

**Redaction** is a wall. Session cookies, authorization headers and tokens are replaced by named placeholders on disk before anything else reads the capture. A model never sees a real secret.

**Distillation** is where a model helps. An agent reads the redacted recording and writes a structured spec for each capability: input and output schemas, the chain of calls and how IDs flow between them, required headers, and a normalizer that maps the site's formats to the output schema.

**Generation** is not done by a model. Templates turn the spec into code, so the output is deterministic, reviewable and diffable between versions. The model writes the spec; the generator writes the code.

**Replay evals** are the gate. Offline replays of recorded fixtures run on every commit, online canaries replay read capabilities against the live site a few times a day, and contract tests check that the generated MCP tool accepts and returns exactly what the schema says.

#### One contract per capability

A capability is a business intent ("post a comment"), not an endpoint. Every connector is a list of capabilities that follow one small, strict contract. The MCP tool, the SDK and the CLI are all derived from it.

```ts
export const postComment = defineCapability({
  id: "forum.post_comment",
  version: 2,
  input:  z.object({ thread_id: z.string(), body: z.string().max(2000) }),
  output: z.object({ comment_id: z.string() }),
  effect: "write_reversible",   // read | write_reversible | write_irreversible
  auth: "client_session",       // whose account runs it
  rate_class: "comment",        // per-connector budgets
  idempotency: "input_hash",
  dry_run: true,
  impls: { http: ..., browser: ... },
  fixtures: "./fixtures/post-comment/*.json",
  drift_signals: ["schema_mismatch", "http_403", "challenge_page"],
});
```

Three fields carry most runtime decisions. `effect` sets the defaults: reads retry freely, reversible writes need an idempotency key, and irreversible writes ask the calling agent to confirm. `auth` decides whose session runs the call, and a capability never mixes the two, so responsibility is clear per call. `rate_class` points to the connector's pacing policy; a call over budget fails fast with a typed error and a retry time instead of hanging. Errors map to one shared taxonomy (drift, auth expired, rate limited, not found, business rule) that a client agent can act on.

#### Running and healing

The runtime is meant to be the most boring part of the system. A router picks the cheapest execution tier the policy allows: plain HTTP, a request issued from inside a live browser session, or full UI automation. A typed error drops the call one tier and counts toward a drift threshold. Temporal holds it together: one workflow per session, one activity per capability call, one workflow per drift incident.

Healing produces pull requests, not hot patches. A drift incident switches the capability to its fallback, re-captures, regenerates, replays the evals and opens a PR. A person merges at first; auto-merge comes once the evals have passed three times in a row.

#### How I measure the factory

The first connector is a one-off whatever you do. The factory is proven when the second one takes less than two days and the third less than one. That metric decides every trade-off in the first phase.

It also shapes where the edge is. The best-known targets are the hardest and the most crowded market. A factory's structural advantage shows on the long tail: business portals, vertical SaaS and internal tools that nobody maintains a connector for.

#### An agent-first repository

The project is itself built by agents. An orchestrator agent keeps its context for planning and delegates work to sub-agents. The repo follows the same rules as [Self-driving engineering](/projects/self-driving-engineering/): end-to-end tests on real scenarios to reproduce bugs, observability the agents can query, parallel worktrees, shift-left hooks, and a skills system improved through loop engineering.

### Agent Control Plane

> A control plane for background coding agents: any harness, any sandbox, self-hosted by small teams. Launching a task is decoupled from where it runs. It grows out of the background-agent platform I built at Topo.

- Status: Building
- Period: 2026
- Role: Author
- Stack: TypeScript, Postgres
- Tags: open source, coding agents

#### The problem

A small team that works with coding agents soon runs many sessions in parallel, and wants them off the laptop: in the cloud, reachable from a phone, still running when the lid closes. The tools that offer this each bundle one harness, one sandbox provider and one hosted backend, often with usage-based pricing on top.

That is a bad trade for a team that already pays for model subscriptions, already has a cloud account, and changes harness every few months because the best one keeps changing.

#### Where it comes from

At Topo I built our own background-agent platform: Temporal as the control plane, OpenCode as the agent server, sandboxed environments, and an always-on machine for headless agents. It worked, and it was the base of [how the team shipped](/projects/self-driving-engineering/).

Before generalizing it, I benchmarked the orchestrators on the market against what a team like ours needs: sessions reachable from anywhere, bring-your-own subscription, our own sandbox provider, infrastructure we can host or expose ourselves, and room to customize. None covered the set. Each one was built around a product decision that a team cannot undo: its harness, its runtime or its cloud.

#### The approach

Decouple launching a task from where it runs. The control plane schedules, tracks and supervises agent sessions. Harnesses, execution environments and clients plug in through interfaces. Small composable plugins extend it without forking.

1. Clients: web, desktop, mobile, API
2. Control plane: tasks, sessions, policies
3. Harness: any coding agent
4. Sandbox: any provider or your own

#### Design choices

- **Built for background agents.** Sessions run for a long time and outlive the client that started them. Durable execution sits behind an interface, with Postgres as the default backend so self-hosting needs nothing exotic.
- **Teams in the core.** Multi-user from the first version. Hooks, policies and secrets belong to the team, not to each laptop.
- **Plugins over forks.** Composable plugins and API endpoints let a team add its own loops and checks without maintaining a fork.
- **Reuse over reinvention.** Existing open-source runners and session protocols where they fit. The value is in the plane, not in another agent.
- **Open core.** A self-hostable core under an open license, with a hosted offer later for teams that would rather not run it.

#### Product loops on top

A control plane knows every task, every session and its cost. That makes it the right place for the loops that turned out to matter most at Topo:

- tasks started from product signals, such as an issue tracker or analytics events;
- preview URLs for each session, with optional database branching;
- proof videos that show a feature working, attached to the change;
- cost-per-task benchmarks on a team's real issues, so model and harness choices rest on data.

#### Who it is for

Small engineering teams that want an agnostic, self-hostable system in their own infrastructure, and that would rather own the plane than rent a bundle. The project is in active development.

### Version control for agents

> One trunk where every change lands signed by the agent that made it, conflicts resolve as they happen, and any agent’s work can be rolled back. A layer over plain Git, not a replacement.

- Status: Exploring
- Period: 2026
- Role: Research & design
- Stack: Git, SQLite
- Tags: version control, coding agents

#### The problem

Git was designed for people working on separate branches who merge now and then. Put several coding agents on the same codebase and that model strains. Branches diverge within minutes, merges arrive late and full of conflicts, and once the work of several agents is interleaved there is no clean way to undo what one of them did.

The question I wanted to answer: what would version control look like if it were designed for many agents writing at once, with a person supervising?

#### The idea

One trunk, no long-lived branches. Each change is atomic, lands on the main line immediately, and is signed by the agent that made it. Conflicts are resolved as they happen rather than at merge time. And any agent's contribution can be withdrawn after the fact, even when it sits between other agents' edits.

> "Roll back everything agent B did in the last hour" should be one command.

#### From a new system to a layer over Git

The first design was a new system: an append-only log of operations instead of a graph of snapshots, with a CRDT as the materialized state. Rolling back an agent meant replaying the log without its operations. It was clean, and it meant rebuilding everything Git and its ecosystem already do well: transport, remotes, hosting, pull requests, CI.

So the design moved to a layer over Git, in the spirit of Jujutsu and git-branchless. Git keeps storage, history and collaboration. The layer adds agent semantics.

#### Design choices

- **Plain Git underneath.** Remotes, GitHub, pull requests and CI keep working. A team can adopt it without changing tools, and the repo stays a normal Git repository.
- **An operation log beside the commits.** A local log in SQLite records each agent's operations and their causal dependencies. Agent identity and metadata travel with each commit as trailers and git notes.
- **A CRDT-style merge driver.** A custom merge driver, registered in `.gitattributes`, merges concurrent agent edits line by line instead of using Git's default three-way merge.
- **Dependency-aware rollback.** Undoing an agent walks the causal graph, reverts its commits in reverse order, and flags the later edits that depended on them for review.

#### Trade-offs

- **Two sources of truth.** The Git history and the operation log must stay in sync, which is a source of bugs to design against from day one.
- **Reverts add history.** Rolling back creates new commits rather than erasing old ones. Rewriting history would be cleaner but breaks shared branches.
- **Line-level, not character-level.** Git stores files and lines, so the merge works at that grain. For agents that write blocks of code, that covers most real cases.

#### Status

Concept and architecture. The layer approach turns a multi-year rewrite into something one engineer can ship as a first usable version, and anyone can try it without risk because the repo underneath is still Git.

### Durable execution on S3

> What Temporal would look like if S3 were the database: durability on the server, thin clients in any language, primitives for agents that run for hours.

- Status: Exploring
- Period: 2026
- Role: Research & design
- Results: ≈100 ms durability overhead per step; No database cluster to run
- Stack: S3, R2, GCS, MinIO
- Tags: durable execution

#### The problem

Durable execution is what keeps a long agent run alive through crashes, deploys and flaky APIs. I have relied on it in production at Topo with Temporal, and I would not build agents without it. But today's engines carry real weight. Temporal needs a database cluster and usually Elasticsearch next to it. Hatchet needs Postgres and a message queue, DBOS needs Postgres. And much of the durability logic lives in thick client SDKs, which makes every new language expensive to support.

The question: what would Temporal look like if S3 were the database?

#### The thesis

Object storage is already the most durable store most teams have. It is strongly consistent, it supports conditional writes, it scales without operations work, and it costs almost nothing at rest. The same idea already reshaped other categories: WarpStream did it for streaming, Quickwit for search. Nobody had done it for durable execution.

#### Architecture

1. Workers run your code
2. Long-poll a single server binary
3. Server appends events to S3
4. State rebuilt by replay

- **The log is the database.** Everything is event sourcing. Each workflow's history is an append-only series of small log segments in the bucket; its current state is derived by replaying them, from the last checkpoint.
- **Conditional writes as consensus.** Segments are written with `If-None-Match`, so two writers can never create the same one. Partition ownership uses leases stored as objects and renewed with `If-Match`. No Raft, no Paxos: S3 is the coordination layer. A single node is enough; more nodes add capacity, not durability.
- **Payloads stay out of the log.** Large step results go to the bucket as separate objects, and the log keeps a reference. Segments stay small, recovery stays fast, and history has no size limit.
- **Any S3-compatible store.** AWS, R2, GCS, MinIO, Tigris. Self-hosting is one binary and one bucket.

#### Trade-offs, chosen on purpose

| What you gain | What you accept |
| --- | --- |
| No database to run | About 100 ms per step instead of a few milliseconds |
| Cost that follows usage | Throughput bounded by object-store write rates |
| One binary to deploy | Slower recovery after a restart than a hot standby |
| Portability across clouds | No SQL queries over history |

For agents these costs barely register. A step that calls a model or an external API already takes hundreds of milliseconds or more, so 100 ms of durability overhead disappears in the noise. The target is teams that want durability without operating a cluster, the same relation WarpStream has to Kafka.

#### The second iteration: built for agents

A first version of the design followed Temporal's model closely. The second one changes two things.

**Durability moves to the server.** The client becomes a thin contract: receive a task, report a result, heartbeat. That makes a new language SDK a small piece of work rather than a port of a complex runtime.

**The primitives are shaped around agents**, coding agents and business agents, rather than batch jobs. The candidates I am designing for:

- steps that run for hours, with heartbeats and safe resumption;
- waiting for a person for days without holding resources;
- large contexts and artifacts passed between steps by reference;
- streaming partial output to a user interface while the run stays durable.

#### Status

Research and design, with an open-source release as the goal. The [Agent Control Plane](/projects/agent-control-plane/) keeps its durable execution behind an interface for exactly this reason.

### Search for agents

> An S3-native engine shaped around how agents query: many precise, iterative queries that mix full text, vectors and filters.

- Status: Exploring
- Period: 2026
- Role: Research & design
- Results: 400M+ documents indexed at Topo
- Stack: S3, BM25, vectors, MCP
- Tags: search, market study

#### The problem

Search engines were designed for a person typing a few words and reading ten results. Agents search differently. They send many precise queries in bursts, often in parallel, refine them as they go, and mix full text, vectors and structured filters. They read results as input for the next step, so a result has to be exact and fit in a token budget.

Coding agents show the pattern clearly. The leading ones search code with `grep`, `glob` and `read` rather than embeddings, and search takes a large share of their turns. Outside code, the same agents now need to search millions of files and documents that do not fit on a laptop.

#### Where it comes from

At Topo I ran a people and company index of more than 400 million documents, first on Quickwit, which keeps its index on S3, then on Elasticsearch. I know how cheap S3-native search can be, and how much an engine designed for people costs to bend toward machine workloads.

#### The market

I started with a market study rather than code. Vectors plus BM25 on object storage for AI apps is already a category, and Turbopuffer leads it. AWS now stores vectors in S3 directly, which pushes the price of plain vector storage toward the floor. A frontal clone would be squeezed from both sides.

The opening is the interface. No one sells the thing agents already know how to use, a file system with `ls`, `glob`, `grep` and `read`, plus semantic queries, as a product at the scale of S3.

#### Positioning

> The index behind your agents' grep, at S3 scale.

Each agent session gets a workspace that is searchable immediately, can be forked, and answers regex, BM25 and semantic queries. It is stored on S3, exposed with the shell and MCP semantics models already use, and billed per session and per fan-out.

#### What could differentiate it

| Axis | What the customer gets | Role |
| --- | --- | --- |
| Agent-native interface | File-system commands with exact grep semantics, plus semantic search, over millions of files | Core of the offer |
| Open format, local and cloud | The same index read by a library inside the agent's sandbox and by the managed service | Core of the offer |
| Ranking learned from traces | The engine learns which results agents actually opened and used, per tenant | Moat to build from day one |
| Ephemeral, forkable workspaces | An index per session, branch or commit, copy-on-write, with fast cold starts | Required |
| Native fan-out | Dozens of sub-queries in one call, deduplicated, billed as one | Launch feature |
| Token-sized answers | Excerpts sized to a token budget, with structure and stable cursors | Launch feature |
| Lowest price | Cheaper than the leader | Avoid as a pitch |

#### The trap

My starting thesis was that coding agents make new infrastructure cheap to build. That is true for everyone: competitors, customers who build in-house, and a leader that ships every month. So the moat will not be the engine. It has to be the open format and its ecosystem, distribution through agent platforms, and owning one precise workload.

#### What would make it a yes

Reading the study as an investor would: strong timing, a clear wedge, defensibility still to build. Before going further I want three design partners committed in writing, a benchmark on a real agent workload that beats grep and the leader on cold latency and tokens, and someone on the team who has shipped a search or storage engine.

### System 1 judges

> Fast, calibrated scoring: a judgment split into dozens of yes/no questions, answered as probabilities by a decision model in one call and aggregated in code. First use case: outbound emails.

- Status: Exploring
- Period: 2026
- Role: Method
- Results: ~65 atomic rules; 2,755 reference templates; One model call per email
- Tags: evals, calibration

#### The problem

An agent improves only as fast as its feedback. The usual LLM-as-a-judge asks a frontier model for a rating and a rationale. That takes seconds per draft, costs too much to run inside a loop, and is poorly calibrated. Such judges also show position, verbosity and self-enhancement biases ([Zheng et al., 2023](https://arxiv.org/abs/2306.05685)).

My first use case was a writing agent for outbound sales emails. It rewrites a draft until it passes, so the judge is called many times per email. It has to answer in under a second, cost a fraction of a cent, and say exactly what to fix.

#### The idea

Separate System 2 from System 1, in Kahneman's sense. A slow model does the expensive thinking once: it writes the rubric as narrow, checkable questions, each with a prewritten fix. A fast decision model answers those questions on every draft, as probabilities. Code does the arithmetic.

#### Method

1. Decompose
2. Route
3. Ask once
4. Score with probabilities
5. Aggregate in code
6. Calibrate

- **Decompose.** About 65 atomic rules in families: gates, deliverability, subject line, opening, personalization, value, call to action, tone, structure, follow-ups. One rule checks one requirement, as in TICK, where checklists raised judge–human exact agreement from 46.4% to 52.2% over direct scoring ([Cook et al., 2024](https://arxiv.org/abs/2410.03608)).
- **Route.** Anything code can measure exactly stays in code: length, links, empty variables, spam words, the ratio of "you" to "I", readability. Only judgment calls go to the model.
- **Ask once.** All judgment questions for an email go in one request to Jev, TypeSafe's decision model, which returns one probability per yes/no question. Adding questions barely changes latency, so splitting into many calls only adds cost.
- **Probabilities, not ratings.** A calibrated P(yes) is already a continuous score, so rules are yes/no questions with precise true/false criteria rather than 1-to-5 scales. G-Eval weights scores by output probabilities for the same reason ([Liu et al., 2023](https://arxiv.org/abs/2303.16634)).
- **Aggregate in code.** A failed gate caps the score whatever the other rules say. Answers in the uncertain band are flagged, not counted as failures. The email is split into indexed sentences, so each failed rule points at its sentence and returns its fix, with no second model call.
- **Calibrate.** 2,755 real templates ranked through pairwise comparisons serve as the reference. Reliability diagrams and expected calibration error check that a 0.8 means 80% ([Guo et al., 2017](https://arxiv.org/abs/1706.04599)).

#### Writing good questions

The craft is in the questions. A good rule names something observable. Not "is the personalization good?", but "if you replace the company name with a competitor's, is the first sentence still true?". Each rule is a small object: an ID, a family, code or model, the question and its criteria, a weight, a gate flag, when it applies (language, sequence step, seniority), and the fix.

The feedback the writing agent receives is short on purpose: the top three fixes, ranked by weight times the chance of failure. With forty fixes at once, the agent over-corrects and the loop oscillates. The loop stops when the score passes the threshold or stops improving, and keeps the best version rather than the last.

#### Why it transfers

The pattern fits anywhere an agent needs a reward signal in a tight loop: code review, support replies, extraction checks. A slow model writes the rubric, a fast calibrated model applies it, code aggregates. Emails are the first use case, not the point.

#### Side lab: training a small decision model

To understand how a model like Jev works, I am reproducing the idea at small scale on a laptop. A small open-weight encoder reads the state and all questions in one sequence; an attention mask lets each question see the state but not the other questions, so many decisions come out of a single forward pass. Separate heads handle choices, yes/no and ordinal answers. Training starts supervised, then moves to reinforcement learning rewarded on calibration, compared against a reward on accuracy alone to show how that makes a model overconfident.

#### Limits

- Calibration claimed by a vendor has to be measured on your own labelled set before you trust a threshold.
- Sixty-five rules are correlated. Their weights should be fitted to the reference ranking, not set by hand.
- A writing agent that optimizes a judge will find its blind spots. A held-out set ranked by people keeps it honest.

### Low-cost inference ASIC

> How low can the cost per million tokens go on a mature 12 nm node, with LPDDR and an SRAM cache instead of HBM?

- Status: Study
- Period: 2026
- Role: Feasibility study
- Results: ~12 nm node; No HBM, no CoWoS
- Stack: LPDDR, SRAM, INT4/FP4, vLLM, SGLang
- Tags: ASIC, inference, feasibility study

#### The question

How low can the cost per million tokens go on silicon anyone can still buy? Most inference chips race for latency. A large share of AI workloads does not need it: asynchronous agents, synthetic data generation, large-scale retrieval jobs. For those, throughput per dollar is the only number that matters.

> Build the truck, not the race car.

#### The thesis

A fabless ASIC specialized for Transformer inference, designed for the lowest cost per token rather than the lowest latency. Every architectural choice follows one thread: supply chain resilience. The real bottlenecks in AI chips today are high-bandwidth memory and advanced packaging, not silicon. A chip that needs neither can be sourced from several suppliers at every step.

| Choice | Instead of | Why |
| --- | --- | --- |
| LPDDR or GDDR, with an SRAM cache tier | HBM, or SRAM only | Standard memory with many suppliers. SRAM-only designs optimize for latency and run short of capacity on mature nodes. |
| Mature node, around 12 nm | Leading-edge nodes | Lower mask and wafer costs, more foundry options. |
| Standard packaging | CoWoS-class advanced packaging | Avoids the tightest bottleneck in the supply chain. |
| Minimal licensed IP | Large third-party IP blocks | Keeps the design portable between foundries. |
| Narrow native software stack | CUDA compatibility | CUDA's moat is software. A backend for vLLM and SGLang covering about ten open model families is enough for the target workloads. |

#### Making up for bandwidth

Without HBM, memory bandwidth is the constraint. The design compensates in three ways: heavy batching, which the target workloads allow; low-precision formats such as INT4 and FP4; and memory scheduling decided by the compiler. A deterministic, compiler-scheduled architecture also moves complexity from hardware into software, which matters because verification is roughly half to sixty percent of the labor in a chip project. Staying on the software side as long as possible is the cheapest way to reduce that effort.

#### The risks I accepted

- **Architectural obsolescence.** A Transformer-specialized chip takes about three years to design. Compiler programmability mitigates it but does not remove it.
- **Latency that will not compete.** By design. The chip is for batch work.
- **An unproven cost model.** The cost per token has to hold on real mixture-of-experts workloads, not only dense models.

#### What the study concluded

I ran a full feasibility study: technical feasibility, design cost and commercial viability. The architecture holds together on paper. The venture, as I would have started it, did not. It needs a co-founder who has already shipped silicon, which is a co-founder problem and not a hiring one. It needs an anchor customer, ideally a model maker willing to co-design. And it needs the cost model tested against real mixture-of-experts workloads before raising money.

The study also changed my view of where the leverage is. Reducing the cost of using compute moves the market more than reducing the cost of producing it. That pushed my later work toward the software layers of inference: how agents spend tokens, and how to route them.

#### What I took from it

I came to this with no background in semiconductors and built the domain from first principles: tape-out economics, memory hierarchies, packaging, verification flows from performance models to FPGA prototypes. The method transfers. Start from the constraint that actually binds, here memory and packaging supply, and let every other choice follow from it.

### MLP: neural networks from scratch

> I wrote my first neural network in 2012, rewrote it during an internship at Jalgos in 2015, and rebuilt it from scratch in 2026 as a small C++ library with no dependencies.

- Status: Released
- Period: 2012–2026
- Role: Solo project
- Results: 97.4% accuracy on MNIST; Gradients match finite differences to 10⁻⁷; Zero third-party libraries
- Stack: C++98, Make
- Tags: Neural networks, MNIST
- Links: [GitHub](https://github.com/leonard-henriquez/MLP)

#### Three versions, one repository

| Version | What it was | Where it stopped |
| --- | --- | --- |
| 2012 · Prototypes | Code::Blocks, in French. One neuron, perceptron rule, AND, OR and NOR truth tables | Linking neurons together |
| 2015 · Jalgos | A Qt interface, then a console program. MNIST on Eigen and MKL, multithreading, batch mode | 30 commits in five weeks |
| 2026 · Rewrite | C++98, no dependencies. Perceptron to multilayer network, tested | 97.4% on MNIST, live terminal demos |

Each version kept what the previous one taught and dropped the rest. The repository holds all three: the 2012 code and the 2015 code are each one tag away from the current one.

#### 2012: one neuron at a time

The first version was a set of Code::Blocks projects written in French: `SimpleNeurone`, `Neurons`, `Perceptron`, `NeuronalClass`, and a Qt window that never got past its skeleton. The goal was to understand a single neuron before stacking them.

A single neuron was trained with the perceptron rule on AND, OR and NOR, read from truth tables in a small text format of my own (`exemples 4; entrees 2; 1/1/1; ...`). The next step, linking neurons together through pointers, never compiled.

Those truth tables are still in the repository, unchanged since April 2012, and the current library still reads them.

#### 2015: scaling up at Jalgos

Three years later, during a summer internship at Jalgos, I picked the idea up again with a real dataset: MNIST, 60,000 handwritten digits. The repository started there, on July 13, 2015, and its 30 commits from that summer are untouched.

It began as a Qt interface with dialogs to load MNIST and run a network. Two weeks in, I dropped the interface for a console program:

- matrix maths on Eigen, with Intel MKL and multithreading;
- a batch mode, a validation set to measure generalisation, and an adaptive learning rate;
- networks saved to and loaded from files, and a test mode;
- a branch benchmarking iterative against recursive computation.

It leaned on two large libraries I had not written. Baptiste Henriquez contributed the man page, the last commit of that summer.

#### 2026: the rewrite, with no dependencies

Coming back to it, I wanted what the 2015 version lacked: every line of the maths written by hand, with no library underneath, small enough to read and covered by tests. The 2015 code was removed from the main branch and kept under the `2015-jalgos` tag; the rewrite started from scratch, keeping only the 2012 truth tables.

It is plain C++98 and a Makefile, nothing else:

- a `Perceptron`, then `Layer` and `Network` classes trained by stochastic gradient descent;
- step, sigmoid, tanh and linear activations, chosen per layer;
- an MNIST reader, PGM image loading, and a network file format that round-trips exactly;
- a portable random generator, so a seed gives the same network on every machine;
- unit tests, including a check of every gradient against finite differences;
- a terminal interface that shows the networks learning, frame by frame.

#### How it learns

Each neuron computes a weighted sum of its inputs plus a bias, then applies its activation: y = f(w · x + b). Training shows the network one example at a time and nudges every weight against the gradient of the squared error.

1. **Forward pass.** Each layer computes its outputs and keeps its inputs and weighted sums s for the way back.
2. **Backward pass.** The output layer starts from dE/dy = y − t. Each layer turns the gradient it receives into a delta per neuron, passes the gradient on to the layer before, then updates its own weights:

```text
δⱼ    = ∂E/∂yⱼ · f′(sⱼ)
∂E/∂xᵢ = Σⱼ δⱼ · wⱼᵢ
wⱼᵢ   ← wⱼᵢ − η · δⱼ · xᵢ
```

The step I trust least is the one I wrote myself, so the tests check it. For a 3-4-3-2 network, they nudge every weight by 10⁻⁶, measure how the error moves, and compare with the update backpropagation made. They agree to 10⁻⁷ on every weight.

#### Results

A 784-100-10 network, measured on the 10,000 MNIST test images it never trains on (`bin/mnist_train` with default settings, seed 1). Before training: 10.1%, chance.

| Epoch | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Test accuracy | 93.9% | 95.7% | 96.2% | 96.6% | 97.0% | 97.3% | 97.2% | 97.4% | 97.5% | 97.4% |

Most of the gain comes in the first epoch; from the sixth on, accuracy stays between 97.2% and 97.5%. The hardest digits are 8 (94.9%), most often read as 3, and 7 (96.0%), most often read as 2.

#### Try it

It needs a C++ compiler and `make`, nothing else. From the repository root:

```sh
make && make test             # build, then run the unit tests
bin/tui                       # interactive demos in the terminal
scripts/download_mnist.sh     # 11 MB, needed for the MNIST demos
```

The terminal interface has three demos:

| Demo | What you watch |
| --- | --- |
| Logic gates | A perceptron and a 2-3-1 network learn AND, OR, NOR and XOR side by side, with the error curve and a map of each network's output redrawn as it trains. The perceptron gives up on XOR; the hidden layer solves it in about 4,000 epochs. |
| MNIST training | A 784-100-10 network trains live on 60,000 digits at about 10,000 images per second, with the current image, the ten outputs and the test accuracy climbing. |
| MNIST test | Browse the 10,000 test digits, jump to the next mistake, or try the hand-drawn digits shipped in the repository. |

Your own handwriting works too: draw a digit, convert it with `magick my-digit.png my-digit.pgm`, train a network once (`bin/mnist_train`, about a minute), and run `bin/recognize data/mnist/mnist.mlp my-digit.pgm`. Any size works, black on white or white on black: the image is cropped, scaled to 20×20 and centred by its centre of mass, the way MNIST itself was built.

#### Trade-offs, chosen on purpose

| Choice | What it costs |
| --- | --- |
| No libraries: every matrix loop written by hand | Slower than Eigen or BLAS, but every operation is readable in a few lines |
| C++98 only | No `auto` or smart pointers, but it builds with any compiler of the last twenty years |
| One example at a time (online gradient descent) | No batching or GPU, but backpropagation reads exactly like the maths |
| Plain-text formats for datasets and networks | Larger files, but a trained network can be opened and read |
| A terminal interface built on ANSI escape codes, not ncurses | More code to handle keys and resizing, and still zero dependencies |

#### Status

Released. The library, the command line programs and the terminal demos are on [GitHub](https://github.com/leonard-henriquez/MLP), with the 2012 and 2015 versions one tag away: [`2012-prototypes`](https://github.com/leonard-henriquez/MLP/tree/2012-prototypes) and [`2015-jalgos`](https://github.com/leonard-henriquez/MLP/tree/2015-jalgos).

## Principles

### 1. Agents are distributed systems

A run is a long-lived workflow calling slow models and flaky APIs. It needs durable execution, retries, idempotent steps and replay.

### 2. Context beats prompts

Most quality gains came from what the model sees: CRM history, call transcripts, the right tools at the right step. Evals tell whether a change helped.

### 3. Autonomy is earned with feedback

Fast checks let agents catch their own mistakes: strict CI for coding agents, human review wherever a mistake is expensive.

## Recognition

- 2024: Y Combinator W24
- 2024: Talk: LangGraph in production
- 2024: Judge, Mistral AI hackathon, San Francisco
- 2025: Invited to the Élysée to help prepare the AI Action Summit

---

Source: https://hqz.me/ · Generated 2026-10-28
