Documentation
¶
Overview ¶
Package config loads Seamless configuration from a single YAML file with SEAMLESS_* environment overrides. Env wins over file; file wins over defaults.
Deliberately halved from Seam v1: no JWT/auth/multi-user config, no ChromaDB. Auth is a single static bearer key; vectors live in SQLite.
Index ¶
Constants ¶
const ( ProviderOpenAI = "openai" ProviderOllama = "ollama" ProviderAnthropic = "anthropic" )
LLM provider identifiers.
const ( // MaxEmbeddingDimensions bounds a configured/requested vector size. Current // providers are in the low thousands; 65,536 permits future models while // preventing a typo from driving unbounded vector allocations downstream. MaxEmbeddingDimensions = 65_536 )
Variables ¶
var UtilityModes = []string{"auto", "on", "off"}
UtilityModes are the accepted briefing.utility_mode values.
Functions ¶
This section is empty.
Types ¶
type Anthropic ¶
type Anthropic struct {
APIKey string `yaml:"api_key"`
BaseURL string `yaml:"base_url"`
ChatModel string `yaml:"chat_model"`
}
Anthropic is a chat-only provider (no embeddings API).
type Briefing ¶
type Briefing struct {
// ConstraintMaxFull is how many top-ranked constraints render as full
// "- name: description" bullets in the Constraints section; the rest
// collapse into one compact "+N more, equally binding" line that still
// names every one. 0 disables the tiering (every constraint renders full,
// the legacy behavior).
ConstraintMaxFull int `yaml:"constraint_max_full" json:"constraintMaxFull"`
// ConventionMaxFull is how many top-ranked conventions render as full
// bullets in the budget-competing Conventions section; the rest stay
// behind the section's count line ("recall kind=convention"). Starred
// conventions always render full past the cap. 0 disables the tiering
// (every convention renders full), matching ConstraintMaxFull semantics.
ConventionMaxFull int `yaml:"convention_max_full" json:"conventionMaxFull"`
// MemoryMaxAgeDays drops memory-index lines not updated within this many
// days. 0 = no recency filter. Constraints and stages are exempt.
MemoryMaxAgeDays int `yaml:"memory_max_age_days" json:"memoryMaxAgeDays"`
// MemoryMaxItems caps the memory-index line count before budget packing.
// 0 = budget-only (no cap).
MemoryMaxItems int `yaml:"memory_max_items" json:"memoryMaxItems"`
// FindingsCount is how many recent findings to inject. 0 hides the section.
FindingsCount int `yaml:"findings_count" json:"findingsCount"`
// FindingsMaxAgeDays drops findings older than this many days. 0 = no filter.
FindingsMaxAgeDays int `yaml:"findings_max_age_days" json:"findingsMaxAgeDays"`
// ReadyTasksShown is how many ready-task titles the ready line names.
// 0 hides the line entirely.
ReadyTasksShown int `yaml:"ready_tasks_shown" json:"readyTasksShown"`
// PendingPlanMaxDays is how far back captured-but-unapproved Claude Code
// plans earn "awaiting approval" lines. 0 = no age cutoff.
PendingPlanMaxDays int `yaml:"pending_plan_max_days" json:"pendingPlanMaxDays"`
// StageUnknownMaxAgeDays is the grace window (days since last update) a
// stage memory stays pinned when its Status header is missing or not a live
// gate (open/in_progress/blocked). Past it the stage leaves the briefing --
// recall still finds it. 0 = pin forever (the historical behavior).
StageUnknownMaxAgeDays int `yaml:"stage_unknown_max_age_days" json:"stageUnknownMaxAgeDays"`
// HardCapMultiplier times budgets.max_briefing_tokens is the absolute
// truncation ceiling. 0 falls back to 2.
HardCapMultiplier int `yaml:"hard_cap_multiplier" json:"hardCapMultiplier"`
// IncludeParentMemories folds a shared parent project's active memories
// into a child project's briefing (the historical automatic behavior).
IncludeParentMemories bool `yaml:"include_parent_memories" json:"includeParentMemories"`
// SiblingFindingsCount is how many recent findings from family-member
// projects to inject. 0 hides the section.
SiblingFindingsCount int `yaml:"sibling_findings_count" json:"siblingFindingsCount"`
// IncludeSiblingMemories folds family-member projects' active memories
// (constraints and stages excluded) into the briefing as a low-priority
// "Sibling memories" section. Off by default to avoid crowding.
IncludeSiblingMemories bool `yaml:"include_sibling_memories" json:"includeSiblingMemories"`
// UtilityWeight is utility's share of the briefing memory-index sort key:
// (1-w)*recency + w*utility, both half-life-decayed to [0,1). 0 = pure
// recency (the legacy order); constraints, stages, and favorites are pinned
// regardless. Applies only where utility ranking is active (UtilityMode).
UtilityWeight float64 `yaml:"utility_weight" json:"utilityWeight"`
// UtilityMode gates the briefing's utility re-ordering: "auto" (default)
// activates per project once the gardener's readiness latch trips, "on"
// activates everywhere immediately, "off" disables it everywhere. The
// bounded recall/prompt-recall boosts are not gated by this.
UtilityMode string `yaml:"utility_mode" json:"utilityMode"`
}
Briefing tunes what the SessionStart briefing auto-injects: how many items each section carries, recency filters, related-project cross-over, and the hard-cap multiplier. Defaults reproduce the historical hardcoded behavior. The JSON tags back the console's runtime override row (see store.BriefingConfig), which layers on top of this file/env base.
The never-drop invariant: constraints and active-plan rollups are exempt from every filter here, and so is a pinned stage while its Status header marks a live gate -- recency and count filters apply only to the memory index, findings, and sibling sections. ConstraintMaxFull shapes how constraints render (full vs compact), never whether they appear. A stage with no live gate holds its pin only through the StageUnknownMaxAgeDays grace window.
type Budgets ¶
type Budgets struct {
MaxBriefingTokens int `yaml:"max_briefing_tokens"`
RecallBudgetTokens int `yaml:"recall_budget_tokens"`
// ToolEventMaxChars caps each captured field (tool-call args value, result,
// hook prompt, session findings) of an Interactions transport event at this
// many runes. 0 = unlimited (the default): content is stored in full, and the
// tool-event retention prune -- not truncation -- is the growth control.
ToolEventMaxChars int `yaml:"tool_event_max_chars"`
}
Budgets holds token budgets for retrieval.
type Capture ¶
type Capture struct {
// AllowedPorts are the only destination ports capture_url may dial, enforced
// on the initial URL and on every redirect hop. Empty is deliberately NOT
// "any port": an unset key, an explicit `allowed_ports: []`, or an empty env
// override all fall back to the 80/443 default, so the SSRF port guard cannot
// be switched off by omission. Ports outside 1-65535 are rejected by Validate.
AllowedPorts []int `yaml:"allowed_ports"`
}
Capture configures the SSRF-guarded URL fetch behind the capture_url tool. Unrelated to PlanCapture, which is about Claude Code plan mode.
type Config ¶
type Config struct {
// Addr is the HTTP bind address (host:port). Defaults to 127.0.0.1:8081.
Addr string `yaml:"addr"`
// DataDir holds the SQLite database and markdown trees. A leading ~ expands.
DataDir string `yaml:"data_dir"`
MCP MCP `yaml:"mcp"`
Budgets Budgets `yaml:"budgets"`
Briefing Briefing `yaml:"briefing"`
Search Search `yaml:"search"`
LLM LLM `yaml:"llm"`
Gardener Gardener `yaml:"gardener"`
Capture Capture `yaml:"capture"`
PlanCapture PlanCapture `yaml:"plan_capture"`
// contains filtered or unexported fields
}
Config is the fully-resolved Seamless configuration.
func Defaults ¶
func Defaults() Config
Defaults returns the built-in configuration. File and env values are layered on top of these, so absent keys keep their default.
func EnsureAPIKey ¶
EnsureAPIKey makes a true first run self-configuring: when no config file exists anywhere in the search order and SEAMLESS_MCP_API_KEY is absent from the environment, it generates a bearer key, writes it to ~/.config/seamless/seamless.yaml (0600), and returns the updated config plus the path it wrote. In every other case it changes nothing and returns "": a key already set, an owner-authored config file (even one with an empty key), or an env override (even set-but-empty) are never edited on the owner's behalf -- the existing empty-key warning paths stay in charge there.
func Load ¶
Load resolves configuration from the first config file found in the search order ($SEAMLESS_CONFIG, ~/.config/seamless/seamless.yaml, ./seamless.yaml), then applies SEAMLESS_* environment overrides and expands paths.
func LoadFrom ¶
LoadFrom loads defaults, overlays the YAML file at path (if non-empty), applies environment overrides, and expands paths. An empty path uses defaults + env.
func (Config) SourcePath ¶
SourcePath returns the config file that was loaded, or "" if defaults+env only.
type Gardener ¶
type Gardener struct {
Enabled bool `yaml:"enabled"`
// IntervalMinutes is the ticker period between full gardener passes.
IntervalMinutes int `yaml:"interval_minutes"`
// DedupThreshold is the cosine-similarity floor at/above which two active
// memories are proposed for a merge.
DedupThreshold float64 `yaml:"dedup_threshold"`
// StalenessDays is the no-activity age (no update, injection, or read) beyond
// which an active memory is proposed for archiving.
StalenessDays int `yaml:"staleness_days"`
// DigestDays is the trailing window of completed sessions rolled into a
// monthly digest proposal.
DigestDays int `yaml:"digest_days"`
// ToolEventRetentionDays is the age beyond which transport-level Interactions
// events (tool.call, hook.prompt) are pruned by the gardener. 0 disables the
// prune; domain events are never pruned regardless.
ToolEventRetentionDays int `yaml:"tool_event_retention_days"`
// StalePlanDays is the age beyond which a captured, never-approved Claude
// Code plan (plan-status draft/presented) is proposed for abandonment.
// 0 disables the pass.
StalePlanDays int `yaml:"stale_plan_days"`
// StaleStageDays is the age (days since last update) beyond which a stage
// memory that is not a live gate -- Status done, missing, or unrecognized --
// is proposed for archiving. Live gates (open/in_progress/blocked) are never
// proposed regardless of age. 0 disables the pass.
StaleStageDays int `yaml:"stale_stage_days"`
// SessionIdleMinutes is the no-activity age beyond which an active session
// is considered dead: the gardener reaper expires it and the console stops
// counting it as live. It is the single liveness threshold shared by both,
// so the reaper cutoff and the console "live" window never drift.
// Must be positive. The fully resolved config already supplies 45 when the
// key is absent, so zero is an explicit invalid value rather than a second,
// silent spelling of the default.
SessionIdleMinutes int `yaml:"session_idle_minutes"`
}
Gardener configures the propose-only maintenance passes and their ticker.
type LLM ¶
type LLM struct {
Provider string `yaml:"provider"`
OpenAI OpenAI `yaml:"openai"`
Ollama Ollama `yaml:"ollama"`
Anthropic Anthropic `yaml:"anthropic"`
}
LLM configures chat (digests) and embeddings. OpenAI is the default provider.
func (LLM) EmbeddingModel ¶ added in v0.4.1
EmbeddingModel returns the embedding model the configured provider would use, or "" for a provider with no embeddings API (Anthropic) or an unknown one. It reports configuration, not capability: the provider may still lack the credential to actually serve it.
type MCP ¶
type MCP struct {
APIKey string `yaml:"api_key"`
}
MCP holds the static bearer key guarding /api/mcp and the console.
type Ollama ¶
type Ollama struct {
BaseURL string `yaml:"base_url"`
ChatModel string `yaml:"chat_model"`
EmbeddingModel string `yaml:"embedding_model"`
EmbeddingDims int `yaml:"embedding_dims"`
}
Ollama is the local provider (chat + embeddings).
type OpenAI ¶
type OpenAI struct {
APIKey string `yaml:"api_key"`
BaseURL string `yaml:"base_url"`
ChatModel string `yaml:"chat_model"`
EmbeddingModel string `yaml:"embedding_model"`
// EmbeddingDims is the model's native dimensionality; 0 = auto-detect from
// the first embedding response.
EmbeddingDims int `yaml:"embedding_dims"`
}
OpenAI is the first-class provider (chat + embeddings).
type PlanCapture ¶
type PlanCapture struct {
// Enabled turns the plan-capture hook endpoints into no-ops when false.
Enabled bool `yaml:"enabled"`
// AutoTask creates a tracking task ("Implement plan: ...") when a plan is
// approved, composing it into the plan via plan_slug.
AutoTask bool `yaml:"auto_task"`
// InjectRelated returns related prior plans/memories as additionalContext on
// a session's first captured plan iteration.
InjectRelated bool `yaml:"inject_related"`
}
PlanCapture configures capturing Claude Code plan-mode iterations and planning subagents into notes via the PostToolUse/SubagentStop hooks.
type Search ¶ added in v0.3.9
type Search struct {
// SemanticFloor is the minimum cosine similarity a semantic-only hit needs
// to appear in search results; hits the lexical leg also matched are exempt.
// Without it the cosine leg is pure nearest-neighbor -- there is always a
// "nearest" item, so any query fills the page. 0 disables the floor. Useful
// values depend on the embedding model; the default suits OpenAI
// text-embedding-3-*.
SemanticFloor float64 `yaml:"semantic_floor"`
}
Search tunes the human-facing console search (retrieve.Search). Agent-facing recall is deliberately not covered: an agent can judge a weak hit for itself, but an observer reads "20 results" as 20 matches.