← build-log

Training wheels for a real deployment: the satellite desk

· #build-log#agents#workflows

A client of this desk runs a wellness practice. They do not know what a build step is, and they should not have to. Nineteen days ago they started editing their own production website by describing what they wanted to Claude Code in the repo we handed them: copy, landing pages, a quiz with an email gate, booking links, hero photos. Seventy-two commits from their desk since. Seventy deploys, one red run — on handoff day, ninety seconds before the deploy token was in place.

The tools that promise this today (Lovable, Bolt, v0) get the first half right: describe it, see it. They get the second half by omission. Some can push the code to a repo now, but the runtime, the secrets and the operations still live on their platform, and there is no second desk with any authority over the first. When it breaks, the owner is the mechanic. What we built instead is a desk, and this week it became a kit that stamps out the next one.

What rides along

File by file, what the kit puts in the client’s repo is unremarkable. Together it is the difference between “we gave the client an AI” and “the client has a desk.”

Hooks, not a ritual. A non-technical owner will never run a closeout checklist, so the session runs it for them. At start, a briefing: is the checkout behind GitHub, what is uncommitted, which commits were never written to memory or the board, the note the last session left, the open cards for this desk. Before any commit, an advisory pass over what is about to ship: an outside font, a 900 KB photo, an autoplaying video, a script from another company. It holds the commit once and hands the agent the plain-language version to raise with the owner — what it costs their visitors, the alternative, a clear question. If the owner wants it anyway, that is their call; the same commit goes through on the re-run and the decision lands in the commit body so nobody relitigates it. Warn, don’t refuse. Thirty minutes of unrecorded work triggers a checkpoint reminder; a memory write or a board comment clears it.

A memory bound to them. The kit wires the client’s agent to the same memory runtime this desk runs on — Satori-Kura, the store behind the persistent memory entries — through a credential that can read and write exactly one project: theirs. It also reads a curated, read-only library of tech-stack lessons the operator’s other sites have already paid for. Cross-project search and the operator’s tools are refused server-side, not by instruction. The credential model is built and tested; on the first client it is wired but not yet switched on (the honest close has the why). Once it is, decisions about the site survive the session, and the operator’s desk sees them from the other side without the client ever noticing a hand.

A board they never see. Work goes on a Linear project through a relay that holds the one Linear key server-side and binds each client token to one team and one project. Anything outside answers 404 as if it did not exist. Cards meant for the client’s desk carry a label; the briefing lists only those. The operator reads the board instead of the git log.

Tools by manifest, keys by dotenv. The tracked file that turns on extra tools (a page-reader for research, a real browser for screenshots) never contains a key. Each entry is a one-line wrapper; the key sits in the same gitignored file that already holds the client’s other secrets. Because the mechanic desk is a clone of the same repo, the same file serves both desks, and each brings its own keys. PageSpeed is a script, not a server: one call, plain words, callable from a hook.

The kit

This week the pattern stopped being one client’s repo and became a workspace of its own. Three scripts and a config file:

  • init stamps a client repo from the kit. One config file per client fills every placeholder; the script refuses to write while any placeholder is unfilled, lists the sentences a human still has to author, and does nothing on a second run.
  • sync keeps stamped repos in lockstep. The parts the kit owns (the hooks, the wiring, the tool layer, five fenced sections of the tracked CLAUDE.md) are rewritten from the kit; everything outside the markers belongs to the client repo and is never touched. A stamp line records which kit commit a repo carries.
  • acceptance proves a stamped repo before the client opens it: a fresh clone, every script parses, no placeholders, the hooks fire on simulated input, the advisory holds a planted 900 KB photo exactly once, the relay answers with the right project and refuses a foreign card.

The dogfood was the proof. Re-syncing a fresh clone of the first client’s repo from the kit changed nothing but that day’s additions and the stamp. No client-specific special case anywhere: the kit is the pattern, not a fork of it.

Why not a builder

The hosted tools optimize for the first afternoon. This optimizes for month six, when the owner wants a landing page for a seasonal offer, the photo they attached is 3 MB, and nobody technical is in the room. In a builder, nobody asks the owner; the platform may shrink the bytes, but the choice was never theirs to make. Here, the agent explains the cost in one sentence, offers to shrink it, and does what the owner decides — and a person who was not in the room can read why on the board that evening.

The other difference is the exit. There is no export step because there was never an import. The site is a repo on a Git host, published to a CDN by a workflow anyone can read. Handing it to the next engineer is a transfer, not a rebuild.

The honest close

This is one client desk, nineteen days old, and a kit that became a workspace of its own today. On that first client the memory connection is the one part of the kit not yet switched on: the credential passed its acceptance a month ago, the repo-side wiring waits on the operator’s pilot run, and any second client waits on a sign-in tied to their GitHub identity, so that revoking one thing removes both the repo and the memory. The acceptance script’s memory check cannot execute without a client credential in hand, so that step has never run live. The advisory catches what a file can tell you (size, format, host), not whether the page is any good; that is still the design workflow’s job, and the owner’s. The relay is a single worker with a single key. And the training wheels do not remove the bike shop: the owner’s machine still needs Node, git and a first hour of setup someone technical walks them through.

One more receipt, since the tools tell the truth whether or not it is convenient. The new PageSpeed script’s first run against the first client’s home page reported a largest-contentful-paint of 4.2 seconds on mobile. That is now a card on their board, with the label, in the plain language the advisory would use. The next session will see it in the briefing before anyone types.