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)
Each spend record also carries an optional inline "tokens" object (input, output, cache_read, cache_write_5m, cache_write_1h) at the same per-(day, project, branch, model) grain as its dollar amount. The current server ignores it and keys off amountCents; a future server prefers tokens so it can re-price at its own point-in-time rate. Both are always sent, so the change is backward compatible.
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 ¶
const DefaultEndpoint = "https://goei.roninforge.org/api/ingest"
DefaultEndpoint is the production Goei ingest URL.
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 ¶
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 ¶
Client posts payloads to a Goei ingest endpoint.
func New ¶
New returns a Client with sane defaults. An empty endpoint falls back to DefaultEndpoint.
func (*Client) PullPolicies ¶ added in v1.3.0
func (c *Client) PullPolicies(ctx context.Context, etag string) (resp *PolicyResponse, newETag string, notModified bool, err error)
PullPolicies fetches this device's Guard Mode policy set from GET /api/policy. A conditional request with the last ETag returns notModified=true and no body when nothing changed, so `budgetclaw watch` can poll cheaply. The returned etag should be passed to the next call.
type GuardEvent ¶ added in v1.3.0
type GuardEvent struct {
PolicyID string `json:"policyId"`
Action string `json:"action"` // notify | warn | kill | override
ScopeType string `json:"scopeType,omitempty"`
ScopeValue string `json:"scopeValue,omitempty"`
Machine string `json:"machine,omitempty"`
AmountCents int `json:"amountCents"`
CapCents int `json:"capCents"`
At string `json:"at,omitempty"`
// DedupKey makes reporting idempotent: the server INSERT OR IGNOREs on
// it, so a re-sent event (same period, same action) is recorded once.
DedupKey string `json:"dedupKey,omitempty"`
}
GuardEvent is one enforcement audit record: a remote policy warned or killed a runaway on this machine. Content-free by construction (ids, amounts, scope labels, machine, timestamps only), so it upholds the zero-prompt pledge exactly like the spend records do.
type Payload ¶
type Payload struct {
Provider string `json:"provider"`
Spend []SpendRecord `json:"spend"`
Usage []UsageRecord `json:"usage,omitempty"`
// GuardEvents carries content-free enforcement audit records back up
// with the sync (Guard Mode's audit channel). Omitted when there are
// none, so a plain sync is byte-for-byte unchanged.
GuardEvents []GuardEvent `json:"guardEvents,omitempty"`
}
Payload is one POST body to /api/ingest.
func BuildPayloads ¶
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.
machine is stamped on every spend record so the server can attribute rollups to the machine they came from. An empty machine is fine: the omitempty field is dropped and the server treats it as legacy.
type PolicyResponse ¶ added in v1.3.0
type PolicyResponse struct {
PolicyVersion int `json:"policyVersion"`
Policies []WirePolicy `json:"policies"`
}
PolicyResponse is the Guard Mode policy bundle, returned both by GET /api/policy and piggybacked on the POST /api/ingest response.
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"`
Machine string `json:"machine,omitempty"`
Tokens *TokenCounts `json:"tokens,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.
Machine is an optional per-machine identity (typically the OS hostname). The Goei server uses it to keep two machines' rollups from colliding: the same (day, project, branch, model) synced from a laptop and a desktop stay separate instead of overwriting each other. When empty the server treats it as legacy/unknown, so the field is additive and backward compatible.
Tokens is an optional per-(day, project, branch, model) token rollup at the same grain as AmountCents. The current Goei server ignores it and keys off AmountCents; a future server prefers Tokens so it can re-price at its own point-in-time rate. Both are always sent.
type TokenCounts ¶ added in v1.0.0
type TokenCounts struct {
Input int `json:"input"`
Output int `json:"output"`
CacheRead int `json:"cache_read"`
CacheWrite5m int `json:"cache_write_5m"`
CacheWrite1h int `json:"cache_write_1h"`
}
TokenCounts is the per-(day, project, branch, model) token rollup carried inline on a spend record. It is the same grain as the spend dollar amount, so a future Goei server can re-price the tokens at its own point-in-time rate instead of trusting amountCents. The current server ignores this field; sending it is forward-compatible.
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.
type WirePolicy ¶ added in v1.3.0
type WirePolicy struct {
ID string `json:"id"`
Scope struct {
Type string `json:"type"`
Value string `json:"value"`
} `json:"scope"`
Period string `json:"period"`
CapCents int `json:"capCents"`
Enforcement string `json:"enforcement"`
Action string `json:"action"`
ServerSpentCents int `json:"serverSpentCents"`
AsOf string `json:"asOf"`
SetBy string `json:"setBy"`
Source string `json:"source"`
}
WirePolicy is one budget policy as Goei serializes it for this device on the Guard Mode down-channel. enforcement is "local_exact" (enforce against this machine's own rollup, kill-eligible) or "server_aggregate" (a team-wide figure this device can only warn against, with staleness).