Skip to main content
Dispatches

Fibe Blog

Updates, guides, and engineering notes from the workshop.

Mana and Sparks: building a double-entry wallet that can not go wrong

· 22 min read

Every Fibe environment costs money to keep alive. A Marquee is a real Docker host with a real VM bill behind it, and the only thing standing between "your agent is coding" and "nothing runs" is whether the wallet had enough in it this morning. That makes the wallet the most boring-looking and least forgiving piece of the platform. It is not allowed to lose a credit, double-charge a day, or — the cardinal sin of any money system — let a balance drift negative.

This is the story of how we built that wallet: two currencies, a double-entry ledger where every movement is mirrored exactly once, pessimistic locks, and idempotency keys so aggressive that the same operation can be retried a hundred times and still only happen once. None of it is clever. That is the point. In billing, clever is a liability; the goal is a system whose invariants are so tight that the failure modes simply do not exist.

Docker-truth reconciliation: making the database agree with `docker compose ps`

· 10 min read

There are two stories about what your Playground is doing. One lives in Postgres — a status that says running, error, or stopped. The other lives on a Docker host we don't own, reachable only over SSH, and you read it by running docker compose ps. Most of the time they agree; the interesting engineering is all about what happens when they don't.

This is a post about one reconciler and the small set of rules it uses to decide which story is true. The headline rule is easy to say and weirdly hard to honor: trust the daemon as the source of truth — but only when you can actually see it. A Playground on a host that clearly threw its containers away should be marked stopped; one on a host that simply didn't answer our SSH knock should be left exactly as it is. Telling those two apart is the whole job.

The Fibe security model: scopes, sessions, secrets, and 2FA

· 10 min read

Fibe hands every Player a Docker host and lets agents, CLIs, and browsers spin up real environments on it. That is a lot of power to lend out over an API, and the whole platform leans on a small set of identity primitives doing their job quietly: a key that can only do what it says, a session that actually expires, a vault that never hands back a plaintext it didn't have to, and a log nobody can rewrite after the fact.

None of this is glamorous, and that's the point — it's the part of the system we want boring and correct.

bin/check-full: the quality gate behind every change

· 10 min read

There is exactly one thing you need to know before opening a pull request against the Fibe Rails app: run bin/check-full. Not "run RuboCop, then Sorbet, then remember the architecture script, then the specs, oh and did you regenerate coverage?" Just the one command. If it's green, your change is ready for human eyes. If it's red, it tells you precisely what to fix.

That simplicity is the point — and it matters even more now that coding agents draft so many of our changes. This is the story of our canonical quality gate: what's inside it, and why it's one command instead of a checklist.

Driving Fibe from the terminal: the fibe CLI and Go SDK

· 15 min read

The browser is great for poking at a Playground. But the moment you want a launch to happen on push, or you want to spin up the same environment fifty times in a load test, or you want a Slack bot that reports which of your Playgrounds are unhealthy — you want the terminal. That's what the fibe CLI is for, and underneath it, a Go library you can embed directly in your own programs.

The nice part: it's one binary. The same executable you brew install is the CLI, the Go dependency, and an MCP server for AI agents. Same auth, same resource model, same retry logic. This guide walks you from brew install to a fully scripted launch — install, authenticate with profiles, fire a launch, wait for it to come up, and read its URL — then shows when to drop down into the Go library instead.

Exposure strategy: public, internal, path-based, root, or none

· 15 min read

Every Compose file you bring to Fibe has the same hidden decision baked into it, one service at a time: who gets to reach this thing? On your laptop you answered it by sprinkling ports: entries around until docker compose up let you hit the app in a browser. That habit does not survive contact with a real host. On Fibe, host ports are not how anything becomes reachable, and a ports: line that you think is exposing your app is quietly being stripped before launch.

The good news is that the decision is small and mechanical once you can see it. There are exactly five outcomes for any service — public, internal, root, path-shared, or none — and they're selected by two or three labels in the fibe.gg/* namespace. This guide walks the decision in order, shows the YAML for each pattern, and calls out the gotchas that bite people the first time (the bare-subdomain collision, the at-most-one-@ rule, and why localhost binds are invisible). By the end you'll be able to look at any Compose service and know, in about five seconds, which of the five it is.

One 402 to rule them all: the not-funded gate

· 6 min read

Every platform that rents compute eventually asks the same question in a hundred different places: is this allowed to run right now? On Fibe, "right now" means funded — a Marquee that has paid for the current service-day. We answer that question with exactly one check and one HTTP status, and we route the consequences differently depending on who's asking.

This is the story of the not-funded gate — a single 402 that sits in front of roughly a hundred call sites.

Stop is not delete: the data-volume preservation contract

· 10 min read

Here is the support ticket we never want to receive: "I stopped my Genie to save money over the weekend, and when I came back, everything it had learned about my codebase was gone."

For an AI coding agent, that's the worst possible failure. The agent's value compounds over time — its working state, its history, the files it wrote, the config it tuned — and all of it lives on disk, in Docker volumes, not in the container. So we drew a hard line early: stopping a Genie must never touch its data. Only one explicit, confirmed action deletes it. This post is about that contract and the small amount of code that makes "stop" and "delete" genuinely different.

Grace, suspension, and scheduled destroy: humane billing for ephemeral environments

· 9 min read

Every billing system has a moment it would rather not talk about: the one where the money stops. The card expires, the wallet empties, the trial ends — and now you have an environment that costs real money to keep alive and a customer no longer paying for it. The naive answer is brutal and tempting: tear it down, move on.

We didn't want to build that. Fibe funds a Marquee — your Docker host — out of a daily wallet, and when a day can't be funded, the system enters a deliberate, recoverable sequence rather than a guillotine. This post is about that sequence: the grace incident, the three-day window, the seven-day retention, and the invariant we cared about most — starting grace never marks your billing as paid, and a suspended-but-unrepaid environment can never slip back to "active."

The image build gate: one build per commit, verified

· 10 min read

Here is a bug that does not look like a bug. You push a commit, a build kicks off, it goes green, your environment comes up. Everything works. Except the image inside it was built from a different commit than the one you pushed — a stale checkout, a cached layer, a race between two builds for the same branch. Nothing errored. The dashboard says success. And you spend an afternoon debugging code that was never actually deployed.

That class of failure — a build confidently wrong about what it produced — is the one we decided never to ship to a Player. So Fibe's image builds follow one stubborn rule: a build must be deterministic and honest about which commit it produced. This post is about how each build record enforces that, and the two checks that will fail a build rather than let it lie.