Skip to content

scaffold+broker: dedicated <ns>.balance method for managed budget apps#73

Open
Alexgodoroja wants to merge 1 commit into
pilot-protocol:mainfrom
Alexgodoroja:feat/broker-balance-method
Open

scaffold+broker: dedicated <ns>.balance method for managed budget apps#73
Alexgodoroja wants to merge 1 commit into
pilot-protocol:mainfrom
Alexgodoroja:feat/broker-balance-method

Conversation

@Alexgodoroja

Copy link
Copy Markdown
Collaborator

Problem

Managed (credit-metered) apps meter a per-user $-budget and surface it on the X-Pilot-Credits-Remaining header — but a keyless adapter only returns the response body, so an agent can't actually read that header. There was no first-class way to answer "how much budget do I have left?" before a spend op.

The broker already had half of this: serveCreditBalance + an optional credit.balance_path to shadow a partner's account-balance endpoint (so it returns per-user budget instead of leaking the pooled account). But it was opt-in with no default and no adapter-facing method — dormant.

This PR — wires it end to end

  • Broker: answers a canonical /_pilot/balance for any credit app, from its own per-caller ledger — no upstream call, no master key, no debit, never a 402, scoped to the caller (pooled balance never disclosed). Reuses the existing serveCreditBalance; the canonical path is always available alongside the optional creditBalancePath shadow.
  • Scaffolder: auto-injects <ns>.balance into every auth: managed app (no submission field) — a GET to /_pilot/balance that flows through registration, the manifest exposes list, and <ns>.help like any authored method.
  • scaffold.BalanceMetaPath == broker.pilotBalancePath keeps both ends in sync.

Response body:

{ "balance": "$1.80", "credits_remaining": 1800000, "credits_seed": 5000000,
  "unit": "micro_usd", "scope": "per-pilot-user" }

Tests

  • Broker (zz_balance_meta_test.go): canonical path seeds a fresh caller, reflects a spend, is free, and never forwards upstream.
  • Scaffold (zz_balance_method_test.go): injected for managed apps only (not byo), generated + wired to the reserved path + in the manifest, and the project compiles.
  • Full broker + scaffold + publish suites green.

Docs

MANAGED-KEY.md and PUBLISHING-PLAYBOOK.md document the pattern for all broker apps that meter a budget: set the credit block → the adapter exposes <ns>.balance for free; tell agents to check it (or the header) before a spend.

Managed (credit-metered) apps could meter a per-user $-budget and surface it
on the X-Pilot-Credits-Remaining header, but a keyless adapter only returns the
response body — so an agent could never actually read its balance, and there was
no first-class way to check funds before a spend op.

This wires a dedicated balance method, end to end:

- Broker answers a canonical /_pilot/balance for any credit app from its own
  per-caller ledger — no upstream call, no master key, no debit, never a 402,
  scoped to the caller (the pooled account balance is never disclosed). Reuses
  the existing serveCreditBalance (which also backs the optional creditBalancePath
  partner-endpoint shadow); the canonical path is always available alongside it.
- Scaffolder auto-injects `<ns>.balance` into every `auth: managed` app (no
  submission field), a GET to that path — flowing through registration, the
  manifest `exposes` list, and `<ns>.help` like any authored method.
- scaffold.BalanceMetaPath == broker.pilotBalancePath keeps the two ends in sync.
- Tests: broker (canonical path seeds, reflects spend, free, never forwards) and
  scaffold (injected for managed only, generated + compiles + in the manifest).
- Docs: MANAGED-KEY.md and the publishing playbook document the pattern for all
  broker apps that meter a budget.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant