StrideLabs/Writing/Why Prox is API-first
Why Prox is API-first
Why the process manager I run my dev stack with exposes logs, process control, and proxy requests over an API first, so agents can inspect failures without me copying text around.
It started with a small, recurring annoyance: copying an error out of a server log and pasting it into a coding agent. I’d been using honcho to remember how to start the processes in my web projects, and the next thing I wanted was for the agent to read those processes’ logs when something broke, without me playing courier. That itch is most of why prox exists.
Most process managers assume a human is watching. You run a Procfile, a wall of interleaved logs scrolls past, and control happens through whatever keys the TUI happens to bind. That’s fine until the thing that needs to start a service, read its output, or notice it fell over isn’t a person: it’s a script, an editor task, or a coding agent. Prox starts from the opposite assumption: the process manager is a small server, and everything else (including its own TUI) is a client.
The API is the product surface
When you run prox up, you get a supervisor that exposes every meaningful action over HTTP: start and stop processes, restart one, stream logs, query health. The TUI is a nice way to use that API by hand, but it has no privileged path. Anything the TUI can do, a curl one-liner can do too.
# stream a service's logs, filtered to errors
curl -N "localhost:5555/api/v1/logs/stream?process=web&pattern=ERROR"
# restart just that service, without touching the TUI
curl -XPOST localhost:5555/api/v1/processes/web/restart
That symmetry is the whole point. The moment control is an API instead of a keystroke, the set of things that can manage your dev environment expands from “me, looking at a terminal” to “anything that can make a request”, including the agent that just wrote the code you’re testing.
HTTPS and friendly domains, locally
The second itch was the network in front of those processes. I didn’t want to remember that the frontend is on 3000 and the API on 8000, and I didn’t want to keep juggling the differences between HTTP and HTTPS locally: secure cookies, mixed content, the usual. So prox grew an optional reverse proxy. Give it a base domain and it routes subdomains to your services (app.local.myapp.dev, api.local.myapp.dev) over locally-trusted HTTPS, with the certificates generated for you through mkcert.
It also scales past one project. I usually have a few services running across separate repos (an auth service, an API, a frontend) and I wanted them all reachable on the same port without fighting over it. So the proxy runs as a shared, per-machine daemon: the first project that needs the port starts it, every other project registers its hostnames with it, and routing happens by full hostname (SNI for HTTPS). Each project still does its own prox up and prox down; the daemon comes up on first use and shuts down when the last one leaves. There’s no separate thing to start. It’s auto-managed.
The proxy also records the requests passing through it, which closes the loop on the original annoyance. When a test run produces a 500, you don’t reconstruct it from logs; you ask for it:
# every request that failed, newest first
curl "localhost:5555/api/v1/proxy/requests?min_status=500"
To a human that’s a filter in the TUI; to an agent it’s one more endpoint, and it can see exactly which call broke.
Healthy, not just started
A process being up and a process being ready are different facts, and conflating them is where flaky local setups come from. Prox lets each process declare an optional health check, so “started” and “actually serving traffic” are distinguishable, to you in the TUI, and to whatever automation is waiting on the environment before it does the next thing.
Built for the agents next door
This is where prox fits the rest of the lab. Roost runs the agents; Shed gives them somewhere isolated to run. Prox gives them a process environment they can actually operate: bring services up, watch the logs, react to a failing check, tear it all down, all over the same API a human uses. Keeping a human-facing TUI and an agent-facing API as the same surface, rather than two codepaths, is a small discipline that keeps the tool honest.
Prox is one of the tools here whose shape feels mostly settled. It will pick up polish over time, but the important decision is already made: the API and the human UI are the same surface.