The conventional wisdom says to fetch a lightweight outline of a Figma file first, then pull styling only for the components you actually need. It sounds efficient. It's the kind of advice a senior engineer nods along to.
It's also wrong. On a file built with real components, the outline-first approach cost almost as much as fetching everything at once. On a file built from plain, un-componentized frames, it cost up to twice as much.
Last week, this column argued that the bottleneck in AI-assisted design work had moved from generation to defining done. This week, we can put numbers on that claim. The tax is real, it's measurable, and it's coming from three places most teams aren't watching: hard API quotas, the invisible cost of context re-reads, and agent runs that never learn when to stop.
The tax is real, it's measurable, and it's coming from three places most teams aren't watching.
Start with the quota. Figma's REST API limits file content requests on a Starter plan to six per month. Not per day. Per month. A 50-screen project, fetched once per screen, would take 42 months to complete on that plan. Half a day of work becomes three and a half years.
The token bill is the number everyone watches. It's also the one that matters least. Cheaper tokens have coincided with bigger bills because agents multiply token usage per task. The rate is one factor of four. The other three — context per step, steps per task, and total runs — all grow as agents get more capable.
The dominant driver is the loop. An agent re-reads its own growing context on every step. Step one sends a small context. Step two sends step one's context plus step one's output. Step ten re-sends everything from steps one through nine. The conversation doesn't cost N for N steps. It costs roughly N-squared.
Two consequences follow. Input tokens dominate the bill, because the agent reads vastly more than it writes. And anything that bloats per-step context gets multiplied by every future step. Trimming a thousand tokens from a context that gets re-sent ten times saves ten thousand tokens, not one thousand.
This is why the "smart" outline-first fetch strategy backfires. Figma's get_design_context response includes a fixed trailing instruction block — boilerplate that explains style tokens, Code Connect usage, and component props. On a tiny five-node section, that boilerplate was 48% of the entire response. Fetch a screen in ten pieces, and you pay for that boilerplate ten times over.
The file's construction matters more than any fetching strategy. A component-based page with 243 visible nodes cost 17,948 characters. A plain-frame page with 131 visible nodes cost 30,020 characters. The page with nearly double the nodes cost 40% less, because Code Connect returns clean component references instead of reverse-engineering a wall of Tailwind classes.
The plain-frame page didn't just cost more. It produced worse code. Because its root frame was absolutely positioned, the response was littered with 45 absolutely-positioned elements and 54 pixel-perfect offset classes. A nav bar sitting 39 pixels off-canvas came back as a snapshot of exactly where that one element happened to sit. Not a layout that could ever be responsive.
No clever fetching strategy fixes this. If the file itself is built badly, the output is built badly. Full stop.
Now scale that to a multi-agent system. Nine agents launched simultaneously. In 22 minutes they opened 10 pull requests. Then GitHub started returning 429 errors. Every agent retried at the same time. The retry wave triggered a second 429 wave, then a third. Within 90 seconds, the system had burned through GitHub's 5,000 requests per hour limit and was locked out entirely.
Meanwhile, the lead agent making critical architecture decisions was stuck behind a background polling agent that had eaten the remaining completions doing low-priority issue triage.
The core lesson from that incident: rate limiting in multi-agent systems is a coordination problem, not a retry problem. Every tool evaluated — Azure API Management, Resilience4j, LangGraph — treats rate limiting as something each caller handles independently. But when nine agents share the same API quotas, independent retry logic doesn't just fail. It actively makes things worse.
The failure modes have names. Thundering herd: after a 429, all agents wait the same Retry-After duration and retry simultaneously. Priority inversion: background polling consumes quota that blocking architecture decisions need. Cascade amplification: a single rate-limit hit causes multiple agents to queue their pending work, and when the limit lifts, they all flush their queues at once, immediately re-triggering the limit. One 429 became a system-wide outage that took up to 60 minutes to recover from.
There's a parallel problem inside the agent's own execution loop. An agent isn't capped only by its context window. It's also capped by how many times it's allowed to act. Go beyond that, and cost and side effects run away. Stay too far under it, and you starve the task.
Tool-call budgets are a system design problem. What fills a tool budget is discovery, retries, bad schemas, oversized results, verification loops, and branches. Every one of these is an architectural decision. If your agent can see 80 tools with no ranking, that's a routing design problem. If a failed API call becomes a brand new plan instead of a bounded retry, that's a reliability problem. A prompt instruction does not fix either.
Agents also behave differently near their tool-call limit. They repeat tools, dump raw JSON back into context, and try one more thing that's just another side effect. You cannot prompt your way around that. You design around it.
The prompt is the last 5%. The runtime is the other 95%.
A sample failure scenario: a tool returns a 504 or malformed JSON. The agent appends a 2KB error log to context. The planner retries with "more detail," increasing the prompt size. Each subsequent call is more expensive than the last. The system terminates only when it hits a hard timeout or burns through its budget. By that point, the original intent is lost.
This is an economic denial of service attack. It isn't an infinite loop. It's resource exhaustion caused by unbounded execution.
The mitigations are concrete. Task-scoped budgets: hard-stop execution at $0.50 per Task ID. Token-delta monitoring: terminate if context growth exceeds 25% between steps. Semantic circuit breakers: if an agent calls the same tool with the same arguments three times and receives the same error, break. Inline enforcement: controls must execute before the next LLM call, because that's the only way to prevent the cost from being incurred.
One commenter put it plainly: the duplicate ticket costs more than the token bill does. A budget caps spend, but idempotency keys on the tool side are what stop the second create.
There's a deeper architectural insight here. Subagents get justified by time saved and parallel execution, but that's not what matters most in long-running multi-agent work. Every token in the orchestrator's context is competing for its attention. The real value of a subagent is what it keeps out of that context, not how fast it runs.
In one documented incident, an orchestrator suggested checking on running agents. That small, throwaway prompt pulled back the full raw transcript of a background agent — tens of thousands of tokens of JSONL, intermediate reasoning, and tool output — imported wholesale into the main thread. Then it happened again, for a second status check.
The scarce resource is the orchestrator's working memory. Subagents should be treated as a tool for protecting that memory, offloading reasoning the orchestrator doesn't need to hold onto.
This connects directly to the quota problem. Figma's rate limits are applied per user, per plan, per app. For OAuth apps, a user gets a unique rate limit budget for each app they're using. But for personal access tokens, rate limits are tracked on a per-user, per-plan basis. When multiple people on a team run the same script with the same token, all requests count toward the same limit.
A single agent stuck in a loop can consume the entire quota. Without task-level priority queuing or isolated quotas, one buggy agent becomes a bottleneck that creates a denial of service for every other AI-dependent service in the stack.
The fix isn't more governance. It's better system design. Read the rate-limit headers after every API call. Don't wait for a 429 to tell you you're out of quota. The headers tell you ten calls in advance.
Build a traffic-light system. Above 40% quota remaining, normal operation. Between 15% and 40%, add proportional delays — background agents slow down first. Below 15%, background agents park, standard agents slow to one request per second, critical agents pass through immediately.
The longer the run, the more the system needs traces, not vibes. A three-day agent run without a spend cap is a blank check. Caps are not pessimism. They are how you sleep.
A day-long goal needs the same artifacts you would demand from a human owner. A stop condition: what does done mean in the product, not in the model's self-report? A blast radius: which accounts, which environments, which write actions are allowed? A log that survives the session: tokens expire, tabs crash, context windows fill. The run only counts if the next morning you can read what it tried without reconstructing from vibes.
The prompt is the pitch. The product is the harness around it.
The inversion is simple. Letting an agent run for days is not the hard part. Making the run bounded, reversible, and inspectable is.
Last week, we said the bottleneck had moved from generation to defining done. This week, the numbers confirm it. The hidden tax is real: quotas you didn't know you had, context re-reads you can't see, and runs that never learned when to stop. The teams that win won't be the ones with the smartest prompts. They'll be the ones who fixed the file first, fetched each screen exactly once, and built the harness before they walked away.