Your agent pays by the line
That's the constraint everything else here comes from, and most dev tooling wasn't built with it in mind. A build fails and you get ten thousand lines of output. A person scrolls to the bottom and finds the error in four seconds. An agent reads all ten thousand, pays for all ten thousand, and has less context left for the fix than it had for the failure.
So the platform's job is to pick out what matters before you get billed for the line, instead of dumping the whole stream on the model and letting it do the picking on its own dime.
Some of this is built. Most of it isn't, and I'll say which is which as I go — because describing a plan in the present tense is just lying with better grammar.
What already works
Four things, all shipped, all checkable.
The work happens outside your session. You never write the Dockerfile and you never see it. The platform makes one per built service and builds that. Compose, ports, health checks, database wiring — same deal, all on the server, where it costs your agent nothing.
A committed plan means no planning call. Commit a smartline.json and later deploys build straight from it. That's not a cache. The archive's hash changes on every deploy by design, so a content-addressed cache would never hit anyway. It's your agent — which has read the whole repo — handing a conclusion to a pipeline that deliberately doesn't get one.
A broken plan gets refused before you pay for anything. The checks are deterministic and ordered cheapest first, so the one call that costs money runs last. If the file stops matching your repo, the deploy is refused and tells you what changed.
The biggest chunk never reaches the expensive stage. The file tree is the largest thing in the prompt, and the stage that does the hardest thinking never sees it.
The next piece, and the biggest one
Errors, not transcripts.
Right now what you get when something breaks is a short tail held by the node. The tool that returns it says so in its own description: no history, no search behind it. The lines come from Docker's json-file driver, capped at ten megabytes across three files per container, and they're gone when the container is.
That last bit is the real problem. The logs vanish exactly when the agent needs them most. A container that crash-loops gets destroyed and recreated, so the first failure — the useful one — is the first thing you lose. What's left is the end of the loop: the same line over and over until the tail filled up.
There's one thing that helps already. When a deploy fails, the node grabs a snapshot of the moment it broke. That covers deploys. It doesn't cover the container that started fine and died an hour later.
The plan is a real log store behind that call, there for every project, nothing for you to install and nothing for your agent to provision. Loki is the candidate, not the decision. The design docs still have it marked open, and I'm not going to publish a decision I haven't made.
Four things a store gives you that a tail can't.
Severity becomes a query. The filter runs where the lines are, so your agent pays for the result instead of the stream the result came out of. That's the whole idea in one sentence; the other three follow from it.
The first failure outlives the container. That's what retention is for. The first moment things went off the rails is worth more than the last hundred lines of a loop, and right now it's the one thing you can't have.
A repeat becomes a count. Four hundred identical stack traces tell you exactly as much as one stack trace and the number four hundred.
Returning the second version isn't a summary or lossy compression. It's the same fact, written shorter.
The labels are already there. Project, service and deploy attempt get attached when the line is written, so nothing downstream has to grep for them — and neither does your agent.
None of this is deployed yet. It's what's next.
Five smaller ones
Also plans. Each one is a spot where you get billed for a line that didn't need to be there.
The first divergence, not the last N lines. A tail gives you the end. The end of a crash loop is the least useful part of it, and picking it is just an accident of how tails work, not a choice anybody made.
The service filter, everywhere. Half done. The runtime tail already takes a service name, and without one every service gets interleaved — which on a multi-service project is most of what you're reading. Build output and status don't take one yet. They should.
Errors written for an agent. The config gate already does this: it refuses and names the lockfile that left and the lockfile that showed up. That's one sentence an agent can act on. A stack trace isn't. Every error surface we own should be held to that standard.
State as a diff. Ask twice, get what changed — not the whole object again. Most of a second status call is just the first status call.
A cheap read before an expensive one. Summarising costs somebody something, and it should cost a small model on our hardware rather than the context in your session. I'm less sure about this one than the other four, and it's the first thing I'd cut if it turns out to hide more than it saves.

Replies