← Blog

The size cap on an AI-written app was never storage. It was the model's own reply.

The size cap on an AI-written app was never storage. It was the model's own reply.

Every FOKL tool runs in a sandboxed iframe with no access to cookies, local storage, or the parent page — real isolation, the kind Claude Artifacts and ChatGPT also use and Dyad, notably, doesn't. That part of the architecture held up under scrutiny from the day I designed it. It is not what broke first.

What broke first was someone asking for something big.

A tool in FOKL is written inside a single model response — one call, one document, no streaming edits. So I went looking for the actual ceiling on how large a tool could get, and measured it instead of guessing. An ordinary chore chart: 9,198 tokens, 21 KB, a clean stop. Then I asked for something deliberately oversized — "120 rows, written out literally" — and the reply stopped mid-document: 65,532 tokens, 168 KB, cut off by the model's own output limit, not mine.

Claude Sonnet 5 and Opus 5 cap a single reply at 128,000 tokens — a little over 300 KB at the extreme. Our own byte cap on a tool at the time was 2 MiB, about 26 times larger than anything a model could ever actually produce. It had never once been the thing stopping a build. I'd been guarding a door nobody could reach while the real wall sat 26x closer.

Two things came out of chasing that number down. First: we were never sending max_tokens at all — the proxy was quietly filling in its own default, 65,536, and the single most important limit on a tool's size had been set by a config value nobody on our side had chosen or could see. Second, and worse: when a reply gets cut off mid-document, the tool call never closes, fails to parse, and gets dropped — arriving at the person building it looking exactly like the model said nothing at all. The message they got was "FOKL couldn't get that one working, try describing it a different way." Which sends someone off rewording a request the model understood perfectly and simply ran out of room to finish.

So now the ceiling gets a name. We set max_tokens ourselves, watch for the model stopping because it ran out of room rather than because it was done, ask once for a smaller version, and if it still doesn't fit, fail with a message that says why — not one that quietly blames the person for how they asked.

None of this is really about FOKL. It's what happens anywhere an AI writes something inside one reply and you didn't measure where that reply actually ends: your real ceiling is the model's output window, and every truncated result looks identical to a confused one until you go check the stop reason. Ours turned out to be a support-ticket variety I'd been misdiagnosing for weeks — "the AI didn't get it," when the honest answer was "it did, and ran out of room saying so."

We haven't solved building something bigger than one reply yet — that's still open, and the honest version of "make it bigger" for now is: ask for less at a time.

FAQ

What's the real limit on how large an AI-generated app can be?

It's the model's own output window for a single reply — not disk space, not a database, and not whatever byte cap a product sets internally. Claude Sonnet 5 and Opus 5 cap a single response at 128,000 tokens (roughly 330 KB at the theoretical maximum). A tool generated inside one model call can never exceed what that one reply can hold, regardless of how much storage backs it.

Why does AI-generated code or app output sometimes get cut off partway through?

When a model hits its maximum output length mid-response, it stops with a `length` finish reason instead of a clean `stop`. If that response was a structured tool call or a file being written in one shot, the cutoff usually leaves the output malformed — valid JSON or a complete document never gets to close — so it fails to parse and gets discarded. From the outside, that failure looks identical to the model producing nothing at all.

What does finish_reason: length mean and why does it matter?

It's the signal an LLM API returns when a response was truncated because it hit the maximum token limit, as opposed to `stop`, which means the model finished on its own. Systems that generate structured output in one call need to check this explicitly — treating every failure the same, whether it was a truncation or a genuine misunderstanding, produces error messages that blame the wrong cause.

Why doesn't raising a byte-size cap fix an AI generation size limit?

Because the model's own output window is almost always the binding constraint long before an application-level byte cap is reached. In one measured case, a byte cap of 2 MiB was roughly 26 times larger than the largest output the model could physically produce (168 KB, near its 128K-token ceiling) — so the byte cap had never actually been the limiting factor, and raising it further would have changed nothing while increasing what has to be stored and transmitted for every other case.

How do you stop an LLM proxy from silently defaulting max_tokens?

Set `max_tokens` explicitly in every request rather than relying on the proxy's or SDK's built-in default, which can be an arbitrary value nobody chose for the specific use case. Pair it with checking the response's finish reason so a truncation is detected and handled — asking for a smaller output, or failing with a message that names the actual cause — rather than surfacing a generic, misleading error.

Made with FOKL — little apps your family keeps.