Documentation
¶
Overview ¶
Package contracts defines the shared types and interfaces used across all ccx internal packages. Every other internal/* package imports from this package only — never from sibling packages. This isolation is what allows Phase 1 development to run in parallel git worktrees.
Index ¶
- Variables
- type DaemonStatus
- type Doctor
- type DoctorCheck
- type Event
- type HeadroomRecommendation
- type HookEvent
- type PricingTable
- type Profile
- type ProfileHealth
- type ProfileLimits
- type ProfileQuota
- type QuotaWindow
- type RecommendationEvent
- type RecommendationLevel
- type Scanner
- type SessionQuery
- type SessionTelemetry
- type Shell
- type ShellEmitter
- type Store
- type TimeRange
- type Usage
- type UsageQuery
- type UsageRow
Constants ¶
This section is empty.
Variables ¶
var ( // ErrProfileNotFound is returned when the requested profile name has no // entry in the registry. ErrProfileNotFound = errors.New("profile not found") // ErrProfileAlreadyExists is returned by profile-add when a profile with // the requested name is already registered. ErrProfileAlreadyExists = errors.New("profile already exists") // ErrInvalidConfigDir is returned when a path is not a valid Claude Code // config directory (e.g., not a directory, or unreadable). ErrInvalidConfigDir = errors.New("invalid config directory") // ErrConfigDirConflict is returned when two profiles would point at the // same config directory. ErrConfigDirConflict = errors.New("config directory already used by another profile") // ErrUnknownShell is returned when a shell name is not recognized by the // shell package (see ParseShell). ErrUnknownShell = errors.New("unknown shell") // ErrNoActiveProfile is returned when an operation requires an active // profile but neither CCX_ACTIVE_PROFILE nor CLAUDE_CONFIG_DIR is set. ErrNoActiveProfile = errors.New("no active profile") )
Sentinel errors. All ccx packages return one of these (wrapped with %w for context) for known, expected failure modes. Tests and callers use errors.Is to detect them.
Functions ¶
This section is empty.
Types ¶
type DaemonStatus ¶
type DaemonStatus struct {
PID int `json:"pid"`
Version string `json:"version"`
StartedAt time.Time `json:"started_at"`
Port int `json:"port"`
URL string `json:"url"`
DBPath string `json:"db_path"`
LogPath string `json:"log_path"`
ExecutablePath string `json:"executable_path,omitempty"`
StartToken string `json:"start_token,omitempty"`
ProcessIdentity string `json:"process_identity,omitempty"`
ProfilesWatched int `json:"profiles_watched"`
Running bool `json:"running"`
}
DaemonStatus is the daemon's externally visible runtime state.
type Doctor ¶
type Doctor interface {
Run(ctx context.Context) ([]DoctorCheck, error)
}
Doctor runs diagnostic checks and reports them as a structured slice.
type DoctorCheck ¶
DoctorCheck is one diagnostic finding. Status is "ok", "warn", or "fail".
type Event ¶
type Event struct {
UUID string `json:"uuid"`
SessionID string `json:"session_id"`
Timestamp time.Time `json:"timestamp"`
Type string `json:"type"`
Project string `json:"project"`
Model string `json:"model,omitempty"`
Usage *Usage `json:"usage,omitempty"`
}
Event is a single parsed JSONL line from a Claude Code session file. The Usage field is non-nil only for assistant events that carry token counts.
type HeadroomRecommendation ¶
type HeadroomRecommendation struct {
Profile string `json:"profile"`
Score float64 `json:"score"`
HeadroomPercent float64 `json:"headroom_percent"`
Available bool `json:"available"`
Reason string `json:"reason"`
CooldownUntil time.Time `json:"cooldown_until"`
AuthStatus string `json:"auth_status"`
}
HeadroomRecommendation is an advisory ranking for profile selection.
type HookEvent ¶
type HookEvent struct {
Profile string `json:"profile"`
Session string `json:"session"`
Event string `json:"event"`
Timestamp time.Time `json:"timestamp"`
Transcript string `json:"transcript"`
CWD string `json:"cwd"`
Model string `json:"model"`
Source string `json:"source"`
Permission string `json:"permission"`
Reason string `json:"reason"`
Error string `json:"error"`
ErrorDetails string `json:"error_details"`
Trigger string `json:"trigger"`
}
HookEvent captures one daemon-facing hook event emitted by Claude Code.
type PricingTable ¶
type PricingTable interface {
Cost(model string, ts time.Time, usage Usage) (float64, error)
LastUpdated() time.Time
}
PricingTable returns estimated USD cost for a given model + usage at a given timestamp. Implementations consult an embedded pricing YAML; users may override via ~/.ccx/pricing.yaml.
type Profile ¶
type Profile struct {
Name string `json:"name" toml:"name"`
ConfigDir string `json:"config_dir" toml:"config_dir"`
Label string `json:"label" toml:"label,omitempty"`
Color string `json:"color" toml:"color,omitempty"`
CreatedAt time.Time `json:"created_at" toml:"created_at"`
LastUsedAt time.Time `json:"last_used_at" toml:"last_used_at"`
Limits ProfileLimits `json:"limits" toml:"limits,omitempty"`
}
Profile identifies a Claude Code account by its config directory. The ConfigDir field is the only thing that determines identity — setting CLAUDE_CONFIG_DIR to this value is what isolates the account.
type ProfileHealth ¶
type ProfileHealth struct {
Profile string `json:"profile"`
CheckedAt time.Time `json:"checked_at"`
AuthStatus string `json:"auth_status"`
AuthDetail string `json:"auth_detail"`
}
ProfileHealth records the latest authentication health check for a profile.
type ProfileLimits ¶
type ProfileLimits struct {
DailyTokenBudget int `json:"daily_token_budget" toml:"daily_token_budget,omitempty"`
WeeklyTokenBudget int `json:"weekly_token_budget" toml:"weekly_token_budget,omitempty"`
MonthlyUSDBudget float64 `json:"monthly_usd_budget" toml:"monthly_usd_budget,omitempty"`
Priority int `json:"priority" toml:"priority,omitempty"`
SuggestEnabled *bool `json:"suggest_enabled" toml:"suggest_enabled,omitempty"`
RateLimitCooldown string `json:"rate_limit_cooldown" toml:"rate_limit_cooldown,omitempty"`
// PlanTier identifies the Anthropic subscription tier this profile uses.
// One of "pro", "max5", "max20", "api". Empty disables plan-aware quota
// tracking for this profile.
PlanTier string `json:"plan_tier,omitempty" toml:"plan_tier,omitempty"`
// WeeklyAnchor controls how the weekly quota window is computed. "rolling"
// (default) counts the trailing 7 days. A weekday name ("monday".."sunday")
// anchors the window to the most recent occurrence of that weekday at
// 00:00 UTC.
WeeklyAnchor string `json:"weekly_anchor,omitempty" toml:"weekly_anchor,omitempty"`
// Caps5hTurns overrides the shipped default 5-hour-window turn cap. Zero
// means "use the shipped default for PlanTier".
Caps5hTurns int `json:"caps_5h_turns,omitempty" toml:"caps_5h_turns,omitempty"`
// CapsWeeklyTurns overrides the shipped default weekly turn cap. Zero
// means "use the shipped default for PlanTier".
CapsWeeklyTurns int `json:"caps_weekly_turns,omitempty" toml:"caps_weekly_turns,omitempty"`
}
ProfileLimits configures optional per-profile budget and headroom behavior. Zero values mean no explicit limit is configured.
type ProfileQuota ¶
type ProfileQuota struct {
Profile string `json:"profile"`
PlanTier string `json:"plan_tier"`
Window5h QuotaWindow `json:"window_5h"`
WindowWeekly QuotaWindow `json:"window_weekly"`
}
ProfileQuota is the per-profile response shape returned by GET /api/quota. Both windows are always present; their Cap field is zero when no plan tier is configured for the profile.
type QuotaWindow ¶
type QuotaWindow struct {
Used int `json:"used"`
Cap int `json:"cap"`
Pct float64 `json:"pct"`
ResetsAt time.Time `json:"resets_at"`
}
QuotaWindow describes turn usage within a single quota window (rolling 5h or weekly). Cap is zero when the owning profile has no PlanTier configured.
type RecommendationEvent ¶
type RecommendationEvent struct {
Profile string `json:"profile"`
Level RecommendationLevel `json:"level"`
Reason string `json:"reason"`
Suggested string `json:"suggested,omitempty"`
Quota5hPct float64 `json:"quota_5h_pct"`
QuotaWeeklyPct float64 `json:"quota_weekly_pct"`
Timestamp time.Time `json:"timestamp"`
}
RecommendationEvent is the payload emitted over /api/recommendations/live when the daemon detects a profile crossing a pressure threshold and a switch may be warranted. Suggested is empty when no sibling has more headroom than the crossed profile.
type RecommendationLevel ¶
type RecommendationLevel string
RecommendationLevel categorizes the urgency of a streamed pressure-driven recommendation. Thresholds (warn/soft/hard) are evaluator-defined.
const ( // RecommendationWarn signals a profile crossed the early-warning threshold. RecommendationWarn RecommendationLevel = "warn" // RecommendationSoft signals a profile crossed the soft-penalty threshold. RecommendationSoft RecommendationLevel = "soft" // RecommendationHard signals a profile is at or above its hard cap. RecommendationHard RecommendationLevel = "hard" )
type Scanner ¶
type Scanner interface {
// Scan walks all JSONL files under profile.ConfigDir/projects/ and emits
// Events on the returned channel. The channel is closed when scanning
// completes or when ctx is cancelled. Errors are logged but do not abort
// the scan; truly fatal errors return early via the error channel.
Scan(ctx context.Context, profile Profile) (<-chan Event, <-chan error)
}
Scanner walks a profile's JSONL files and emits parsed Events. Implementations are expected to use the Store's scan-cursor API (via the host package wiring) to avoid re-reading already-consumed bytes.
type SessionQuery ¶
type SessionQuery struct {
Profile string `json:"profile"`
Status string `json:"status"`
Since time.Time `json:"since"`
Limit int `json:"limit"`
}
SessionQuery filters session telemetry rows.
type SessionTelemetry ¶
type SessionTelemetry struct {
Profile string `json:"profile"`
Session string `json:"session"`
Transcript string `json:"transcript"`
CWD string `json:"cwd"`
Model string `json:"model"`
Source string `json:"source"`
Permission string `json:"permission"`
StartedAt time.Time `json:"started_at"`
EndedAt time.Time `json:"ended_at"`
LastSeenAt time.Time `json:"last_seen_at"`
Status string `json:"status"`
EndReason string `json:"end_reason"`
FailureError string `json:"failure_error"`
FailureDetails string `json:"failure_details"`
CompactCount int `json:"compact_count"`
}
SessionTelemetry is the current aggregate state for one Claude Code session.
type Shell ¶
type Shell int
Shell identifies a shell flavor for the purpose of emitting init scripts and `ccx use` shell-eval output.
func ParseShell ¶
ParseShell parses a shell name. Accepts "zsh", "bash", "fish", "pwsh", "powershell". Returns (ShellUnknown, false) for unknown input.
type ShellEmitter ¶
type ShellEmitter interface {
// EmitUseScript returns the script that, when eval'd by the user's shell,
// activates the given profile. The script sets CLAUDE_CONFIG_DIR and
// CCX_ACTIVE_PROFILE.
EmitUseScript(profile Profile, shell Shell) (string, error)
// EmitInitScript returns the rc-file snippet the user pastes into their
// shell config once. The snippet defines a wrapper function so `ccx use foo`
// works without `eval`.
EmitInitScript(shell Shell) (string, error)
}
ShellEmitter generates shell-specific snippets for `ccx use` and `ccx init`.
type Store ¶
type Store interface {
// Profile CRUD
SaveProfile(ctx context.Context, p Profile) error
GetProfile(ctx context.Context, name string) (Profile, error)
ListProfiles(ctx context.Context) ([]Profile, error)
DeleteProfile(ctx context.Context, name string) error
// Event ingestion. Events come from raw JSONL and do not carry profile
// context, so callers must pass the profile name explicitly.
InsertEvents(ctx context.Context, profileName string, events []Event) error
// Usage queries
QueryUsage(ctx context.Context, q UsageQuery) ([]UsageRow, error)
// Hook telemetry and session state
InsertHookEvent(ctx context.Context, profileName string, event HookEvent) error
UpsertSessionTelemetry(ctx context.Context, profileName string, event HookEvent) error
QuerySessions(ctx context.Context, q SessionQuery) ([]SessionTelemetry, error)
QueryRecentFailures(ctx context.Context, profileName string, since time.Time) ([]HookEvent, error)
SaveProfileHealth(ctx context.Context, health ProfileHealth) error
GetProfileHealth(ctx context.Context, profileName string) (ProfileHealth, error)
// Scan cursors (for incremental scanning)
GetCursor(ctx context.Context, profileName, filePath string) (offset int64, inode uint64, err error)
SetCursor(ctx context.Context, profileName, filePath string, offset int64, inode uint64) error
// Lifecycle
Migrate(ctx context.Context) error
Close() error
}
Store persists profiles and events. SQLite is the v0.1 implementation, but the interface is deliberately storage-agnostic.
type Usage ¶
type Usage struct {
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens"`
CacheCreateTokens int `json:"cache_create_tokens"`
}
Usage holds the token counts for a single Claude Code event. All fields are non-negative. Token counts come from the upstream JSONL `message.usage` block.
func (Usage) TotalTokens ¶
TotalTokens returns the sum of all four token counts. Useful for one-number usage displays, but cost calculations should use the per-bucket fields because each bucket has a different rate.
type UsageQuery ¶
UsageQuery filters and groups events for the Store.QueryUsage method. An empty Profile means "all profiles." An empty Project means "all projects."
type UsageRow ¶
type UsageRow struct {
Profile string `json:"profile"`
Project string `json:"project,omitempty"`
Model string `json:"model,omitempty"`
Day time.Time `json:"day"` // truncated to start of day in UTC
Usage Usage `json:"usage"`
SessionCount int `json:"session_count"`
EstimatedUSD float64 `json:"estimated_usd"` // populated by the caller after pricing lookup
}
UsageRow is one aggregated row returned by Store.QueryUsage. Aggregation granularity (per-profile, per-day, per-project) is determined by the concrete Store implementation.