Documentation
¶
Overview ¶
Package cost provides cost tracking and reporting for bc agents.
The package supports both SQLite and PostgreSQL backends for persistent storage of cost records and budgets. Use OpenStore to automatically select the backend (Postgres via DATABASE_URL, falling back to SQLite).
Basic Usage ¶
Create and open a cost store:
store := cost.NewStore("/path/to/workspace")
if err := store.Open(); err != nil {
log.Fatal(err)
}
defer store.Close()
Record a cost entry:
record, err := store.Record("agent-1", "team-alpha", "claude-3-opus",
1000, // input tokens
500, // output tokens
0.05, // cost in USD
)
Get cost summaries:
// By agent summaries, _ := store.SummaryByAgent() // By model summaries, _ := store.SummaryByModel() // Total workspace cost total, _ := store.WorkspaceSummary()
Budgets ¶
Set and check budgets:
// Set monthly budget for workspace
store.SetBudget("workspace", cost.BudgetPeriodMonthly, 100.0, 0.8, false)
// Check budget status
status, _ := store.CheckBudget("workspace")
if status.IsNearLimit {
log.Warn("approaching budget limit")
}
Index ¶
- func CalcCost(model string, ...) float64
- func FindSessionFiles(claudeProjectsDir string) ([]string, error)
- type AgentDailyCost
- type Budget
- type BudgetPeriod
- type BudgetStatus
- type CostBackend
- type DailyCost
- type Importer
- type ModelPricing
- type PostgresStore
- func (s *PostgresStore) AgentSummary(ctx context.Context, agentID string) (*Summary, error)
- func (s *PostgresStore) CheckBudget(ctx context.Context, scope string) (*BudgetStatus, error)
- func (s *PostgresStore) Clear(ctx context.Context) error
- func (s *PostgresStore) Close() error
- func (s *PostgresStore) DB() *sql.DB
- func (s *PostgresStore) DeleteBudget(ctx context.Context, scope string) error
- func (s *PostgresStore) GetAgentDailyCosts(ctx context.Context, since time.Time) ([]*AgentDailyCost, error)
- func (s *PostgresStore) GetAgentSummarySince(ctx context.Context, since time.Time) ([]*Summary, error)
- func (s *PostgresStore) GetAll(ctx context.Context, limit int) ([]*Record, error)
- func (s *PostgresStore) GetAllBudgets(ctx context.Context) ([]*Budget, error)
- func (s *PostgresStore) GetAllWithOffset(ctx context.Context, limit, offset int) ([]*Record, error)
- func (s *PostgresStore) GetBudget(ctx context.Context, scope string) (*Budget, error)
- func (s *PostgresStore) GetByAgent(ctx context.Context, agentID string, limit int) ([]*Record, error)
- func (s *PostgresStore) GetByAgentWithOffset(ctx context.Context, agentID string, limit, offset int) ([]*Record, error)
- func (s *PostgresStore) GetByID(ctx context.Context, id int64) (*Record, error)
- func (s *PostgresStore) GetByTeam(ctx context.Context, teamID string, limit int) ([]*Record, error)
- func (s *PostgresStore) GetDailyCosts(ctx context.Context, since time.Time) ([]*DailyCost, error)
- func (s *PostgresStore) GetSummarySince(ctx context.Context, since time.Time) (*Summary, error)
- func (s *PostgresStore) InitSchema() error
- func (s *PostgresStore) ProjectCost(ctx context.Context, lookbackDays int, projectDuration time.Duration) (*Projection, error)
- func (s *PostgresStore) Record(ctx context.Context, agentID, teamID, model string, ...) (*Record, error)
- func (s *PostgresStore) SetBudget(ctx context.Context, scope string, period BudgetPeriod, ...) (*Budget, error)
- func (s *PostgresStore) SummaryByAgent(ctx context.Context) ([]*Summary, error)
- func (s *PostgresStore) SummaryByModel(ctx context.Context) ([]*Summary, error)
- func (s *PostgresStore) SummaryByTeam(ctx context.Context) ([]*Summary, error)
- func (s *PostgresStore) TeamSummary(ctx context.Context, teamID string) (*Summary, error)
- func (s *PostgresStore) WorkspaceSummary(ctx context.Context) (*Summary, error)
- type Projection
- type Record
- type SessionEntry
- type Store
- func (s *Store) AgentSummary(ctx context.Context, agentID string) (*Summary, error)
- func (s *Store) CheckBudget(ctx context.Context, scope string) (*BudgetStatus, error)
- func (s *Store) Clear(ctx context.Context) error
- func (s *Store) Close() error
- func (s *Store) DB() *sql.DB
- func (s *Store) DeleteBudget(ctx context.Context, scope string) error
- func (s *Store) GetAgentDailyCosts(ctx context.Context, since time.Time) ([]*AgentDailyCost, error)
- func (s *Store) GetAgentSummarySince(ctx context.Context, since time.Time) ([]*Summary, error)
- func (s *Store) GetAll(ctx context.Context, limit int) ([]*Record, error)
- func (s *Store) GetAllBudgets(ctx context.Context) ([]*Budget, error)
- func (s *Store) GetAllWithOffset(ctx context.Context, limit, offset int) ([]*Record, error)
- func (s *Store) GetBudget(ctx context.Context, scope string) (*Budget, error)
- func (s *Store) GetByAgent(ctx context.Context, agentID string, limit int) ([]*Record, error)
- func (s *Store) GetByAgentWithOffset(ctx context.Context, agentID string, limit, offset int) ([]*Record, error)
- func (s *Store) GetByID(ctx context.Context, id int64) (*Record, error)
- func (s *Store) GetByTeam(ctx context.Context, teamID string, limit int) ([]*Record, error)
- func (s *Store) GetDailyCosts(ctx context.Context, since time.Time) ([]*DailyCost, error)
- func (s *Store) GetSummarySince(ctx context.Context, since time.Time) (*Summary, error)
- func (s *Store) Open() error
- func (s *Store) ProjectCost(ctx context.Context, lookbackDays int, projectDuration time.Duration) (*Projection, error)
- func (s *Store) Record(ctx context.Context, agentID, teamID, model string, ...) (*Record, error)
- func (s *Store) SetBudget(ctx context.Context, scope string, period BudgetPeriod, ...) (*Budget, error)
- func (s *Store) SummaryByAgent(ctx context.Context) ([]*Summary, error)
- func (s *Store) SummaryByModel(ctx context.Context) ([]*Summary, error)
- func (s *Store) SummaryByTeam(ctx context.Context) ([]*Summary, error)
- func (s *Store) TeamSummary(ctx context.Context, teamID string) (*Summary, error)
- func (s *Store) WorkspaceSummary(ctx context.Context) (*Summary, error)
- type Summary
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CalcCost ¶
func CalcCost(model string, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens int64) float64
CalcCost returns the USD cost for the given token counts and model.
func FindSessionFiles ¶
FindSessionFiles returns all .jsonl session file paths under the given Claude projects root directory (~/.claude/projects/).
Types ¶
type AgentDailyCost ¶
type AgentDailyCost struct {
AgentID string `json:"agent_id"`
Date string `json:"date"`
CostUSD float64 `json:"cost_usd"`
TotalTokens int64 `json:"total_tokens"`
RecordCount int64 `json:"record_count"`
InputTokens int64 `json:"input_tokens"`
OutputTokens int64 `json:"output_tokens"`
}
AgentDailyCost represents daily cost data for a specific agent.
type Budget ¶
type Budget struct {
UpdatedAt time.Time `json:"updated_at"`
Period BudgetPeriod `json:"period"`
Scope string `json:"scope"` // "workspace", "agent:<id>", "team:<id>"
ID int64 `json:"id"`
LimitUSD float64 `json:"limit_usd"`
AlertAt float64 `json:"alert_at"` // Percentage (0.0-1.0) at which to alert
HardStop bool `json:"hard_stop"` // If true, stop when limit reached
}
Budget represents a cost budget configuration.
type BudgetPeriod ¶
type BudgetPeriod string
BudgetPeriod represents the time period for a budget.
const ( BudgetPeriodDaily BudgetPeriod = "daily" BudgetPeriodWeekly BudgetPeriod = "weekly" BudgetPeriodMonthly BudgetPeriod = "monthly" )
type BudgetStatus ¶
type BudgetStatus struct {
Budget *Budget `json:"budget"`
CurrentSpend float64 `json:"current_spend"`
Remaining float64 `json:"remaining"`
PercentUsed float64 `json:"percent_used"`
IsOverBudget bool `json:"is_over_budget"`
IsNearLimit bool `json:"is_near_limit"` // True if >= AlertAt percentage
}
BudgetStatus represents the current status against a budget.
type CostBackend ¶
type CostBackend interface {
// Lifecycle
Close() error
DB() *sql.DB
// Record operations
Record(ctx context.Context, agentID, teamID, model string, inputTokens, outputTokens int64, costUSD float64) (*Record, error)
GetByID(ctx context.Context, id int64) (*Record, error)
GetByAgent(ctx context.Context, agentID string, limit int) ([]*Record, error)
GetByAgentWithOffset(ctx context.Context, agentID string, limit, offset int) ([]*Record, error)
GetByTeam(ctx context.Context, teamID string, limit int) ([]*Record, error)
GetAll(ctx context.Context, limit int) ([]*Record, error)
GetAllWithOffset(ctx context.Context, limit, offset int) ([]*Record, error)
Clear(ctx context.Context) error
// Summary operations
SummaryByAgent(ctx context.Context) ([]*Summary, error)
SummaryByTeam(ctx context.Context) ([]*Summary, error)
SummaryByModel(ctx context.Context) ([]*Summary, error)
WorkspaceSummary(ctx context.Context) (*Summary, error)
AgentSummary(ctx context.Context, agentID string) (*Summary, error)
TeamSummary(ctx context.Context, teamID string) (*Summary, error)
GetSummarySince(ctx context.Context, since time.Time) (*Summary, error)
GetAgentSummarySince(ctx context.Context, since time.Time) ([]*Summary, error)
// Budget operations
SetBudget(ctx context.Context, scope string, period BudgetPeriod, limitUSD, alertAt float64, hardStop bool) (*Budget, error)
GetBudget(ctx context.Context, scope string) (*Budget, error)
GetAllBudgets(ctx context.Context) ([]*Budget, error)
DeleteBudget(ctx context.Context, scope string) error
CheckBudget(ctx context.Context, scope string) (*BudgetStatus, error)
// Daily cost operations
GetDailyCosts(ctx context.Context, since time.Time) ([]*DailyCost, error)
GetAgentDailyCosts(ctx context.Context, since time.Time) ([]*AgentDailyCost, error)
// Projection
ProjectCost(ctx context.Context, lookbackDays int, projectDuration time.Duration) (*Projection, error)
}
CostBackend is the storage interface implemented by both SQLiteStore (the existing Store) and PostgresStore. Higher-level wrappers delegate all persistence operations to this interface.
type DailyCost ¶
type DailyCost struct {
Date string `json:"date"`
CostUSD float64 `json:"cost_usd"`
TotalTokens int64 `json:"total_tokens"`
RecordCount int64 `json:"record_count"`
InputTokens int64 `json:"input_tokens"`
OutputTokens int64 `json:"output_tokens"`
}
DailyCost represents aggregated cost data for a single day.
type Importer ¶
type Importer struct {
// contains filtered or unexported fields
}
Importer scans Claude Code JSONL session files and imports token usage into the cost.db store. It tracks which session files have been imported to avoid double-counting.
func NewImporter ¶
NewImporter creates an Importer for the given workspace.
type ModelPricing ¶
type ModelPricing struct {
InputPerM float64
OutputPerM float64
CacheWritePerM float64 // cache_creation_input_tokens
CacheReadPerM float64 // cache_read_input_tokens
}
ModelPricing holds per-token pricing for a Claude model in USD per 1M tokens.
func PricingFor ¶
func PricingFor(model string) ModelPricing
PricingFor returns the pricing for a model (matched by prefix, case-insensitive prefix walk).
type PostgresStore ¶
type PostgresStore struct {
// contains filtered or unexported fields
}
PostgresStore provides Postgres-backed cost tracking. It implements CostBackend with the same API as the SQLite Store.
func NewPostgresStore ¶
func NewPostgresStore(db *sql.DB) *PostgresStore
NewPostgresStore creates a PostgresStore from an existing *sql.DB connection.
func (*PostgresStore) AgentSummary ¶
AgentSummary returns the cost summary for a specific agent.
func (*PostgresStore) CheckBudget ¶
func (s *PostgresStore) CheckBudget(ctx context.Context, scope string) (*BudgetStatus, error)
CheckBudget returns the current status against a budget.
func (*PostgresStore) Clear ¶
func (s *PostgresStore) Clear(ctx context.Context) error
Clear removes all cost records.
func (*PostgresStore) Close ¶
func (s *PostgresStore) Close() error
Close is a no-op — the shared DB is owned by the caller.
func (*PostgresStore) DB ¶
func (s *PostgresStore) DB() *sql.DB
DB returns the underlying database connection.
func (*PostgresStore) DeleteBudget ¶
func (s *PostgresStore) DeleteBudget(ctx context.Context, scope string) error
DeleteBudget removes a budget for the given scope.
func (*PostgresStore) GetAgentDailyCosts ¶
func (s *PostgresStore) GetAgentDailyCosts(ctx context.Context, since time.Time) ([]*AgentDailyCost, error)
GetAgentDailyCosts returns daily cost totals per agent since the given time.
func (*PostgresStore) GetAgentSummarySince ¶
func (s *PostgresStore) GetAgentSummarySince(ctx context.Context, since time.Time) ([]*Summary, error)
GetAgentSummarySince returns per-agent summaries since the given time.
func (*PostgresStore) GetAllBudgets ¶
func (s *PostgresStore) GetAllBudgets(ctx context.Context) ([]*Budget, error)
GetAllBudgets returns all configured budgets.
func (*PostgresStore) GetAllWithOffset ¶
GetAllWithOffset returns cost records with pagination.
func (*PostgresStore) GetByAgent ¶
func (s *PostgresStore) GetByAgent(ctx context.Context, agentID string, limit int) ([]*Record, error)
GetByAgent returns cost records for an agent.
func (*PostgresStore) GetByAgentWithOffset ¶
func (s *PostgresStore) GetByAgentWithOffset(ctx context.Context, agentID string, limit, offset int) ([]*Record, error)
GetByAgentWithOffset returns cost records for an agent with pagination.
func (*PostgresStore) GetDailyCosts ¶
GetDailyCosts returns daily cost totals since the given time.
func (*PostgresStore) GetSummarySince ¶
GetSummarySince returns a summary of costs since the given time.
func (*PostgresStore) InitSchema ¶
func (s *PostgresStore) InitSchema() error
InitSchema creates the cost tables in Postgres if they don't exist.
func (*PostgresStore) ProjectCost ¶
func (s *PostgresStore) ProjectCost(ctx context.Context, lookbackDays int, projectDuration time.Duration) (*Projection, error)
ProjectCost calculates a projected cost based on historical daily average.
func (*PostgresStore) Record ¶
func (s *PostgresStore) Record(ctx context.Context, agentID, teamID, model string, inputTokens, outputTokens int64, costUSD float64) (*Record, error)
Record adds a new cost record.
func (*PostgresStore) SetBudget ¶
func (s *PostgresStore) SetBudget(ctx context.Context, scope string, period BudgetPeriod, limitUSD, alertAt float64, hardStop bool) (*Budget, error)
SetBudget creates or updates a budget for the given scope.
func (*PostgresStore) SummaryByAgent ¶
func (s *PostgresStore) SummaryByAgent(ctx context.Context) ([]*Summary, error)
SummaryByAgent returns aggregated costs per agent.
func (*PostgresStore) SummaryByModel ¶
func (s *PostgresStore) SummaryByModel(ctx context.Context) ([]*Summary, error)
SummaryByModel returns aggregated costs per model.
func (*PostgresStore) SummaryByTeam ¶
func (s *PostgresStore) SummaryByTeam(ctx context.Context) ([]*Summary, error)
SummaryByTeam returns aggregated costs per team.
func (*PostgresStore) TeamSummary ¶
TeamSummary returns the cost summary for a specific team.
func (*PostgresStore) WorkspaceSummary ¶
func (s *PostgresStore) WorkspaceSummary(ctx context.Context) (*Summary, error)
WorkspaceSummary returns the total cost summary for the workspace.
type Projection ¶
type Projection struct {
Duration time.Duration `json:"duration"`
DailyAvgCost float64 `json:"daily_avg_cost"`
ProjectedCost float64 `json:"projected_cost"`
DaysAnalyzed int `json:"days_analyzed"`
TotalHistorical float64 `json:"total_historical"`
}
Projection represents a cost projection based on historical data.
type Record ¶
type Record struct {
Timestamp time.Time `json:"timestamp"`
AgentID string `json:"agent_id"`
Model string `json:"model"`
TeamID string `json:"team_id,omitempty"`
ID int64 `json:"id"`
InputTokens int64 `json:"input_tokens"`
OutputTokens int64 `json:"output_tokens"`
TotalTokens int64 `json:"total_tokens"`
CostUSD float64 `json:"cost_usd"`
}
Record represents a cost entry for an API call.
type SessionEntry ¶
type SessionEntry struct {
Timestamp time.Time
SessionID string
Model string
CWD string
InputTokens int64
OutputTokens int64
CacheCreationTokens int64
CacheReadTokens int64
}
SessionEntry is a parsed assistant message from a Claude Code JSONL session file.
func ParseSessionFile ¶
func ParseSessionFile(path string) ([]SessionEntry, error)
ParseSessionFile reads a Claude Code JSONL session file and returns all assistant message entries that contain token usage.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store provides cost tracking backed by SQLite or Postgres. When created via OpenStore, the backend field is set and all operations are delegated to it. When created via NewStore/Open (legacy), the store uses its embedded SQLite connection directly.
func OpenStore ¶
OpenStore opens the cost store using the shared workspace database. Uses the shared driver type to determine the backend (timescale or sqlite).
func (*Store) AgentSummary ¶
AgentSummary returns the cost summary for a specific agent.
func (*Store) CheckBudget ¶
CheckBudget returns the current status against a budget.
func (*Store) Close ¶
Close is a no-op — the shared DB is owned by the caller. The Postgres backend also uses the shared connection now.
func (*Store) DeleteBudget ¶
DeleteBudget removes a budget for the given scope.
func (*Store) GetAgentDailyCosts ¶
GetAgentDailyCosts returns daily cost totals per agent since the given time.
func (*Store) GetAgentSummarySince ¶
GetAgentSummarySince returns per-agent summaries since the given time.
func (*Store) GetAllBudgets ¶
GetAllBudgets returns all configured budgets.
func (*Store) GetAllWithOffset ¶
GetAllWithOffset returns cost records with pagination support.
func (*Store) GetByAgent ¶
GetByAgent returns all cost records for an agent.
func (*Store) GetByAgentWithOffset ¶
func (s *Store) GetByAgentWithOffset(ctx context.Context, agentID string, limit, offset int) ([]*Record, error)
GetByAgentWithOffset returns cost records for an agent with pagination support.
func (*Store) GetDailyCosts ¶
GetDailyCosts returns daily cost totals since the given time.
func (*Store) GetSummarySince ¶
GetSummarySince returns a summary of costs since the given time.
func (*Store) ProjectCost ¶
func (s *Store) ProjectCost(ctx context.Context, lookbackDays int, projectDuration time.Duration) (*Projection, error)
ProjectCost calculates a projected cost based on historical daily average.
func (*Store) Record ¶
func (s *Store) Record(ctx context.Context, agentID, teamID, model string, inputTokens, outputTokens int64, costUSD float64) (*Record, error)
Record adds a new cost record.
func (*Store) SetBudget ¶
func (s *Store) SetBudget(ctx context.Context, scope string, period BudgetPeriod, limitUSD, alertAt float64, hardStop bool) (*Budget, error)
SetBudget creates or updates a budget for the given scope.
func (*Store) SummaryByAgent ¶
SummaryByAgent returns aggregated costs per agent.
func (*Store) SummaryByModel ¶
SummaryByModel returns aggregated costs per model.
func (*Store) SummaryByTeam ¶
SummaryByTeam returns aggregated costs per team.
func (*Store) TeamSummary ¶
TeamSummary returns the cost summary for a specific team.
type Summary ¶
type Summary struct {
AgentID string `json:"agent_id,omitempty"`
TeamID string `json:"team_id,omitempty"`
Model string `json:"model,omitempty"`
InputTokens int64 `json:"input_tokens"`
OutputTokens int64 `json:"output_tokens"`
TotalTokens int64 `json:"total_tokens"`
TotalCostUSD float64 `json:"total_cost_usd"`
RecordCount int64 `json:"record_count"`
}
Summary represents aggregated cost data.