C.W.K.
Stream
Lesson 02 of 04 · published

Engine First, Clients After

~11 min · api-first, build-order, clients, engine

Level 0Unlit Wick
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Build the circuit before you shop for lamps. The lamp you buy first will quietly decide what the circuit is allowed to be."

The Build Order Is a Design Decision

Every engine in this family follows the same order: complete the engine, open the API, let clients come after. It sounds like project management. It's actually architecture. The order you build in determines which component gets to make demands of the other — and whatever you build first becomes the thing everything else is shaped around. Build the engine first and clients adapt to a clean API. Build the UI first and the API adapts to that UI, forever.

What UI-First Quietly Does to an API

Start with the interface and something subtle goes wrong. You need a screen that shows results with a filter and a toggle, so you write an endpoint that returns exactly that screen's data, in that screen's shape, with that screen's filter semantics. It works beautifully — for that screen. Then the second client arrives and discovers the API speaks a dialect invented for a UI it has never seen: fields it doesn't want, a shape it has to unpick, assumptions it doesn't share. The first UI's accidents have become the API's permanent vocabulary.

The Console Is a Lightbulb, Not the Product

So the console gets built second, and it's honest about its role: it's the first thing plugged into the circuit, there to prove the current flows. It has no privileges. It calls the same public endpoints anyone else would, and if it needs something the API doesn't offer, that's a signal about the API, not an excuse for a private back door. A first client that gets special access isn't a client — it's the engine wearing a costume, and the API will never be tested honestly again.

Whatever you build first becomes what everything else is shaped around. This is why build order is architecture, not scheduling. The first consumer of an interface imprints its assumptions permanently. So build the general thing first and let the specific things adapt — and make your own first client use the public path with no privileges, because a client with back doors can't tell you whether the front door works.

The Proof: Later Clients Cost Nothing

The payoff shows up when the second, third, and fourth clients arrive and the engine doesn't change at all. An editor's completion popup, an assistant calling search as a tool over HTTP, an internal site-search view — each one plugged into the same endpoints and got full capability on arrival. Zero engine modifications. That's the receipt for engine-first: when adding a client is a client-side-only change, the API was general enough. When every new client forces an engine change, you built a UI's backend and called it an engine.

Code

One public contract; every client, including your own, uses the front door·python
# The engine exposes ONE public contract. Nobody gets a private door.
@app.post("/api/search")
def search(query: str, mode: str = "hybrid", k: int = 8) -> list[CitableResult]:
    ...

# Client 1 — the console. Built SECOND. A lightbulb proving current flows.
results = http.post("/api/search", json={"query": q, "mode": "hybrid"})

# Client 2 — an editor's completion popup. Arrived later. Engine changes: zero.
suggestions = http.post("/api/complete", json={"prefix": tail})

# Client 3 — an assistant calling the engine as a tool over HTTP. Also zero.
slices = http.post("/api/search", json={"query": question, "k": 8})

# The receipt for engine-first: adding clients 2 and 3 was a CLIENT-side change.
# If each new client had forced an engine change, it was never a general engine —
# it was one UI's backend wearing an engine's name.

External links

Exercise

Look at an API you've built or used. Ask: can you tell, from the endpoint shapes alone, which UI was built first? Look for fields that only make sense for one screen, or filters named after a specific view. Then imagine adding a totally different client — a CLI, a bot, another app. List everything that client would have to work around. That list is the tax the first UI charged the API.
Hint
The tells are endpoints named after screens rather than resources, response shapes that mirror a layout, and parameters that encode a specific view's state. Each one is a place the first client's accidents got frozen into the contract that every future client now has to live with.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.