ZeNorm

Usage visibility dashboard and org-settable budget gates for agent spend

Paid-plan org owners can see per-period agent spend broken down by spec and session, set a hard budget that pauses the next turn (never kills work in flight), receive an approaching-budget warning at a configurable threshold, and see a clear blocked-by-budget state with an upgrade path. Free tier keeps its existing spec-count quota unchanged.

July 25, 2026grounded in ACE-72/zenormusage-visibility-dashboard-orgsettable-budget-gates
The request that started it

I have no idea what our agent runs actually cost us or how to stop a runaway bill.

6Rounds
3Questions
1Gate refusals
16Blocks

The grilling

Round 1read 27 files

I have no idea what our agent runs actually cost us or how to stop a runaway bill. That's the ask at whiteboard level. Go read the repo first — how agent turns are priced and recorded today, what an org's billing state looks like, and whether anything already gates or alerts on spend — then grill me. I'm expecting this to be feature-scale with several moving parts, not a dashboard.

ZeNorm

I've thoroughly explored the codebase. Here's what I found: **What exists today:** - Every agent turn is already **priced** (`pricing.ts`) and **recorded** to `agent_usage_ledger` with per-model token rates in micro-dollars - `orgs.period_spend_micros` accumulates spend per billing period - **Soft operator alerts** fire via PostHog when an org crosses $20/mo (paid) or $1/mo (free) — but NOTHING blocks or even warns the user - The settings page shows subscription status ("Active") and "Unlimited usage" — but **raw spend is explicitly hidden**: the code comments say "Dollar/token figures are intentionally NOT surfaced to the user" - **No user-facing controls whatsoever** — no dashboard, no per-turn/per-period cost breakdown, no budget caps, no spend alerts So the data pipeline is complete but invisible. You have no dashboard, no budget controls, no way to cap or even see spend from the product UI. Let's start defining scope. The pricing ledger already has every turn costed and stored — the raw data for a dashboard is there, and the `period_alert_micros` field on orgs is a ready-made threshold mechanism. The question is which problem to solve first (or both in one spec).

Files the agent read
  • read_repo_structure whole repo
  • read_repo_file apps/api/src/turn-spend.ts
  • read_repo_file apps/api/src/pricing.ts
  • read_repo_file apps/api/src/stripe-client.ts
  • read_repo_file apps/web/src/components/BillingBanner.tsx
  • read_repo_file apps/api/src/metrics.ts
  • read_repo_file apps/api/src/routes/stripe.ts
  • read_repo_file apps/api/src/spec-quota.ts
  • read_repo_file apps/web/src/routes/dashboard/settings.tsx
  • read_repo_file apps/web/src/lib/handle-credits-exhausted.ts
  • grep apps/web/src
  • grep apps/api/src
  • grep packages
  • read apps/web/src/routes/dashboard/settings.tsx
  • find **/schema/**
  • read_repo_file packages/db/schema/index.ts
  • grep apps/api/src/routes/stripe.ts
  • find packages/db
  • read apps/api/src/routes/stripe.ts
  • read_repo_structure packages
  • read apps/web/src/routes/dashboard/settings.tsx
  • grep packages/zero/src/schema.ts
  • grep packages/zero/src/schema.ts
  • read packages/zero/src/schema.ts
  • grep apps/api/src/monitoring.ts
  • find agent_usage_ledger
  • read apps/api/src/monitoring.ts
Round 2

C, and you don't have to sell me — your own framing is right. Visibility without control is anxiety, control without visibility is a mystery outage. Both, one feature. Building on what you found, here's the brief: Spend becomes visible. Right now the code deliberately hides dollar figures and shows "Unlimited usage," which was a defensible choice when nobody was near a limit and is the wrong choice the moment I'm asking this question. An org owner should be able to see what was spent this period and what drove it — which specs, which sessions. Not a BI tool. Enough to answer "why was this month expensive" without me querying the ledger by hand. Budgets become real. Today the alert is soft and operator-facing — it fires into PostHog and the user never knows. I want an org-settable budget that actually does something when crossed. And I want to be precise about what "does something" means, because this is where I have a strong opinion: crossing a budget must never destroy work in flight. Killing a turn mid-execution means the user paid for the tokens and got nothing, which is the worst possible outcome — we charged them and deleted the result. So enforcement stops the *next* turn, not the current one. Whatever's running finishes. Warning before the wall. A budget that silently allows everything until it blocks everything is a bad product. Somebody should hear about it on the way up — at a threshold, not just at the limit — and that warning goes to the person who can act on it, not into our telemetry. And when they hit the wall, the product has to say so clearly. The failure mode I refuse to ship is an agent turn that just doesn't work and gives a generic error, and the user files a bug because from where they're standing the product is broken. Blocked-by-budget is a state the UI understands and explains, with the way out visible. Constraints: - Free tier keeps its existing spec-count quota. That's the free-tier limit and I'm not replacing it. Budgets are the paid-tier control. Don't unify them into one mechanism — they're answering different questions. - Never bill-blocking retroactively. Nothing already spent gets clawed back or re-evaluated. The budget affects what happens next. - Org-scoped, and only whoever owns billing for the org sets it. A member shouldn't be able to raise the ceiling on someone else's card. That's the feature. Before you write blocks: you said spend accumulates in orgs.period_spend_micros and turns are priced per model. Tell me whether that accumulation is reliable enough to gate on. Specifically — is a turn's spend recorded before or after the turn runs, and does a failed or cancelled turn still get recorded? If spend lands after the fact, then a gate reading that number is always a turn behind, and I need to know whether that's a rounding error or a hole someone could drive through.

ZeNorm

Excellent question. The answer is yes, it's reliable to gate on — and the "one turn behind" pattern is actually the correct design for your constraint (never kill work in flight). Here's why: **Timing**: `recordTurnSpend()` runs in the turn **finalizer** — after the agent completes. It writes the priced cost into `agent_usage_ledger` and atomically adds it to `orgs.period_spend_micros` in a single transaction. So a budget gate that checks `period_spend_micros` BEFORE starting a new turn is looking at settled, complete data. **Failure handling**: A failed turn is recorded with `isError: true` and $0 cost — it's distinguishable from a clean free turn, but it doesn't pollute the spend total. So you won't lose your budget to errored turns. **The only edge case** is concurrent turns (two sessions running at once). Both could check the budget, see headroom, and start — then both record spend and overshoot by one turn each. For v1 that's probably acceptable (a few dollars at most on a $27.99 plan), but if you want to close it, a pre-reservation pattern (hold budget before starting, release unused on completion) would be the fix. Now let me capture what you described. Intent is at 0.85 with no blocking gaps. Two clarifying decisions remain — here's the one that most affects the architecture. You said "warning before the wall" and "at a threshold, not just at the limit." The architecture question is whether that threshold is a second knob the org owner tunes, or a fixed ratio of their budget. My recommendation is two knobs (configurable percentage) — an org with a $50 budget might want to hear at 60%, another at 90% — and setting it as a percentage of the budget keeps it simple. But if you'd rather ship one knob (just the hard budget) and let the product pick the warning point, that's simpler and still addresses the brief.

Round 3

Threshold: fixed, one knob. The org owner sets a budget and the product warns at 80%. Two knobs means a settings page with a percentage field, which means somebody sets it to 99% and gets a warning that's useless, or sets it to 20% and gets warned constantly and stops reading them. Pick a sensible number and own it. If it turns out 80% is wrong we change one constant. That's my scope cut for this feature and I'm making it happily. Now the concurrency thing, because you flagged it and then told me it's probably fine, and I don't think it is. You said two concurrent sessions could both see headroom and both start, overshooting by one turn each, and that's a few dollars on a $27.99 plan. That reasoning holds for two. It doesn't hold for the case I actually worry about, which is someone running the CLI in a loop, or a team where several people are working at once, or an agent workflow that fans out. The bound on the overshoot isn't one turn, it's however many turns can start in the window before any of them settle — and a turn can run for minutes. So the real bound is "however much you can spend in the time it takes one turn to finish," which on a fan-out is not a few dollars. But — and this is me arguing against myself — a full pre-reservation system with holds and releases is a meaningful chunk of engineering, and it has its own failure mode: a hold that never releases because the process died, and now the user is blocked by phantom spend they never incurred. That's a worse bug than overshooting. So I want you to tell me which way to go rather than me picking blind. What I care about is that the overshoot is bounded by something I can state, not unbounded. If there's a cheaper mechanism than full reservation that bounds concurrent starts — capping how many turns an org can have in flight at once, or counting started-and-unsettled turns against the budget at an assumed cost — that might get me most of the protection for much less machinery. If you think reservation is the only honest answer, say that and it goes in the feature. Either way I want the answer written into the spec as a stated bound, so that when someone eventually overshoots their budget, the product's behavior was specified rather than accidental. Everything else from my last message stands. After you answer this, write the constraints and acceptance criteria. Acceptance criteria I'll hold this to: - An org owner can see this period's spend and what drove it, without SQL. - A turn in flight when the budget is crossed completes. Nobody pays for a killed turn. - The next turn after the budget is crossed doesn't start, and the user is told why in terms they understand, with the way out on screen. - The 80% warning reaches the person who can act on it, not just our telemetry. - Concurrent turns cannot overshoot the budget by more than the stated bound — whatever we decide that bound is. - A free-tier org is unaffected. Their limit is still the spec count.

ZeNorm

The concurrent-turn cap is the right answer. You effectively sketched it yourself. Here's why it wins: **Full pre-reservation** gives you phantom-hold risk (process dies, budget is stuck) and requires a release-fast path plus a ttl sweep — that's the engineering you're rightly wary of. **Concurrent-turn cap** (max simultaneously active agent sessions per org) bounds the overshoot with zero phantom-spend risk. No holds, no releases, just an atomic counter. Implementation is ~one column, one pre-turn check, one post-turn decrement. The bound is: > `max_active_turns × highest_realistic_turn_cost_for_the_orgs_model` With a cap of **5** (generous — most users run one session; five is for team-fan-out scenarios) and DeepSeek V4 Flash at ~$0.05/worst-case turn, that's $0.25 max overshoot. With Claude Opus at ~$5/worst-case long turn, that's $25 — still an order of magnitude below the $100+ a genuinely unbounded fan-out could hit. And you've shipped the bound as a stated property of the product: "You will never overshoot your budget by more than **5 × max single-turn cost for your model**." Let me capture everything and finalize intent. Done. Here's the summary of the concurrency decision: **Concurrent-turn cap (max 5 active sessions per org)** is the mechanism. It avoids the phantom-hold risk of pre-reservation, bounds overshoot to a stated value (`cap × model_max_turn_cost`), and is simple enough to implement as an atomic counter — increment on start, decrement on finish, reject when at cap. I've written it into the spec as a constraint block along with the fixed 80% warning threshold. Intent is at 0.95 with no blocking gaps. Ready for you to tell me to proceed to acceptance criteria, or raise anything else while intent is still open.

Round 4

Good. Take the concurrent-turn cap, and make sure the spec states the bound in the user-facing form you wrote — "you will never overshoot by more than the cap times the worst-case single-turn cost for your model" — because that's a promise we can actually keep and it's the kind of thing that belongs in the product, not just in the code. One refinement on it: hitting the concurrency cap and hitting the budget are different situations and must not share a message. "You have too many sessions running at once, wait for one to finish" and "you're out of budget for this period" lead to completely different user actions. If they collapse into one generic "can't start a turn" state we've made the diagnosis problem worse, not better. Same standard I set for the blocked-by-budget state: the user should never have to guess. Proceed to acceptance criteria and tasks. My six criteria from the last message stand, plus that the concurrency refusal is distinguishable from the budget refusal. On task grouping: propose it yourself. My instinct says the visibility surface is one piece and the enforcement machinery is another, but the warning could plausibly go with either, and you know where the code seams are. Two or three coarse tasks. Tell me your split and why.

ZeNorm

The spend visibility question is straightforward — it needs one clarifying decision before I can write the AC concretely. My recommendation is **D — both Settings and inline**. The per-period summary with budget controls is the natural place in Settings (where subscription management already lives), and inline cost-per-session in the spec editor answers "what did this conversation cost me" at the moment the user is having it — which I suspect is where most of the anxiety lives. They're different information needs on different surfaces. But it's your call — if you want to pick one to keep the scope tighter, say so.

Round 5

Settings page only. Not D. Your reasoning for inline is decent — the anxiety is at the moment of use — but I think it's wrong here, and specifically it's wrong for this product. Putting a running dollar counter next to the agent chat changes how people use the agent, and not in the direction I want. The whole value proposition is that the agent grills you thoroughly; a visible per-message price tag makes people terse, makes them accept the first option to end the conversation, and quietly degrades the thing we're selling. I'd rather someone check their spend deliberately in Settings once a week than be nudged toward worse specs every turn. So: Settings, alongside subscription status, with the budget controls in the same place. Per-period total, broken down enough to see which specs drove it. Note that this is a scope cut and not a scope amputation — the feature still has visibility, it just has one surface instead of two. If it turns out people want in-context cost, that's a follow-up informed by evidence, and it's a small one because the data is already there. Now write the acceptance criteria and give me your task split.

ZeNorm

Understood. Settings-only for visibility. That's a clean scope cut. Let me write the acceptance criteria and propose the split. All three sections are at 0.9+. Here's my proposed task split. **Two tasks — one per distinct user-visible capability:** **Task 1 — Add per-period spend breakdown with spec and session drill-down to the Settings page** Read-only surface. Queries `agent_usage_ledger` aggregated by current period → by spec → by session. Renders total spend, with expandable rows per spec showing sessions within it. Lives alongside the existing subscription status panel in Settings (shown only for paid orgs). No agent turn behavior changes at all. Owns AC: spend visibility in Settings. **Task 2 — Add budget controls to Settings with pre-turn enforcement, concurrent-turn cap, and distinct blocked states** The enforcement machinery. Settings gets a budget input (default off, unlimited behavior preserved). The agent turn start flow gets two pre-checks: budget gate (read `period_spend_micros` against org-set budget) and concurrent-turn cap counter (increment, refused if ≥5, decremented on finish). The 80% warning triggers as an in-product notification on the crossing turn's completion. Two distinct refusal states (budget exhausted vs. concurrency cap reached) with different messages and resolve paths. Owns ACs: no kill-in-flight, blocked-by-budget with explanation, 80% warning, concurrent cap with stated bound, distinguishable refusals, free tier unchanged. **Why two, not one**: They're independently shippable. You could ship the spend breakdown while enforcement is still in review, and a user could see what they spent without any budget behavior changing. Conversely, you could ship enforcement first (set a budget, get blocked, see distinct states) and add the breakdown a week later. Each is a complete demo on its own, not half of one. **Why not three**: The 80% warning is triggered by the same lifecycle as the budget gate — it fires when the post-turn spend accumulation crosses 80% of the budget. It's not a separate capability; it's a notification fired by the enforcement route. Folding it into Task 2 keeps each task a whole capability rather than one task per lifecycle event. Does that split work for you, or do you see a different seam?

Round 6read 7 files

That split works and your reasoning for two-not-three is right — the warning is a lifecycle event of the enforcement path, not a capability of its own. Create the tasks and build the trace graph.

ZeNorm

Good — I've confirmed the surfaces. `BillingPanel` in `settings.tsx` for the visibility UI, `runAgentTurn` in `agent.ts` for the enforcement point. Let me create the tasks. The second task's description was too long. Let me tighten both. Both tasks created. Now building the complete trace graph. 26 edges committed, trace coverage complete. Let me clean up the answered questions. The spec is complete. Here's what shipped: **Spec: Usage visibility dashboard and org-settable budget gates for agent spend** **2 tasks, 7 acceptance criteria, 26 trace edges.** | Task | Owns | What it delivers | |------|------|------------------| | **1 — Spend breakdown in Settings BillingPanel** | 1 AC | Per-period spend by spec and session, read-only, paid orgs only | | **2 — Budget gate + concurrent cap + blocked states** | 6 ACs | Budget input, pre-turn enforcement, concurrent-turn cap (max 5), distinct blocked-by-budget vs. blocked-by-concurrency messages, 80% in-product warning, free tier unchanged | **Key product decisions captured in the spec:** - Visibility lives in Settings only (not inline in the agent chat) — you don't want a per-message price tag nudging users toward terse specs - Budgets are the paid-tier control; free tier keeps its existing spec-count quota — separate mechanisms, never unified - The concurrent-turn cap (max 5 active sessions) bounds overshoot to `5 × worst-case single-turn cost for the org's model` — no phantom-hold risk - 80% warning threshold is fixed, not user-configurable — the product owns the choice - Budget crossing never kills work in flight — the turn completes, the *next* turn is refused - Two distinct refusal messages: "concurrency cap" and "budget exhausted" — the user never has to guess which limit they hit

Advisorycreate_tasktask description sprawl

This task description runs 5 sentences — past the 1-3 sentence capability handoff. Keep the outcome, the surfaces it touches, and what proves it works; cut restated acceptance assertions, step lists, and implementation detail the blocks and trace graph already carry.

Refusedcreate_tasktask description sprawl

This task description runs 7 sentences — past the 1-3 sentence capability handoff. Keep the outcome, the surfaces it touches, and what proves it works; cut restated acceptance assertions, step lists, and implementation detail the blocks and trace graph already carry.

What the agent was told to do instead

Stop the current edit sequence. Treat this as a plan-shape failure, not a wording issue: re-plan from the acceptance criteria into the smallest set of coarse, independently shippable user slices before retrying — as few as the distinct capabilities require (commonly 1-3, hard cap 7, no minimum); one narrow regression fix is exactly 1 slice. If two slices are steps of the same capability, merge them into one. If bad tasks or blocks already exist, update/delete that bad shape before adding more.

Advisoryupdate_tasktask description sprawl

This task description runs 5 sentences — past the 1-3 sentence capability handoff. Keep the outcome, the surfaces it touches, and what proves it works; cut restated acceptance assertions, step lists, and implementation detail the blocks and trace graph already carry.

Advisoryupdate_tasktask description sprawl

This task description runs 5 sentences — past the 1-3 sentence capability handoff. Keep the outcome, the surfaces it touches, and what proves it works; cut restated acceptance assertions, step lists, and implementation detail the blocks and trace graph already carry.

Files the agent read
  • grep apps/api/src/routes/agent.ts
  • grep apps/api/src/routes/agent.ts
  • grep apps/api/src/routes/agent.ts
  • grep apps/api/src/routes/agent.ts
  • grep apps/api/src/routes/agent.ts
  • grep apps/api/src/routes/agent.ts
  • grep apps/api/src/monitoring.ts

What it asked

Q1intent

Which gap is more urgent — visibility or stopping a runaway?

  • ASee where money goes

    Spend dashboard showing cost per time range, per spec, per session — org owners can see what drove the bill

  • BStop the bleed first

    A hard per-day or per-period budget that pauses agent execution for the org when crossed

  • CBoth, in one specAgent's pick

    Must ship both to be useful: visibility without control leaves users anxious, control without visibility is blind

What the PM said

C, and you don't have to sell me — your own framing is right. Visibility without control is anxiety, control without visibility is a mystery outage. Both, one feature. Building on what you found, here's the brief: Spend becomes visible. Right now the code deliberately hides dollar figures and shows "Unlimited usage," which was a defensible choice when nobody was near a limit and is the wrong choice the moment I'm asking this question. An org owner should be able to see what was spent this period and what drove it — which specs, which sessions. Not a BI tool. Enough to answer "why was this month expensive" without me querying the ledger by hand. Budgets become real. Today the alert is soft and operator-facing — it fires into PostHog and the user never knows. I want an org-settable budget that actually does something when crossed. And I want to be precise about what "does something" means, because this is where I have a strong opinion: crossing a budget must never destroy work in flight. Killing a turn mid-execution means the user paid for the tokens and got nothing, which is the worst possible outcome — we charged them and deleted the result. So enforcement stops the *next* turn, not the current one. Whatever's running finishes. Warning before the wall. A budget that silently allows everything until it blocks everything is a bad product. Somebody should hear about it on the way up — at a threshold, not just at the limit — and that warning goes to the person who can act on it, not into our telemetry. And when they hit the wall, the product has to say so clearly. The failure mode I refuse to ship is an agent turn that just doesn't work and gives a generic error, and the user files a bug because from where they're standing the product is broken. Blocked-by-budget is a state the UI understands and explains, with the way out visible. Constraints: - Free tier keeps its existing spec-count quota. That's the free-tier limit and I'm not replacing it. Budgets are the paid-tier control. Don't unify them into one mechanism — they're answering different questions. - Never bill-blocking retroactively. Nothing already spent gets clawed back or re-evaluated. The budget affects what happens next. - Org-scoped, and only whoever owns billing for the org sets it. A member shouldn't be able to raise the ceiling on someone else's card. That's the feature. Before you write blocks: you said spend accumulates in orgs.period_spend_micros and turns are priced per model. Tell me whether that accumulation is reliable enough to gate on. Specifically — is a turn's spend recorded before or after the turn runs, and does a failed or cancelled turn still get recorded? If spend lands after the fact, then a gate reading that number is always a turn behind, and I need to know whether that's a rounding error or a hole someone could drive through.

Q2intent

Is the warning threshold configurable or fixed?

  • AUser-configurable % thresholdAgent's pick

    Org owner picks both the warning percentage and the hard budget. Two knobs.

  • BFixed 80% of budget

    The product applies a built-in 80% warning of the set budget. Simpler, one knob.

  • CNo warning knob; budget-only

    No separate warning knob — the hard budget itself triggers a pre-turn warning on the approaching crossing turn.

What the PM said

Threshold: fixed, one knob. The org owner sets a budget and the product warns at 80%. Two knobs means a settings page with a percentage field, which means somebody sets it to 99% and gets a warning that's useless, or sets it to 20% and gets warned constantly and stops reading them. Pick a sensible number and own it. If it turns out 80% is wrong we change one constant. That's my scope cut for this feature and I'm making it happily. Now the concurrency thing, because you flagged it and then told me it's probably fine, and I don't think it is. You said two concurrent sessions could both see headroom and both start, overshooting by one turn each, and that's a few dollars on a $27.99 plan. That reasoning holds for two. It doesn't hold for the case I actually worry about, which is someone running the CLI in a loop, or a team where several people are working at once, or an agent workflow that fans out. The bound on the overshoot isn't one turn, it's however many turns can start in the window before any of them settle — and a turn can run for minutes. So the real bound is "however much you can spend in the time it takes one turn to finish," which on a fan-out is not a few dollars. But — and this is me arguing against myself — a full pre-reservation system with holds and releases is a meaningful chunk of engineering, and it has its own failure mode: a hold that never releases because the process died, and now the user is blocked by phantom spend they never incurred. That's a worse bug than overshooting. So I want you to tell me which way to go rather than me picking blind. What I care about is that the overshoot is bounded by something I can state, not unbounded. If there's a cheaper mechanism than full reservation that bounds concurrent starts — capping how many turns an org can have in flight at once, or counting started-and-unsettled turns against the budget at an assumed cost — that might get me most of the protection for much less machinery. If you think reservation is the only honest answer, say that and it goes in the feature. Either way I want the answer written into the spec as a stated bound, so that when someone eventually overshoots their budget, the product's behavior was specified rather than accidental. Everything else from my last message stands. After you answer this, write the constraints and acceptance criteria. Acceptance criteria I'll hold this to: - An org owner can see this period's spend and what drove it, without SQL. - A turn in flight when the budget is crossed completes. Nobody pays for a killed turn. - The next turn after the budget is crossed doesn't start, and the user is told why in terms they understand, with the way out on screen. - The 80% warning reaches the person who can act on it, not just our telemetry. - Concurrent turns cannot overshoot the budget by more than the stated bound — whatever we decide that bound is. - A free-tier org is unaffected. Their limit is still the spec count.

Q3acceptance

Where does spend visibility live?

  • ASettings page

    A new tab or panel in the existing Settings page, alongside subscription status. Budget controls live here too.

  • BDedicated billing page

    A standalone view — a usage/billing page accessible from the dashboard nav. Separate from settings.

  • CInline in spec editor

    Inline in the spec editor — cost per session shown alongside the agent chat, drilling into per-turn spend.

  • DBoth Settings and inlineAgent's pick

    The per-period summary in Settings, plus inline per-session cost visible in the spec editor. Both surfaces.

What the PM said

Settings page only. Not D. Your reasoning for inline is decent — the anxiety is at the moment of use — but I think it's wrong here, and specifically it's wrong for this product. Putting a running dollar counter next to the agent chat changes how people use the agent, and not in the direction I want. The whole value proposition is that the agent grills you thoroughly; a visible per-message price tag makes people terse, makes them accept the first option to end the conversation, and quietly degrades the thing we're selling. I'd rather someone check their spend deliberately in Settings once a week than be nudged toward worse specs every turn. So: Settings, alongside subscription status, with the budget controls in the same place. Per-period total, broken down enough to see which specs drove it. Note that this is a scope cut and not a scope amputation — the feature still has visibility, it just has one surface instead of two. If it turns out people want in-context cost, that's a follow-up informed by evidence, and it's a small one because the data is already there. Now write the acceptance criteria and give me your task split.

Where the server refused

Each of these rejected the agent's own tool call. The agent had to fix its output and try again before the spec could advance — this is the gate, not a prompt the model can talk past.

Refusedcreate_tasktask description sprawl

This task description runs 7 sentences — past the 1-3 sentence capability handoff. Keep the outcome, the surfaces it touches, and what proves it works; cut restated acceptance assertions, step lists, and implementation detail the blocks and trace graph already carry.

What the agent was told to do instead

Stop the current edit sequence. Treat this as a plan-shape failure, not a wording issue: re-plan from the acceptance criteria into the smallest set of coarse, independently shippable user slices before retrying — as few as the distinct capabilities require (commonly 1-3, hard cap 7, no minimum); one narrow regression fix is exactly 1 slice. If two slices are steps of the same capability, merge them into one. If bad tasks or blocks already exist, update/delete that bad shape before adding more.

What it had to clear

Every section had to score at or above 0.90 before create_task would run at all. This is the gate.

intent0.952 attempts

Four goals fully captured: spend visibility, budget gating with no-kill-in-flight, fixed 80% approaching-budget warning, clear blocked state. Five constraints: free tier unchanged, no retroactive blocking, org-scoped billing-owner authority, never kill work in flight, and concurrent-turn cap bounding overshoot. No outstanding intent gaps.

constraints0.90

Five constraint blocks cover: free-tier scope boundary, no retroactive blocking, org-scoped billing-owner authority, never kill work in flight, and concurrent-turn cap with stated bound. The budget gate uses the already-existing period_spend_micros field — no new storage schema needed. The concurrent cap is a single atomic counter, not a pre-reservation system.

acceptance0.90

Seven acceptance criteria, each stated as an observable input+outcome: spend breakdown visible in Settings, no-kill-in-flight, blocked-by-budget with explanation, 80% in-product warning, concurrent-turn cap with stated bound, free tier unchanged, and distinguishable refusal messages. All are measurable — no vague quality words, no vibes.

The spec it produced

Goals
Spend visibility for paid-plan org owners
Org-settable budget that gates the next turn
Approaching-budget warning to the user
Clear blocked-by-budget state on refusal
Constraints
Free tier unchanged
No retroactive blocking
Org-scoped with billing-owner authority
Never kill work in flight
Concurrent-turn cap bounds budget overshoot
Acceptance criteria
Settings shows per-period spend by spec and session
Budget crossing never kills a running turn
Next turn after budget crossed is refused with explanation
80% warning reaches the billing owner in-product
Concurrent-turn cap enforces stated overshoot bound
Free-tier org unchanged
Concurrency and budget refusals are distinguishable

How it hangs together

goal

Spend visibility for paid-plan org owners

  • constrainsFree tier unchanged
  • constrainsOrg-scoped with billing-owner authority
  • validatesSettings shows per-period spend by spec and session
  • validatesFree-tier org unchanged
goal

Org-settable budget that gates the next turn

  • constrainsFree tier unchanged
  • constrainsNo retroactive blocking
  • constrainsOrg-scoped with billing-owner authority
  • constrainsNever kill work in flight
  • constrainsConcurrent-turn cap bounds budget overshoot
  • validatesBudget crossing never kills a running turn
  • validatesConcurrent-turn cap enforces stated overshoot bound
  • validatesFree-tier org unchanged
goal

Approaching-budget warning to the user

  • constrainsFree tier unchanged
  • constrainsOrg-scoped with billing-owner authority
  • validates80% warning reaches the billing owner in-product
goal

Clear blocked-by-budget state on refusal

  • constrainsFree tier unchanged
  • constrainsOrg-scoped with billing-owner authority
  • validatesNext turn after budget crossed is refused with explanation
  • validatesConcurrency and budget refusals are distinguishable
acceptance

Settings shows per-period spend by spec and session

  • implementsAdd per-period spend breakdown by spec and session to the Settings BillingPanel
acceptance

Budget crossing never kills a running turn

  • implementsAdd org-settable budget gate, concurrent-turn cap, and blocked states to agent turns
acceptance

Next turn after budget crossed is refused with explanation

  • implementsAdd org-settable budget gate, concurrent-turn cap, and blocked states to agent turns
acceptance

80% warning reaches the billing owner in-product

  • implementsAdd org-settable budget gate, concurrent-turn cap, and blocked states to agent turns
acceptance

Concurrent-turn cap enforces stated overshoot bound

  • implementsAdd org-settable budget gate, concurrent-turn cap, and blocked states to agent turns
acceptance

Free-tier org unchanged

  • implementsAdd org-settable budget gate, concurrent-turn cap, and blocked states to agent turns
acceptance

Concurrency and budget refusals are distinguishable

  • implementsAdd org-settable budget gate, concurrent-turn cap, and blocked states to agent turns

What the gate released

Add per-period spend breakdown by spec and session to the Settings BillingPanel

Extend the Settings BillingPanel with a per-period spend summary for paid-plan orgs by querying agent_usage_ledger aggregated by period, spec, and session. Render total spend with an expandable breakdown and assert the drill-down data matches the raw ledger rows. Automated assertions: - Settings shows per-period spend by spec and session — without SQL

Add org-settable budget gate, concurrent-turn cap, and blocked states to agent turns

Add a budget input to the Settings BillingPanel and implement pre-turn enforcement in agent.ts: check period_spend_micros against the org-set budget before each runAgentTurn call, refuse the next turn if exhausted. Add an atomic active-turn cap (max 5, increment on start, decrement on finish) with distinct refusal messaging. Trigger an 80% in-product notification on the crossing turn's completion. Automated assertions: - Budget crossing never kills a running turn - Next turn after budget crossed is refused with explanation - 80% warning reaches the billing owner in-product — When cumulative spend reaches 80% of the org-set budget, a user-visible notification (banner, toast, or badge — not just telemetry) appears in the product for the org owner — does not block turn execution - Concurrent-turn cap enforces stated overshoot bound — never exceeds it - Free-tier org unchanged - Concurrency and budget refusals are distinguishable

Then, in your terminal
zenorm work

Your coding agent claims the task, implements it against the full spec, and gates itself on typecheck, lint, and tests.

One dissected spec per week

A real request, the questions the agent asked, and every place the server refused its output. No product announcements.