accountusage

package
v0.36.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package accountusage is the pure logic behind `hadron team usage` (cli#1472): read each configured model account's rate-limit snapshot (and optionally a ccusage JSON file the operator produced), validate everything before any record exists, and shape one `account-usage` record per account.

It reads exactly two kinds of file per account and nothing else: the snapshot at <configDir>/hadron-usage/rate-limits.json and the optional ccusage file named in the config. It never runs a subprocess and never reads anything else under a Claude config dir (credentials and transcripts live there). Errors name a path and a reason class, never file contents.

Index

Constants

View Source
const (
	// Collection is the Hadron object type the records are written under.
	Collection = "account-usage"
	// SchemaVersion is the record shape version (golden-pinned).
	SchemaVersion = 1
	// SnapshotRel is where the operator's status line writes the snapshot,
	// relative to an account's config dir.
	SnapshotRel = "hadron-usage/rate-limits.json"
)
View Source
const ActiveWindow = 6 * time.Hour

ActiveWindow bounds how long a ccusage block can keep growing (blocks are 5-hour windows; the margin covers a late final write). A block that started longer before an observation is final, so the checkpoint omits it.

Variables

This section is empty.

Functions

This section is empty.

Types

type Account

type Account struct {
	Label       string   `yaml:"label"`
	ConfigDir   string   `yaml:"configDir"`
	Family      string   `yaml:"family"`
	CcusageFile string   `yaml:"ccusageFile"`
	Workers     []string `yaml:"workers"`
	// contains filtered or unexported fields
}

Account is one configured subscription account.

type AccountView

type AccountView struct {
	Label      string     `json:"label"`
	Family     string     `json:"family"`
	Host       string     `json:"host"`
	ObservedAt string     `json:"observedAt"`
	FiveHour   WindowView `json:"fiveHour"`
	SevenDay   WindowView `json:"sevenDay"`
	Workers    []string   `json:"workers"`
	// WorkersConfigured is false when the account's workers list was never
	// configured: Workers is then empty because it is unknown, not because
	// nobody ran on the account.
	WorkersConfigured bool `json:"workersConfigured"`
	Points            int  `json:"points"`
}

AccountView is one account's current usage.

func View

func View(objects []json.RawMessage, now time.Time) []AccountView

View builds the per-account view from recorded objects (any order, any number of accounts). A record that does not parse as the documented shape is skipped, not guessed at. now decides which windows are expired.

type Block

type Block struct {
	Start  time.Time
	Tokens float64
	Cost   float64
}

Block is one ccusage 5-hour block: only the fields collect uses.

func ReadCcusage

func ReadCcusage(a Account) ([]Block, error)

ReadCcusage reads a `ccusage blocks --json` file the operator produced. An empty path means none was configured (nil, nil).

type BlockCheckpoint

type BlockCheckpoint struct {
	Start  string  `json:"start"`
	Tokens float64 `json:"tokens"`
	Cost   float64 `json:"costUsd"`
}

BlockCheckpoint is one still-growing ccusage block's totals.

type Config

type Config struct {
	// Memory is where records are written (a memory ref); `-m` overrides it.
	Memory string `yaml:"memory"`
	// Host labels this host in each record; empty means the hostname.
	Host     string    `yaml:"host"`
	Accounts []Account `yaml:"accounts"`
}

Config is the host-local YAML file (`--config`).

func LoadConfig

func LoadConfig(path string) (*Config, error)

LoadConfig reads and validates the config file. Unknown keys are refused so a typo cannot silently drop an account.

type Prepared

type Prepared struct {
	Account  Account
	Snapshot Snapshot
	Blocks   []Block
}

Prepared is one account's validated input, ready to become a record.

func Prepare

func Prepare(cfg *Config) ([]Prepared, error)

Prepare validates every account's input before anything is written. The first problem refuses the whole run (nothing is recorded for any account).

type Previous

type Previous struct {
	ObservedAt time.Time
	Blocks     *[]BlockCheckpoint
}

Previous is the checkpoint carried by this account's previous record on this host and family: its observation time and recorded blocks (nil when that record carried no checkpoint).

type Record

type Record struct {
	Label               string   `json:"label"`
	Family              string   `json:"family"`
	Host                string   `json:"host"`
	ObservedAt          string   `json:"observedAt"`
	FiveHourPct         *float64 `json:"fiveHourPct,omitempty"`
	FiveHourResetsAt    *string  `json:"fiveHourResetsAt,omitempty"`
	SevenDayPct         *float64 `json:"sevenDayPct,omitempty"`
	SevenDayResetsAt    *string  `json:"sevenDayResetsAt,omitempty"`
	TokensSinceLast     *float64 `json:"tokensSinceLast,omitempty"`
	EstCostUsdSinceLast *float64 `json:"estCostUsdSinceLast,omitempty"`
	// CcusageBlocks is the checkpoint the next collection differences against:
	// the ccusage blocks that could still be growing at observation (started
	// within ActiveWindow of it). Present, possibly empty, whenever a ccusage
	// file was read.
	CcusageBlocks     *[]BlockCheckpoint `json:"ccusageBlocks,omitempty"`
	Workers           []string           `json:"workers"`
	WorkersConfigured bool               `json:"workersConfigured"`
	SchemaVersion     int                `json:"schemaVersion"`
}

Record is the `account-usage` object's fields (schemaVersion 1). Absent values are omitted, never 0. The shape is pinned by a golden test: the portal reads it without the CLI.

func BuildRecord

func BuildRecord(p Prepared, host string, now time.Time, prev Previous) Record

BuildRecord shapes one record. observedAt is the snapshot's own observation time when there is a snapshot, else now. With a ccusage file the record carries its still-growing blocks as the checkpoint. The since-last fields are the growth of blocks that started within ActiveWindow of the previous observation (a block that started after it counts in full, a known block by its increase; older blocks are final and contribute nothing), so growth inside a running block counts and blocks evicted from a rolling file do not matter. They stay absent when there is no ccusage file or previous checkpoint, or a known block's totals went down: an interval that cannot be measured is unknown, not zero.

type Snapshot

type Snapshot struct {
	Present    bool
	ObservedAt time.Time
	FiveHour   *Window
	SevenDay   *Window
}

Snapshot is a validated rate-limits.json. A missing file is "no data": Present is false and both windows are nil.

func ReadSnapshot

func ReadSnapshot(a Account) (Snapshot, error)

ReadSnapshot reads one account's snapshot. A file that does not exist yet is no data, not an error; anything unreadable or malformed is refused.

type ValidationError

type ValidationError struct{ Msg string }

ValidationError is a refusal of the operator's input (exit 2): a config, snapshot or ccusage file that is missing, malformed or out of range.

func (*ValidationError) Error

func (e *ValidationError) Error() string

type Window

type Window struct {
	UsedPct  float64
	ResetsAt time.Time
}

Window is one rate-limit window as the harness reported it.

type WindowView

type WindowView struct {
	UsedPct *float64 `json:"usedPct"`
	// ResetsAt is when the window resets (RFC 3339).
	ResetsAt *string `json:"resetsAt"`
	// Expired is true when ResetsAt has passed: the percentage describes a
	// window that is over, so it is reported but must not be read as current.
	Expired bool `json:"expired"`
	// BurnPctPerHour is the rise in used percentage per hour across this
	// window's recorded points (needs two at different times, same window).
	BurnPctPerHour *float64 `json:"burnPctPerHour"`
	// ExhaustsAt projects when the window reaches 100% at that burn rate.
	ExhaustsAt *string `json:"exhaustsAt"`
	// ExhaustsBeforeReset is true when ExhaustsAt falls before ResetsAt.
	ExhaustsBeforeReset *bool `json:"exhaustsBeforeReset"`
}

WindowView is one window's current state for `team usage show --json`. Null fields mean unknown, never 0.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL