← blog

Why I Open-Sourced Fact0 and Shut Down the Hosted Service

September 23, 2026 (1d ago) · 11 min read

failure
personal story
saas
open-source
ai
postmortem
Table of contents

For more than seven months I worked on the idea behind Fact0: a system for recording and inspecting what an AI agent actually did. On September 16, 2026, I shut down its AWS infrastructure. The application is now open source under the MIT license.

In that time I spoke with a lot of people, including people at three or more startups. I gave four potential clients free access for early feedback. Early users started pushing real logs into Fact0 and told me what they thought. By the time I decided to stop, nobody was using it.

Pitching it was hard. Onboarding people was harder. Eventually I had to treat that difficulty as the feedback it was.

This is what I built, where I got it wrong, what the engineering taught me, and why open source is where Fact0 continues.

Fact0 landing page


What Fact0 actually did

When an agent does something, working out what happened is harder than it should be. There is a prompt, some model responses, tool calls, intermediate decisions, and a failure somewhere in the middle. Ordinary application logs flatten all of that into lines.

Fact0 recorded that activity and let you inspect it. A Go API, PostgreSQL for storage, a Next.js dashboard. You could open an execution, see parent and child operations, follow a timeline and replay recorded activity. A separate audit log chained records together with hashes, so a change to recorded history could be detected by verification.

The engineering was solid. The problem was that I had built three products and was trying to sell them as one.

One was a developer tool for understanding agent behaviour. One was an audit-record system. And the commercial positioning reached further than both, toward helping teams with enterprise security reviews and governance evidence. Later, Claude Code gave me a more concrete place to capture and inspect agent activity during development.


Why it failed commercially

1. I let the scope grow before I understood one use case

Each direction made sense on its own. Together they were much harder to explain. Debugging an execution and getting a company through a security review are different jobs, with different workflows and different people signing off.

That is my biggest product mistake. I widened the scope before I understood the full set of requirements behind a single use case I could actually support.

2. The requirements that came back were not the ones I had built for

I am keeping the four prospects anonymous, and I am not going to flatten separate conversations into one tidy explanation. They had their own reasons.

What did come up: they needed the data in a particular form, they had AWS-related requirements, and they needed setup I was not ready to provide. With the resources I had, meeting them would have meant taking on a much broader commitment.

Fact0's hosted application already ran on AWS. That is not the same as having built everything a client needed around their AWS. For an infrastructure product, the environment and the workflow around it are part of what you are actually selling.

3. Free access removed the purchase decision, not the work

Giving the tool away made it easy to try. It did not make it fit.

People spent real time with it, sent logs, and gave me feedback. That was generous, and it was also the clearest signal I got. A working integration proved the recording system worked. It did not prove the product matched the way they needed to work.

I had been counting the first thing as progress and not measuring the second.

There was also more than one person to convince. An engineer does the integration, a manager owns the budget, and a security reviewer decides whether the resulting records are worth anything. Ingestion working is the start of that conversation, not the end of it.

Four prospects is a thin basis for a general conclusion, and I am not drawing one.


On being the wrong founder for this

At one point I called myself the wrong person for product-market fit here. I want to be more precise than that.

The project proved I could build across the API, database, frontend, integrations and deployment. The commercial version also needed customer discovery, positioning, onboarding, support, and credibility on security-related claims. I had made all of it one job, and that job was mine.

So the lesson I am carrying forward: define what you are prepared to build, operate and support as carefully as you define the feature list. When feedback keeps pointing at a different product shape, saying yes to each request is a business decision, not a backlog item.


What the engineering taught me

Reviewing the code for release surfaced work still to do in the parts I was keeping. Having the major features implemented had left real correctness questions open.

Ingestion is where correctness actually lives. Retries must not duplicate records or merge unrelated activity. A child span has to land on the right execution and respect tenant boundaries. A running parent operation has to exist before its children arrive, then complete without erasing its own earlier lifecycle. Late-arriving events must not distort the order or duration of a replay.

For a tool whose entire job is telling you what happened, those are not edge cases. A timeline that looks plausible and is wrong is worse than none at all.

A hash chain proves less than it sounds like it does. Hashing a record is the easy part. The format has to define which fields are covered, how the JSON is represented, how timestamps are normalised, and how each record's hash links to the one before it. Verification also has to survive events arriving late, or someone filtering the history by date.

Even when all of that is right, a valid chain tells you about the integrity of the records that were captured. It does not prove every action was captured, or that the submitted events were truthful, or that an agent behaved safely, and it does not establish regulatory compliance. An administrator who controls the database and the signing keys sits inside the trust boundary too.

I had to watch my own language here. The commercial promise drifts larger than the mechanism very easily.

Capture has edges everywhere. The Claude Code integration had to preserve supported content, cope with concurrent hooks, hold failed deliveries through an outage, and report when a transcript was missing or incomplete. A preview truncated in the UI must not quietly become truncation in storage.

The release checks covered Unicode, very long tool output, deliberately failing tools, and the JSON integer 9007199254740993, which loses precision the moment anything casts it to an ordinary JavaScript number. I also checked a real Claude Code session against its source transcript, including replay and audit export.

Those checks tell you that specific behaviours are correct. They are not evidence of adoption, and they do not make the software production-ready for every deployment.


What it actually cost

Let me start with the dollars, because they are the least interesting part of the story.

Fact0 ran in Singapore. Between the first deploy in May 2026 and the September shutdown, that region accounted for $684.00 of AWS usage:

ap-southeast-1 Actual, May to Sep 2026 Annual run-rate
Elastic Container Service 568.99 1,745.16
Virtual Private Cloud 68.93 224.91
CloudWatch 45.51 168.41
RDS, load balancing, container registry 0.57 1.93
Total 684.00 2,140.42

The left column is billed usage for the months Fact0 existed. The right one annualises the rate it settled into over June, July and August, so it is a projection rather than a bill I received.

The account also hosted another project in Virginia, which takes total account usage across those months to $819.67. Credits covered all of it and the recorded net was $0.00. So this is what Fact0 consumed, not cash that left my account, and the regional split is attribution rather than per-project tagged accounting. Domains, other providers, subscriptions and my own time sit outside the table entirely.

Two things in there are worth sitting with.

The first is that 83% of the spend is ECS: containers billed by the hour, running whether or not a single request arrived. The second is the monthly curve, which goes $63.88, $170.55, $183.71, $180.84 and then flattens. That is infrastructure with its own momentum, not infrastructure responding to demand.

Left alone, that is roughly $2,140 a year to keep running, $1,745 of it ECS. Credits covered the real charges, so I never paid that. It was still being spent.

So AWS bills did not kill Fact0; credits covered them. But a zero invoice is not the same as a zero liability. The application kept consuming resources on its own schedule, and I stayed responsible for its configuration, credentials, data and eventual cleanup. Credits do not remove any of that. They just stop you noticing it.

The real cost was attention, spread across more than seven months.

For as long as the hosted service stayed up, I was on the hook for it: keeping it running, keeping it secure, and deciding whether to extend it toward requirements I had not planned for. That is the budget that actually ran out. I have not put a number on it, but it was the expensive line by a wide margin.

By the decision point there was no active usage to justify spending more of it. That was the whole calculation.


What is in the open-source release

The application is on GitHub under the MIT license. The public SDK and documentation history were preserved and the application was added as a reviewed source snapshot; private deployment history, credentials, backups and founder documents stayed out.

The released product has a much smaller description than the one I was pitching:

Self-hosted execution inspection and audit records for AI agents, with Python and Claude Code integrations.

It keeps execution inspection, timelines, dependency graphs, replay, audit verification and authenticated exports. Billing, invitations, founder administration, public sharing, external alerting and policy enforcement are disabled. The supported setup is one owner, one workspace, fresh install: Docker Compose runs the Go API, the Next.js application and PostgreSQL, with no AWS account, Google OAuth, Redis or email provider needed.

Getting there took more than pushing the code up. Everything my hosted environment had quietly handled needed explicit local setup and documented behaviour: a repeatable database baseline, authentication that works out of the box, a production frontend build, and clear instructions for the first thing worth doing.

Two things before you run it. Full supported content is captured by default, so prompts, source code, tool output and errors can end up in the installation and in the local retry spool; reduced capture modes exist, and the local data and backups are yours to protect. And the release is explicitly experimental: best-effort maintenance, no SLA, replay reconstructs recorded history rather than rerunning an agent, and self-hosting puts storage, access and backups on the operator.

Open source does not answer the adoption question. Making the code public tells me nothing about whether anyone will use it. I am doing it because the work can stay available and useful without me running a commercial service behind it.


The shutdown

The teardown turned into one last engineering exercise. With Codex helping on inventory and verification, I kept an encrypted local recovery archive and verified an isolated database restore before deleting any hosted data. Then I retired the services and removed the database, snapshots, container images, logs and the rest of the identified billable resources, and disabled the old deployment automation and application credentials.

I checked across 17 enabled AWS regions, covering both projects that had shared the account. Stopping the containers would have left plenty behind, including storage, backups, and the machinery that could deploy everything again.

The AWS account is still open and the docs are still up. The shutdown record covers identified AWS workloads and billable application resources; usage already accrued can still appear later as billing catches up.


What I would do differently

Fact0 did not become the product I wanted it to be. People tried it, pushed logs and showed me the gap between what I had built and what they needed. I learned a lot about the correctness of agent records, and more than that about the scope I am actually prepared to take on.

If the code is useful to you, take it.

Read next