goei

package
v0.1.9 Latest Latest
Warning

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

Go to latest
Published: Jun 10, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package goei pushes locally-computed Claude Code spend aggregates to a Goei dashboard's device-token ingest endpoint.

This is the "zero-key" half of Goei's two-track trust model: instead of handing Goei an Anthropic admin API key, the user runs budgetclaw locally (which only ever reads ~/.claude/projects/*.jsonl) and ships aggregated dollar-and-token rollups to their own dashboard. No key leaves the machine; the only thing transmitted is the cost summary.

The wire contract mirrors Goei's POST /api/ingest handler:

  • Authorization: Bearer goei_dt_<32-hex> (exactly 40 chars)
  • body: {provider, spend[], usage?} provider must be "anthropic"
  • spend dedup key: (period_start, model, project, branch)
  • usage dedup key: (period_start, metric_type, model, breakdown_key, breakdown_value)

Per-branch attribution (a budgetclaw differentiator) rides on the spend record's own optional branch field, so the project field always carries the bare project name. With --no-branch the branch is omitted and all branches of a project collapse server-side. Usage records break down by bare project name regardless.

Both arrays dedupe server-side via upsert, so re-running sync is idempotent: the same day re-sent overwrites, it does not double-count.

Index

Constants

View Source
const DefaultEndpoint = "https://goei.roninforge.org/api/ingest"

DefaultEndpoint is the production Goei ingest URL.

View Source
const Provider = "anthropic"

Provider is the only provider value Goei accepts for Claude Code data. Claude Code spend is Anthropic API spend.

Variables

This section is empty.

Functions

func ValidToken

func ValidToken(t string) bool

ValidToken reports whether a string is shaped like a Goei device token: the "goei_dt_" prefix plus a 32-char body, 40 chars total. This matches the format check Goei's ingest handler enforces.

Types

type Aggregate

type Aggregate struct {
	Project            string
	GitBranch          string
	Model              string
	Day                string // YYYY-MM-DD (UTC)
	CostUSD            float64
	InputTokens        int
	OutputTokens       int
	CacheReadTokens    int
	CacheWrite5mTokens int
	CacheWrite1hTokens int
}

Aggregate is the neutral input to BuildPayloads, decoupled from the db package so this package has no storage dependency. It mirrors db.SyncAggregate.

type Client

type Client struct {
	Endpoint string
	Token    string
	HTTP     *http.Client
}

Client posts payloads to a Goei ingest endpoint.

func New

func New(endpoint, token string) *Client

New returns a Client with sane defaults. An empty endpoint falls back to DefaultEndpoint.

func (*Client) Push

func (c *Client) Push(ctx context.Context, p Payload) (int, error)

Push sends a single payload and returns the number of records Goei reports it stored. Errors include the HTTP status and a snippet of the response body for diagnosis.

type Payload

type Payload struct {
	Provider string        `json:"provider"`
	Spend    []SpendRecord `json:"spend"`
	Usage    []UsageRecord `json:"usage,omitempty"`
}

Payload is one POST body to /api/ingest.

func BuildPayloads

func BuildPayloads(aggregates []Aggregate, includeBranch bool) []Payload

BuildPayloads converts aggregates into one or more ingest payloads, chunked to stay under the server's per-request caps. Aggregates are grouped by day and whole days are packed into requests, so every request carries each day's spend and usage together and no request is ever spend-empty (which the endpoint rejects).

A spend record is emitted for every aggregate (including ones that round to zero cents) so that a day with only sub-cent usage still has the spend row its usage rows ride along with. Usage records are emitted only for non-zero token metrics.

type SpendRecord

type SpendRecord struct {
	PeriodStart string `json:"periodStart"`
	PeriodEnd   string `json:"periodEnd"`
	AmountCents int    `json:"amountCents"`
	Currency    string `json:"currency"`
	Model       string `json:"model,omitempty"`
	Project     string `json:"project,omitempty"`
	Branch      string `json:"branch,omitempty"`
}

SpendRecord is one daily per-(model, project, branch) dollar amount. Branch is optional: when empty (the --no-branch case) the server collapses every branch of a project into a single project-level row.

type UsageRecord

type UsageRecord struct {
	PeriodStart    string `json:"periodStart"`
	PeriodEnd      string `json:"periodEnd"`
	MetricType     string `json:"metricType"`
	MetricValue    int    `json:"metricValue"`
	Model          string `json:"model,omitempty"`
	BreakdownKey   string `json:"breakdownKey,omitempty"`
	BreakdownValue string `json:"breakdownValue,omitempty"`
}

UsageRecord is one daily per-(model, project) token count for a single metric type.

Jump to

Keyboard shortcuts

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