Skip to main content
Dispatches

Fibe Blog

Updates, guides, and engineering notes from the workshop.

A real conversion, end to end: a Rails + Postgres app on Fibe

· 15 min read

You have a Rails app. It has a web service, a Postgres database, and a Sidekiq worker, and it runs on your laptop with a docker-compose.yml you copy-pasted from a blog post two years ago. You want it on Fibe: a real HTTPS URL, live logs, a terminal, source pulled from your repo, secrets that aren't sitting in plaintext, and migrations that run before anyone hits the app.

This post does the whole conversion, top to bottom: we start from a realistic raw Compose file and turn it, one decision at a time, into a polished, launchable template — the kind you'd publish to the Bazaar. By the end you'll have a file you can click Launch on, and a mental model for why each label is there.

Catching design bugs before code: formal models in Alloy

· 10 min read

Most of our nastiest bugs were never typos. They were a state machine that looked right in the PR, passed its tests, and then met a customer doing something perfectly reasonable that nobody had drawn on the whiteboard. A Playground stuck in an error state forever. A chat that vanished because a healthcheck flapped. A runtime launched on a Marquee that hadn't been funded.

So we started writing down the hard lifecycles in Alloy, a relational modeling language, and letting a solver do the part humans are worst at: trying every small, weird combination of states and asking "does your invariant actually hold here?" Often it doesn't — and the solver tells us exactly which world breaks it.

Registry auth precedence: we never pull your images with our tokens

· 10 min read

Every time Fibe brings up a Playground, provisioning has to answer a small, unglamorous question: which credentials do we hand the Docker daemon so it can pull your private images? It's plumbing — but the wrong answer is the kind of thing that turns into a security incident with a postmortem and a regretful blog post.

So here is the one rule we refuse to bend: when we pull an image from GitHub Container Registry, we authenticate with your credentials and only your credentials. Fibe's own platform tokens never touch your pulls — not as a convenience fallback, not for a system mirror, not "just this once" to unblock a build. This post walks through how the credential merge works and what we get out of keeping our tokens on the other side of a wall.

Playguard: the 60-second reconciler that keeps everything alive

· 22 min read

Kubernetes has a luxury Fibe doesn't: it owns the nodes. The kubelet lives on the box, watches the local container runtime, and the control plane can assume the daemon is there and answering. We can't assume any of that. A Player's Marquee might be a Scaleway VM we provisioned, or it might be a laptop under someone's desk reachable only over SSH. The Docker daemon can vanish mid-reconcile. The network can swallow a docker compose up halfway through. And the one rule we are never allowed to break is the one that matters most to the person using it: don't throw away my work.

Playguard is our answer. It's a control loop — the same shape as a Kubernetes reconciler — that runs once a minute per Marquee, compares declared state against real Docker state over an SSH link we don't trust, and nudges reality back toward what you asked for. The interesting parts aren't the happy paths. They're all the places where it decides to do nothing, on purpose.

Publishing to the Bazaar: a template-publish checklist

· 15 min read

You've got a template that works. It launches on your Marquee, the URLs resolve, the database comes up. So you flip the Make public toggle and it's in the Bazaar — instantly, for everyone, with no review queue standing between your YAML and the next person who clicks Launch.

That last part is the whole reason this checklist exists. A public version is live the moment you publish it. There's no reviewer to catch the password you left in a default:, no queue to bounce the template back because you forgot a category. The bar you ship at is the bar you set yourself. This is a walkthrough of how to set it high: what to check, why each check matters to the person on the other end, and a literal copy-paste list at the bottom.

Observability, honestly: Sentry, health checks, and structured logs

· 10 min read

Every infra engineer has a fantasy where a beautiful dashboard catches the incident before the customer does — heatmaps, a p99 graph that turns amber at the right moment, a wall-mounted TV. We don't have any of that. At Fibe, observability is five plain things: errors go to Sentry, a health endpoint, structured JSON logs, an immutable audit log of every meaningful action, and a reconciler that runs every sixty seconds and tells us when reality has drifted. No Prometheus, no Grafana. For a team our size that's not a gap — it's the right call.

Core vs full: designing the Fibe CLI and MCP tool surface

· 10 min read

The Fibe SDK is one Go binary doing two jobs. Type fibe playgrounds list and it's a normal Cobra CLI. Run fibe mcp serve and the same binary becomes a Model Context Protocol server, so an AI agent — Claude, Codex, Cursor, whoever — can drive your Marquee without paying the fork-and-exec cost of shelling out to the CLI on every operation.

That second job came with a problem we didn't appreciate until we watched agents fail at it. A platform like Fibe has a lot of capabilities: provision a Marquee, launch a Playground, connect a repo through Props, start a Genie agent chat, read logs, manage secrets, fund a wallet. Expose every one as a native MCP tool and you hand the agent a menu with hundreds of items — which, counterintuitively, makes the agent worse. So we split the surface into tiers, where "hidden" never means "gone."

An error taxonomy that routes itself: retry vs user-error vs fatal

· 9 min read

Provisioning a Playground touches more moving parts than we'd like to admit. We SSH into a Marquee, clone source from a Prop, merge registry credentials, build an image, generate a Compose file, and bring it up behind Traefik. Each step can fail, and for wildly different reasons: a flaky network, a typo in a branch name, a server that ran out of disk, a Docker daemon that blinked.

For a long time, "what do we do when step N fails?" was answered by a human reading a Sidekiq backtrace. That doesn't scale, and worse, it's inconsistent — the same failure handled two different ways on two different days. So we turned operational judgment into data. Every failure gets a category, and the category — not a person, not an ad-hoc rescue clause — decides what's next.

Cron and commits: scheduling jobs and triggering them from Git

· 14 min read

You already have a Trick — a job-mode Template that runs your tests, takes a backup, or migrates a database, then exits and records a result. So far you've been launching it by hand. The next move is to stop: have Fibe fire it at 3 a.m. every night, or fire it the instant someone pushes a commit. Both are two extra keys in the template's metadata block. No external cron daemon, no GitHub Actions YAML, no second CI runner that drifts away from your dev environment.

This guide is the hands-on version. We'll wire up a nightly Postgres backup on a cron schedule and a test-runner that fires on every pull request, and we'll be precise about the parts that trip people up: which branch a triggered run actually checks out, why a schedule that "should" fire at midnight runs at the wrong hour, and what Fibe does not tell GitHub when a run finishes.

How we test a Docker platform across five languages

· 20 min read

Most products are software that runs on infrastructure. Fibe's product is infrastructure: a Player funds a Marquee (a Docker host), and on it we deploy Playgrounds, Tricks, and AI agent sidecars as Docker-Compose projects, route them through Traefik with real wildcard TLS, and continuously heal them with a reconciler. When the thing you ship is "a Docker daemon does what the database said it should," your test pyramid has a problem the textbook diagram never warns you about: the genuinely end-to-end test needs a genuine Docker daemon, and that is slow, heavy, and flaky in all the classic ways.

So we test in five languages, with surfaces that range from sub-millisecond Rust unit tests to a ten-minute Docker-in-Docker run that spins up a real Playground. The interesting part isn't the list. It's the rule we use to decide which surface a given change actually deserves, and how a pile of formal models lets us not write some tests at all.