feat(agents,budget): per-persona spending-cap primitive (OpenRouter Phase 0)#411
Merged
Conversation
…hase 0) DA must-fix #3 from the OpenRouter integration analysis: without a spending-cap envelope, fusion (4.4x cost) + recursing Hermes loops could drain $200/credit overnight. Land the primitive BEFORE adding any paid-surface provider (V1 OpenRouter upstream, V2 hal0-fusion MCP). Adds `[persona.budget]` TOML block + a pure-Python BudgetLedger (append-only JSONL at /var/lib/hal0/agents/{id}/personas/{pid}/spend.jsonl) + a check/charge API + a UI editor. API: - GET /api/agents/{id}/personas/{pid}/budget - PUT /api/agents/{id}/personas/{pid}/budget - POST /api/agents/{id}/personas/{pid}/budget/check (dry-run pre-call gate) - POST /api/agents/{id}/personas/{pid}/budget/charge (post-response record) Scope decision (PLANNING.md §5 Q2): per-persona only for v0.3. Per-agent + platform caps are containing scopes deferred to v0.4. Race-tolerance: append-only ledger + read-then-check is eventual consistency; periodic over-spend within one window is acceptable. No provider charges to this primitive yet. V1 (OpenRouter as Hermes upstream) will wire it in as a pre-call gate + post-response record. Refs openrouter-research-2026-05-28/PLANNING.md §3 Phase 0 + §5 Q2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
thinmintdev
added a commit
that referenced
this pull request
May 29, 2026
End-of-stream cut for v0.3. Bundles MCP-completion, memory-map redesign, Settings → Updates fix (#386), silent-eviction dispatcher recovery (#392), ADR-0020 OpenRouter callback skeleton (#409), persona spending-cap primitive (#411), δ-harness Hermes coverage (#410), and the docs/internal pin + dashboard-v3 walkthrough (#389/#390). After this tag, active scope rolls to v0.4 (install-mode reconciliation + UI polish + fully-implemented Agents/UI/Install bootstrapped) and v0.5 (MCP admin + memory wiring across UI and agents). CHANGELOG merged from two coexisting Unreleased blocks into a single [v0.3.2-alpha.1] section; added missing entries for #392 (dispatcher), #387 (async-job polling contract), and the docs PRs #389/#390. pyproject 0.3.1-alpha.1 → 0.3.2-alpha.1. uv.lock resynced (was stuck at 0.3.0a1 from prior drift). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
[persona.budget]TOML block +BudgetLedger(append-only JSONL at/var/lib/hal0/agents/{id}/personas/{pid}/spend.jsonl)/api/agents/{id}/personas/{pid}/budgetREST surface (GET / PUT / check / charge)PersonaBudgetPanel+ TanStack hooks)Why now
DA review of the OpenRouter integration plan flagged this as P0 must-fix #3 (fusion 4.4x cost + recursion = $200/credit drain risk). Lands BEFORE V1 OpenRouter provider + V2 fusion MCP so they have a budget gate from day 1.
Scope locked
tail -f+jq.hard_cap=Truedefault (block over budget);hard_cap=Falseis warn-only.Test plan
ruff format --check/ruff check/mypy/pytest(58 passed)tsc --noEmittypecheckIdempotency
hal0 agent reprovision hermesafter the operator PUTs a budget preserves the caps:_phase_persona_seedcallsseed_default_personas(overwrite=False)which skips existing files. Only--repairre-writes seeds back to canonical empty.Refs
openrouter-research-2026-05-28/PLANNING.md§3 Phase 0 + §5 Q2.🤖 Generated with Claude Code