Skip to content

feat: account registry and quota rotation for multi-account agent sessions #19

@julianknutsen

Description

@julianknutsen

Summary

Gas City needs an account registry and quota rotation system so that agents can be rotated to a different provider account when one hits rate limits. This is critical for sustained multi-agent operation — without it, a rate-limited account blocks all agents using it until the limit resets.

Gastown implements this across two subsystems: an account registry (gt account) and a quota rotation engine (gt quota). Gas City should provide equivalent infrastructure.

Gastown Reference

Account Registry

Commands: gt account list|add|default|status|switch

Data model:

  • Accounts stored in <town>/mayor/accounts.json
  • Each account has: email, description, config_dir (path to CLAUDE_CONFIG_DIR)
  • One account is marked default
  • Account directories live at ~/.claude-accounts/<handle>/
  • ~/.claude is a symlink to the active account's config dir

Resolution priority: GT_ACCOUNT env > --account flag > default from config > fallback

Session wiring: The resolved account's config_dir is set as CLAUDE_CONFIG_DIR in the tmux session environment before the agent binary launches.

Quota State

File: <town>/mayor/quota.json (flock-protected)

Per-account state:

status: available | limited | cooldown
limited_at: RFC3339 timestamp
resets_at: human-readable reset time (parsed from provider output)
last_used: RFC3339 timestamp (for LRU assignment)

Rate-Limit Detection

Pattern-based scanning of tmux pane content (last 30 lines):

You've hit your limit
resets \d+[:\d]*(am|pm)\b
Stop and wait for limit to reset
Add funds to continue with extra usage

Maps session → account handle via CLAUDE_CONFIG_DIR environment variable in the tmux session.

Quota Rotation

Commands: gt quota status|scan|rotate|clear

Rotation algorithm:

  1. Scan all sessions for rate-limit patterns
  2. Load quota state (flock held for entire operation)
  3. Mark detected limited accounts in state
  4. Get available accounts sorted by LRU (least-recently-used first)
  5. Assign all limited sessions to best available account
  6. For each session: resolve new config dir → update tmux env → kill pane → respawn with new CLAUDE_CONFIG_DIR
  7. Single atomic save after all rotations

Key design decisions:

  • Manual trigger model — gt quota rotate must be called explicitly (a patrol formula could automate this)
  • LRU assignment — all limited sessions drain to the same account (least recently used)
  • Atomic execution — flock held for entire rotation, single state save at end
  • Session resume support — optional via SessionLinker callback, falls back to fresh start

Gas City Design Considerations

What maps cleanly

  • Account registry → could be a [accounts] section in city.toml or a separate accounts.toml
  • gc account list|add|default → straightforward CLI commands
  • CLAUDE_CONFIG_DIR wiring → already have ConfigDirEnv concept in runtime config
  • Quota state → .gc/quota.json with flock

What needs Gas City adaptation

  • Provider-agnostic patterns: Gastown only handles Claude. Gas City supports multiple providers — rate-limit patterns should be configurable per provider preset, not hardcoded
  • Config field: Need an account field on [[agent]] config (and AgentPatch/AgentOverride/pool deep-copy per CLAUDE.md conventions)
  • Per-sling account: gc sling --account <handle> to override which account the spawned agent uses (for quota rotation on dispatch)
  • No symlink management: Gas City should set CLAUDE_CONFIG_DIR per-session, not manage a global symlink. Multiple cities may run concurrently with different accounts
  • Controller integration: Rate-limit scanning could be a health patrol check rather than a separate command, fitting the existing health monitoring infrastructure (Level 6 capability)

Progressive activation

  • Level 0-1: account field on agent config, gc account commands, CLAUDE_CONFIG_DIR wiring
  • Level 6+: Quota scanning as health check, automatic rotation via patrol formula or order

Acceptance Criteria

  • Account registry with gc account list|add|default commands
  • account field on [[agent]] config wired through to session CLAUDE_CONFIG_DIR
  • --account flag on gc sling for per-dispatch account override
  • Quota state tracking (.gc/quota.json with flock)
  • gc quota status|scan|rotate|clear commands
  • Rate-limit pattern scanning of agent sessions
  • LRU-based rotation assignment
  • Atomic rotation execution (flock + single save)
  • Provider-agnostic pattern configuration (not hardcoded to Claude)
  • Tests for account resolution, quota state, scan, rotation

References

  • Gastown account CLI: gastown/internal/cmd/account.go
  • Gastown account types: gastown/internal/config/types.go (AccountsConfig, Account)
  • Gastown account resolution: gastown/internal/config/loader.go (ResolveAccountConfigDir)
  • Gastown quota engine: gastown3/internal/quota/ (state, scan, executor, rotate)
  • Gastown rate-limit patterns: gastown3/internal/constants/constants.go
  • Gas City feature parity audit: item 2.2
wasteland:
  type: feature
  priority: 2
  effort: large

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/enhancementNew capabilitypriority/p2Medium — real problem, workaround existswastelandTracked by Wasteland sync

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions