← Back

bakery

GitHub: vebrasmusic/bakery

Why I built it

I spend a lot of time working in parallel: multiple agents on multiple features, often across multiple worktrees. I can read diffs and run tests, but fully validating a feature usually meant checking out a branch into my main local environment, running the app, and manually clicking around. That breaks flow and makes multi-worktree development feel fake.

Bakery fixes that by giving each worktree a full, runnable slice of the app locally. Each slice gets its own URL and (optionally) its own ports for services and databases. I can open each feature in the browser at the same time, finish my manual checks, and then open a PR with confidence.

The idea: pies and slices

A pie is a project namespace. A slice is a runnable environment inside that pie (typically a worktree). You can have multiple slices per pie, and multiple pies for different projects, all running in parallel. Bakery keeps the metadata and routing; your scripts start the actual services on the allocated ports.

How it works

Bakery runs a local daemon with a CLI and a TUI. The control plane is a small HTTP API that creates pies and slices. When you create a slice, Bakery:

  1. Allocates free ports from a configured range (defaults to 30000-45000).
  2. Chooses a router port (tries 80, 443, 4080, then falls back to any available port).
  3. Returns JSON describing the slice: host, routerPort, allocatedPorts, and resources with route metadata.

The important point is what Bakery does not do: it does not orchestrate containers or start your processes. It only allocates ports and routes hosts to those ports. Your setup.sh or dev.sh scripts use the CLI output to generate .env values, then boot your app on the allocated ports.

Design choices

Why TypeScript? This project isn’t performance-locked; the core work is local orchestration and routing. TypeScript makes the codebase easy for me to audit and reason about, which matters when I’m reading big diffs or PRs. That tradeoff felt right for a developer tool where clarity beats micro-optimizations.

Why a TUI? Partly for fun. I wanted to design a terminal UI that felt good to use, and it doubles as a fast, glanceable dashboard for pies and slices.

Why no deployment/orchestration? Scope control. I wanted Bakery to do one thing well: allocate ports and route traffic. Starting services, running containers, and deploying are all user-land concerns. Keeping the surface area narrow kept the tool stable and easier to integrate with existing scripts.

Routing + cookie isolation

The router is an embedded proxy that routes requests based on the Host header. A primary slice host looks like:

<pie>-s<ordinal>.localtest.me

Subdomain resources look like:

<resource>.<pie>-s<ordinal>.localtest.me

Because each slice has its own host, cookies are isolated by hostname. That avoids the usual localhost cookie clashes when running multiple full stacks side-by-side. Some auth providers (notably Google OAuth) still require explicit redirect URI allowlists, so those need to include each slice host.

Typical workflow

  1. bakery up
  2. bakery pie create --name mypie
  3. bakery slice create --pie mypie --numresources 3
  4. Use the returned ports to start your app and services.
  5. Open the slice URL in your browser and validate the full app instance.

This gives you a realistic, multi-instance local environment without the branch checkout shuffle.