prime

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: May 12, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// BudgetSourceSageox: tool overhead. Every word is a SageOx product
	// decision: instructions, commands table, attribution, code-search hint,
	// rule-promotion-guidance, ledger descriptor, session-context framing,
	// immediate-actions, user-notices, catalog headers/footers. SageOx is
	// judged on this bucket and only this bucket.
	BudgetSourceSageox = "sageox"

	// BudgetSourceTeam: team-authored or team-imported content delivered
	// from the team-context repo. AGENTS.md, CLAUDE.md, MEMORY.md, team
	// rules (always-tier bodies and indexed rows), coworker profiles,
	// team commands catalog rows, team docs catalog rows. SageOx delivers
	// it; the team controls its size.
	BudgetSourceTeam = "team"

	// BudgetSourceProject: content the repo (project) authored — the
	// project's own AGENTS.md surfaced via <project-guidance>. Distinct
	// from team content because it lives in the repo, not in team context.
	BudgetSourceProject = "project"

	// BudgetSourceUser: reserved for the upcoming per-user knowledge
	// bubble (a SageOx user's personal context that travels across teams
	// and repos). When the feature lands, tag those emit sites with this
	// constant; no other plumbing changes required.
	BudgetSourceUser = "user"
)

Knowledge-bubble source identifiers for ContextBudget.

Add a new constant here when introducing a new knowledge bubble (e.g., a per-user knowledge bubble, an organization-level bubble, a role-scoped bubble). Tag every emit site that injects content from that bubble with the new constant; the rest of the pipeline (heartbeat, daemon, status) flows the source through automatically — no schema migration required.

Source names are stable string keys serialized into JSON and surfaced to agents in the prime XML <context-budget> block. Use lowercase, no spaces.

Variables

SupportedAgents lists officially supported coding agents for MVP. Other agents may work but quality of guidance is not guaranteed.

Functions

func BuildAttributionTextSection

func BuildAttributionTextSection(attr config.ResolvedAttribution) string

BuildAttributionTextSection renders a human-readable attribution block for text output, only including lines for non-empty config fields.

func BuildHumanSummary

func BuildHumanSummary(output Output) string

BuildHumanSummary creates a human-readable summary for --review mode.

func CanonicalAgentType

func CanonicalAgentType(agentType string) string

CanonicalAgentType normalizes display names and legacy aliases to canonical agent type slugs.

func CodexLifecycleNotification

func CodexLifecycleNotification(agentType string) string

CodexLifecycleNotification returns Codex-specific workflow guidance.

func FormatAge

func FormatAge(d time.Duration) string

FormatAge returns a human-readable relative time string.

func GetAgentSupportNotice

func GetAgentSupportNotice(agentType string) string

GetAgentSupportNotice returns a notice for unsupported agents, or empty string for supported ones.

func IsAgentSupported

func IsAgentSupported(agentType string) bool

IsAgentSupported returns true if the agent is officially supported.

func KBSourceReachable added in v0.8.0

func KBSourceReachable(result kb.MergeResult) bool

KBSourceReachable reports whether the merge result contains at least one row sourced from /api/v1/kb. Used as the proxy for "kb feature flag is on for this caller and the API call succeeded" — when true and the personal bubble is still missing, EnsurePersonalKBPresent emits a warn.

func ShortenPath

func ShortenPath(path string) string

ShortenPath truncates a path for display, keeping the last 3 components.

func SortOtherTeamsByAge

func SortOtherTeamsByAge(entries []OtherTeamEntry)

SortOtherTeamsByAge sorts OtherTeamEntry slices by content age. Entries with a known age are sorted newest-first; entries without age go last.

func WithAttributionGuidance

func WithAttributionGuidance(content string, loggedIn bool, attr config.ResolvedAttribution) string

WithAttributionGuidance appends config-driven SageOx attribution guidance to content. Always-on blocks (not config-gated): real-time insight attribution, plan footer. Config-gated blocks: contribution score, commit attribution, PR attribution. If not logged in, includes a warning about potentially stale team context.

Types

type CapturePriorGuidance

type CapturePriorGuidance struct {
	Action       string   `json:"action"`
	Description  string   `json:"description"`
	Instructions []string `json:"instructions"`
	Example      string   `json:"example"`
}

CapturePriorGuidance provides instructions for capturing prior history

func BuildCapturePriorGuidance

func BuildCapturePriorGuidance(agentID string) *CapturePriorGuidance

BuildCapturePriorGuidance creates instructions for capturing prior history. The agent ID is embedded in the example command for easy copy-paste.

type ContextBudget added in v0.8.0

type ContextBudget struct {
	// BySource maps a source identifier (BudgetSource* constants) to the
	// estimated token count for that source. Sum across all entries
	// equals Total().
	BySource map[string]int `json:"by_source,omitempty"`
}

ContextBudget reports the estimated token cost of prime output split by who controls the content. SageOx is judged on what it directly emits (BudgetSourceSageox) separately from content authored by teams, projects, users, or any future knowledge bubble. A rolled-up single number conflates these and unfairly penalizes teams whose context is rich.

Estimates use the same len/4 heuristic as tokens.EstimateTokens — no tokenizer dependency at the prime emit site.

The map shape (rather than fixed fields) is intentional: future knowledge bubbles add entries by tagging emit sites with a new source constant. The IPC, daemon aggregation, and display layers preserve the map verbatim, so adding a bubble is a one-line code change.

func (*ContextBudget) Add added in v0.8.0

func (b *ContextBudget) Add(source string, tokens int)

Add increments the token count for a given source. Zero or negative tokens are ignored. Lazily initializes the map.

func (ContextBudget) Get added in v0.8.0

func (b ContextBudget) Get(source string) int

Get returns the token count for a given source, or 0 if absent.

func (ContextBudget) OrderedSources added in v0.8.0

func (b ContextBudget) OrderedSources() []string

OrderedSources returns source names in display order: well-known sources first (sageox, team, project, user — the order users intuit most), then any other sources alphabetically. Use for consistent output across runs as new bubbles are added.

func (ContextBudget) Total added in v0.8.0

func (b ContextBudget) Total() int

Total returns the sum of every source's tokens.

type Guidance

type Guidance struct {
	Hint     string          `json:"hint"`     // one-line instruction for the agent
	Commands []IntentCommand `json:"commands"` // ordered by query frequency
}

Guidance provides a top-level intent-to-command lookup for agents. Agents should consult this before exploring files or running ad-hoc discovery.

func BuildGuidance

func BuildGuidance(p GuidanceParams) *Guidance

BuildGuidance constructs state-aware command guidance for agent consumption. Only includes entries when the underlying resource is available.

Convention: Command fields are machine-parsed (no quoting). Prose fields (Hint, Important, CodeSearchTip, etc.) must single-quote command names (e.g. 'ox query') for scannability by both humans and agents.

type GuidanceParams

type GuidanceParams struct {
	AgentID          string
	RepoSlug         string           // "owner/repo" or directory name
	TeamCtx          *TeamContextInfo // nil if no team context
	Ledger           *LedgerInfo      // nil if no ledger
	CodeDBExists     bool             // true if code search index exists on disk
	MemoryEnabled    bool             // true if memory feature is enabled
	MurmuringEnabled bool             // true if murmuring: "auto" is set for this project
}

GuidanceParams holds pre-resolved I/O results needed by BuildGuidance.

type IntentCommand

type IntentCommand struct {
	Intent  string `json:"intent"`  // natural language phrases the user might say
	Command string `json:"command"` // exact ox CLI command to run
}

IntentCommand maps a user intent to the ox command that resolves it.

type KBInfo added in v0.8.0

type KBInfo struct {
	KBID       string `json:"kb_id,omitempty"`
	Type       string `json:"type"` // kb_type slug ("personal", "team", "repo", ...)
	Slug       string `json:"slug,omitempty"`
	Name       string `json:"name,omitempty"`
	Path       string `json:"path,omitempty"`        // canonical XDG path (paths.KBDir) or legacy local dir
	ViewerRole string `json:"viewer_role,omitempty"` // "owner", "member", "viewer"
	Tokens     int    `json:"tokens,omitempty"`      // estimated/observed tokens contributed by this bubble
	Legacy     bool   `json:"legacy,omitempty"`      // true for legacy team-context / ledger synthesized rows
	Hint       string `json:"hint,omitempty"`        // short, type-specific guidance for the agent
}

KBInfo is one row in Output.KB — the unified per-knowledge-bubble envelope emitted by `ox agent prime`. Built from the F3 three-source merger (internal/kb.Merger) so kb-API rows, legacy team contexts, and legacy ledger rows all flow through the same shape.

Per the kb plan: per-kind rendering in prime stays differentiated (the rich `team_context` mirror still carries the full team payload for one release). KBInfo itself is intentionally minimal — it identifies the bubble, where it lives on disk, the caller's role, and a short hint; payloads are emitted in their type-specific siblings until the legacy mirrors are removed.

func BuildKBInfos added in v0.8.0

func BuildKBInfos(result kb.MergeResult, tokensByType map[string]int64) []KBInfo

BuildKBInfos converts a merger result into the prime KB envelope.

tokensByType is consulted to populate KBInfo.Tokens — typically sourced from the daemon's per-kb-type cumulative counters (or the prime per-source budget for the freshly-emitted content). Tokens are split equally across bubbles of the same type when there are multiple; this matches the rolled- up shape of the heartbeat counter and avoids fabricating per-bubble numbers the daemon doesn't actually track today. Pass a nil map when no token data is available — Tokens will be left at zero.

Sort order matches `ox kb list`: type-priority, then non-legacy before legacy within a type, then slug. Stable so test snapshots don't churn.

func EnsurePersonalKBPresent added in v0.8.0

func EnsurePersonalKBPresent(kbInfos []KBInfo, kbSourceReachable bool) []KBInfo

EnsurePersonalKBPresent enforces the I2 invariant: the caller's personal bubble must always appear in the KB envelope. Returns the input unchanged today — the server-side EnsurePersonalKBMiddleware lazy-provisions the row during the kb-API call, so the merger result is expected to already contain it. This helper exists to log a defensive warning when the expectation is violated despite the kb-API source being reachable.

kbSourceReachable reports whether the kb-API source contributed at least one row (true) — the proxy for "kb-API call succeeded with the feature flag on". When false (kb API was unavailable / flag off / OX_KB_DISABLE), the absence of a personal bubble is silently tolerated because legacy world doesn't have personal bubbles.

type LedgerInfo

type LedgerInfo struct {
	Exists bool   `json:"exists"`
	Path   string `json:"path,omitempty"`
	Hint   string `json:"hint,omitempty"`
}

LedgerInfo represents discovered ledger state for prime output.

MIGRATION NOTE: New callers should consume Output.KB (typed entries with type=repo). LedgerInfo is the legacy mirror retained for one release while downstream consumers migrate; it will be removed once the kb envelope has shipped for one full release cycle.

type OtherTeamEntry

type OtherTeamEntry struct {
	Slug string `json:"slug"`          // kebab-case identifier for CLI arg
	Name string `json:"name"`          // display name
	Dir  string `json:"dir"`           // subdirectory under root
	Age  string `json:"age,omitempty"` // content freshness from git log
}

OtherTeamEntry is a compact reference to a non-primary team context.

type OtherTeams

type OtherTeams struct {
	Root  string           `json:"root"`  // base directory for all team contexts
	Hint  string           `json:"hint"`  // instruction for agent: only read when asked
	Teams []OtherTeamEntry `json:"teams"` // sorted by content freshness
}

OtherTeams lists non-primary team contexts available to the agent. Included in prime output so agents know what other teams exist. Agents MUST NOT read these unless the user explicitly asks by team name.

type Output

type Output struct {
	Status            string                     `json:"status"` // fresh, degraded, unavailable
	AgentID           string                     `json:"agent_id"`
	Guidance          *Guidance                  `json:"guidance,omitempty"` // intent-to-command lookup (scan first)
	SessionID         string                     `json:"session_id,omitempty"`
	AgentType         string                     `json:"agent_type,omitempty"`     // detected or specified agent type
	AgentSupported    bool                       `json:"agent_supported"`          // true if agent is officially supported
	SupportNotice     string                     `json:"support_notice,omitempty"` // warning for unsupported agents
	Content           string                     `json:"content"`
	Attribution       config.ResolvedAttribution `json:"attribution"`                 // commit/PR attribution for ox-guided work
	PlanFooter        string                     `json:"plan_footer,omitempty"`       // exact text for plan footer ("Guided by SageOx")
	ProjectGuidance   *ProjectGuidance           `json:"project_guidance,omitempty"`  // AGENTS.md content if found
	TeamInstructions  *TeamInstructions          `json:"team_instructions,omitempty"` // team AGENTS.md/CLAUDE.md content if found
	CapturePrior      *CapturePriorGuidance      `json:"capture_prior,omitempty"`     // instructions for capturing prior history
	Message           string                     `json:"message,omitempty"`
	TokenEstimate     int                        `json:"token_estimate,omitempty"`      // estimated token count
	ContentLength     int                        `json:"content_length,omitempty"`      // raw byte length
	Session           *SessionStatus             `json:"session,omitempty"`             // session recording status
	KB                []KBInfo                   `json:"kb,omitempty"`                  // unified knowledge-bubble envelope (kb-API + legacy team-contexts + legacy ledgers, deduped)
	Ledger            *LedgerInfo                `json:"ledger,omitempty"`              // legacy mirror; new callers should use KB (see LedgerInfo godoc)
	Important         string                     `json:"important"`                     // always-present disambiguation of knowledge sources
	TeamContext       *TeamContextInfo           `json:"team_context,omitempty"`        // legacy mirror; new callers should use KB (see TeamContextInfo godoc)
	TeamContextStatus string                     `json:"team_context_status,omitempty"` // "synced", "syncing", or empty; set when team_context is null but sync is expected
	OtherTeams        *OtherTeams                `json:"other_teams,omitempty"`         // non-primary teams (nil when only 1 team)
	UserNotification  string                     `json:"user_notification,omitempty"`   // pre-built status summary for agent to relay to user
	AgentTip          string                     `json:"agent_tip,omitempty"`           // contextual tip for the agent itself (not for the user)
	// Prime call tracking
	PrimeCallCount       int    `json:"prime_call_count,omitempty"`       // number of prime calls this session
	PrimeExcessiveNotice string `json:"prime_excessive_notice,omitempty"` // warning if prime called excessively
	// Cumulative context stats (from daemon, best-effort).
	// CumulativeContextTokens is the rolled-up total; the per-source
	// split lives in CumulativeContextTokensBySource (keyed by
	// BudgetSource* constants — extensible for future knowledge bubbles).
	CumulativeContextTokens         int64            `json:"cumulative_context_tokens,omitempty"`
	CumulativeContextTokensBySource map[string]int64 `json:"cumulative_context_tokens_by_source,omitempty"`
	CommandCount                    int              `json:"command_count,omitempty"` // number of ox commands that produced context

	// Doctor agent marker
	NeedsDoctorAgent bool   `json:"needs_doctor_agent,omitempty"` // true if .needs-doctor-agent marker exists
	DoctorHint       string `json:"doctor_hint,omitempty"`        // hint for agent to run ox agent doctor
	// Observation recording directive (behavioral, not just a tool reference)
	ObservationDirective string `json:"observation_directive,omitempty"` // proactive instruction to record observations via ox memory put
	// Murmur directive (behavioral — set when murmuring: "auto")
	MurmurDirective string `json:"murmur_directive,omitempty"` // proactive instruction to publish WIP status via ox murmur
	// Current user identity (so agents can distinguish self vs teammate)
	// Multiple aliases because sessions, murmurs, and discussions each use different name forms.
	// This is local-only context (not persisted to ledger), so full name is safe here.
	CurrentUserName    string   `json:"current_user_name,omitempty"`    // privacy-safe display name (e.g., "Ryan S.")
	CurrentUserAliases []string `json:"current_user_aliases,omitempty"` // all name forms the agent might encounter

	// Code search availability
	CodeDBAvailable bool   `json:"code_db_available,omitempty"` // true if code search index exists on disk
	CodeSearchTip   string `json:"code_search_tip,omitempty"`   // guidance on code search availability for this repo
	// Hook auto-install
	HooksInstalled     bool   `json:"hooks_installed,omitempty"`      // true if hooks were newly installed this prime
	HooksRestartNotice string `json:"hooks_restart_notice,omitempty"` // message for agent to relay to user about restarting
	// Version update advisory
	UpdateAvailable bool   `json:"update_available,omitempty"` // true if newer ox version exists
	LatestVersion   string `json:"latest_version,omitempty"`   // latest available version (without v prefix)
	UpdateHint      string `json:"update_hint,omitempty"`      // human-readable update instruction
	// Structured user notices (XML <user-notices> block)
	UserNotices []UserNotice `json:"user_notices,omitempty"` // notices that agents must relay to the user
	// Per-step timing instrumentation
	ElapsedMs int64            `json:"elapsed_ms,omitempty"` // total prime execution time
	Timing    map[string]int64 `json:"timing,omitempty"`     // per-phase timing (ms)
}

Output is the structured response for agent bootstrap (prime)

type ProjectGuidance

type ProjectGuidance struct {
	Source     string `json:"source"`                // path where AGENTS.md was found
	Content    string `json:"content"`               // raw content of AGENTS.md
	Size       int    `json:"size"`                  // byte size of content
	Tokens     int    `json:"tokens,omitempty"`      // estimated token count
	Skipped    bool   `json:"skipped,omitempty"`     // true if content was not injected
	SkipReason string `json:"skip_reason,omitempty"` // why content was skipped
}

ProjectGuidance represents parsed AGENTS.md content from the project

type SessionStatus

type SessionStatus struct {
	Recording        bool   `json:"recording"`
	File             string `json:"file,omitempty"`
	Mode             string `json:"mode,omitempty"`              // "infra" or "all"
	Source           string `json:"source,omitempty"`            // "repo", "team", "user", or "default"
	LedgerNeeded     bool   `json:"ledger_needed,omitempty"`     // true if ledger not yet provisioned by cloud
	AutoStarted      bool   `json:"auto_started,omitempty"`      // true if started by ox agent prime
	UserNotification string `json:"user_notification,omitempty"` // message for agent to relay to user
	SessionURL       string `json:"session_url,omitempty"`       // web URL to view this session recording
}

SessionStatus represents the state of session recording

type TeamContextInfo

type TeamContextInfo struct {
	TeamID     string   `json:"team_id"`
	TeamName   string   `json:"team_name,omitempty"`
	IsRepoTeam bool     `json:"is_repo_team"`
	Path       string   `json:"path"`
	Agents     []string `json:"agents,omitempty"`     // discovered agent names
	Escalation string   `json:"escalation,omitempty"` // path to human escalation roster if exists

	// Coworker customizations from coworkers/
	CoworkerInstructions  *TeamCoworkerInstructions `json:"coworker_instructions,omitempty"`
	Coworkers             []claude.Agent            `json:"coworkers,omitempty"`
	CoworkerCommands      []claude.Command          `json:"coworker_commands,omitempty"`
	AgentsIndexPath       string                    `json:"agents_index_path,omitempty"`        // path to agents/index.md if exists
	AgentsAgentsMDContent string                    `json:"agents_agents_md_content,omitempty"` // coworkers/agents/AGENTS.md content (first 200 lines)
	CoworkerHint          string                    `json:"coworker_hint,omitempty"`            // hint for agents about available coworkers

	// Agent context - distilled knowledge for AI agents
	HasAgentContext     bool   `json:"has_agent_context,omitempty"`      // true if agent-context/distilled-discussions.md exists
	AgentContextPath    string `json:"agent_context_path,omitempty"`     // full path to distilled-discussions.md
	AgentContextRelPath string `json:"agent_context_rel_path,omitempty"` // relative path within team context
	AgentContextHash    string `json:"agent_context_hash,omitempty"`     // content hash for deduplication
	ReadCommand         string `json:"read_command,omitempty"`           // command to read team discussions

	// Team docs catalog — progressive disclosure for docs/ files.
	// Listed in prime output so agents know what's available and when to read each doc.
	// Content is NOT inlined — agents read on demand via file path.
	TeamDocs []teamdocs.TeamDoc `json:"team_docs,omitempty"`

	// Team rules — modular AI-coworker rules under agents/rules/**/*.md
	// (with coworkers/rules/ as legacy fallback). The team-scope cousin of
	// Claude's .claude/rules/<topic>.md. Filtered by repos:, audience:, and
	// status: at discovery time. visibility: always rules carry their body
	// inlined for prime emission; visibility: indexed rules carry only
	// metadata and are read on demand by the agent.
	TeamRules []teamdocs.TeamRule `json:"team_rules,omitempty"`

	// v4 Team Memory
	MemoryContent        string   `json:"memory_content,omitempty"`         // full MEMORY.md content (always inlined)
	SoulHint             string   `json:"soul_hint,omitempty"`              // path to SOUL.md (reference, not inlined)
	TeamHint             string   `json:"team_hint,omitempty"`              // path to TEAM.md (reference, not inlined)
	MemoryDaily          []string `json:"memory_daily,omitempty"`           // available daily summary files
	MemoryWeekly         []string `json:"memory_weekly,omitempty"`          // available weekly summary files
	MemoryMonthly        []string `json:"memory_monthly,omitempty"`         // available monthly summary files
	ObservationGuideHint string   `json:"observation_guide_hint,omitempty"` // path to memory/GUIDE.md (read when needed)

	// sync health
	Stale      bool   `json:"stale,omitempty"`       // true if last sync exceeds staleness threshold
	StaleSince string `json:"stale_since,omitempty"` // human-readable duration since last sync
}

TeamContextInfo represents discovered team context for prime output.

MIGRATION NOTE: New callers should consume Output.KB (typed entries with type=team). TeamContextInfo is the legacy mirror retained for one release while downstream consumers migrate; the full payload (AGENTS.md, team_docs, team_rules, soul/team hints, memory) continues to flow here for now because KBInfo is the minimal-envelope contract — per-type rich content moves into KB entries in a follow-up bead.

type TeamCoworkerInstructions

type TeamCoworkerInstructions struct {
	ClaudeMDPath string `json:"claude_md_path,omitempty"` // coworkers/CLAUDE.md
	AgentsMDPath string `json:"agents_md_path,omitempty"` // coworkers/AGENTS.md
	HasClaudeMD  bool   `json:"has_claude_md"`
	HasAgentsMD  bool   `json:"has_agents_md"`
}

TeamCoworkerInstructions holds paths to team instruction files. These files should be read immediately for team-specific configuration.

type TeamInstructions

type TeamInstructions struct {
	Source   string   `json:"source"`              // description of which files contributed
	Content  string   `json:"content"`             // concatenated content of all found files
	TeamName string   `json:"team_name,omitempty"` // team display name
	Size     int      `json:"size"`                // byte size of combined content
	Tokens   int      `json:"tokens,omitempty"`    // estimated token count
	Files    []string `json:"files"`               // which files contributed: ["AGENTS.md", "CLAUDE.md"]
}

TeamInstructions represents team-level instruction files (AGENTS.md / CLAUDE.md) from the root of the team context repo, emitted directly into agent context.

type UserNotice

type UserNotice struct {
	Type    string `json:"type"` // "upgrade", "restart", "support"
	Message string `json:"message"`
}

UserNotice is a notice that agents must relay to the user (upgrade, restart, support).

Jump to

Keyboard shortcuts

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