config

package
v0.3.1 Latest Latest
Warning

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

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

Documentation

Overview

Package config loads ~/.yottacode/config.toml — the single tunable surface for context-window watermarks, retrieval, and provider profiles.

The file is parsed with github.com/BurntSushi/toml so we get arrays of tables ([[providers]], [[providers.models]]) without writing a parser. Unknown keys and unknown sections are rejected at load time so a typo like `enbled = ture` doesn't silently pass — we walk the metadata's Undecoded() set after decoding.

API keys NEVER live in this file. Each [[providers]] block names an environment variable via api_key_env; the actual key is provided either via that OS env var or via ~/.yottacode/.env or <repo>/.yottacode/.env. Inline api_key fields are refused at load.

Index

Constants

View Source
const (
	RouterModeOff    = "off"
	RouterModeManual = "manual"
	RouterModeAuto   = "auto"
)

RouterMode values for RouterConfig.Mode.

View Source
const DefaultCheckpointRetentionDays = 30

DefaultCheckpointRetentionDays mirrors Claude Code's 30-day TTL — long enough to step back through a few days of work, short enough that blob storage doesn't grow without bound. Override per-host via `[checkpoints] retention_days = N` in config.toml.

View Source
const DefaultRouterHealthFailureThreshold = 3

DefaultRouterHealthFailureThreshold is the number of failures within the window that mark a candidate as degraded. Set to 0 in the config file to disable observation entirely.

View Source
const DefaultRouterHealthWindowSeconds = 60

DefaultRouterHealthWindowSeconds is the sliding-window length the router uses when the user enables routing without specifying health_window_seconds.

View Source
const DefaultsTOML = `` /* 8514-byte string literal not displayed */

DefaultsTOML is the documented default file written by EnsureDefault.

Variables

View Source
var ValidKinds = []string{"anthropic", "openai", "openai-auth", "copilot", "openai-compatible", "ollama", "gemini", "xai"}

ValidKinds is the whitelist for Provider.Kind.

View Source
var ValidPolicies = []string{"fallback-chain", "cheap-first"}

ValidPolicies is the whitelist for RouterConfig.Policy. Empty is treated as the default (fallback-chain) at construction time.

ValidRouterModes is the whitelist for RouterConfig.Mode. Empty is treated as the default ("off") at load time.

View Source
var ValidStrategies = []string{"keyword", "bm25", "semantic", "auto"}

ValidStrategies is the whitelist for RetrievalConfig.Strategy. Empty is coerced to the default ("auto") at load time.

View Source
var ValidTiers = []string{"cheap", "balanced", "expensive"}

ValidTiers is the whitelist for Model.Tier. Empty is also accepted (treated as unspecified).

Functions

func DefaultPath

func DefaultPath() (string, error)

DefaultPath returns ~/.yottacode/config.toml.

func EnsureDefault

func EnsureDefault(path string) (string, error)

EnsureDefault writes the documented default config.toml at path if none exists. Returns the resolved path either way so callers can show it to the user. Idempotent — never overwrites an existing file.

func MCPNameValid added in v0.3.0

func MCPNameValid(name string) bool

MCPNameValid reports whether name matches the MCP server name constraint (lowercase letters, digits, hyphens, underscores; must start with a letter).

func ParseCandidate

func ParseCandidate(raw string) (provider, model string, err error)

ParseCandidate splits a "provider" or "provider:model" router candidate string. Empty model means "use the provider's default". Whitespace is trimmed; an empty input is rejected.

func Render

func Render(cfg Config) string

Render produces the canonical TOML body for a Config. Stable section order: tunables block (context / retrieval) first via the BurntSushi encoder, then human-edited sections (active, providers, router) hand-rendered with explicit alignment so diffs read top-to-bottom. The encoder's emit order isn't guaranteed across releases, which is why we don't lean on it for the human-edited bits.

Used both by wizard.Apply (for fresh writes and merges) and by the TUI's /provider add / /model picker save paths so a single rendering function owns the file shape. Callers that need atomic persistence should pair this with Save.

func Save

func Save(cfg Config, path string) error

Save writes cfg to path atomically (tmp + rename). Creates parent dirs as needed. The file mode is 0644 — keys live in .env, never here, so 0600 isn't required. Used by every TUI write path (/provider add / /provider remove / /model picker confirm).

func Validate

func Validate(cfg Config) error

Validate enforces ranges and consistency across the loaded config. Returns a clean error rather than silently clamping — clamping means the user's intent is lost.

Types

type Active

type Active struct {
	Provider     string `toml:"provider"`
	Model        string `toml:"model"`
	DefaultModel string `toml:"default_model"`
}

Active selects which configured provider + model is the session default. All fields are optional — if Provider is empty the user is expected to pass --model / --base-url / --provider via flag or env.

Two TOML keys spell the active model: the new canonical `default_model` and the legacy `model`. Both populate the same in-memory value: after Load(), Model and DefaultModel are kept in sync — whichever the file set (with default_model winning if both appear) is mirrored into the other so existing readers (cfg.Active.Model) keep working unchanged.

type CheckpointsConfig added in v0.2.0

type CheckpointsConfig struct {
	RetentionDays int `toml:"retention_days"`
}

CheckpointsConfig tunes the per-prompt file/conversation snapshot store behind /checkpoints + Esc Esc. RetentionDays<=0 falls through to DefaultCheckpointRetentionDays so the on-disk default doesn't require users to write a [checkpoints] block.

type Config

type Config struct {
	Context     ContextConfig     `toml:"context"`
	Retrieval   RetrievalConfig   `toml:"retrieval"`
	Memory      MemoryConfig      `toml:"memory"`
	Router      RouterConfig      `toml:"router"`
	Active      Active            `toml:"active"`
	Providers   []Provider        `toml:"providers"`
	Checkpoints CheckpointsConfig `toml:"checkpoints"`
	// MCPServers lists Model Context Protocol servers launched at
	// session start. Each entry becomes a stdio subprocess whose
	// advertised tools register into the agent tool registry under
	// the mcp/<name>/<tool> namespace. v1 supports stdio transport
	// only; absence of a `transport` field means adding HTTP/SSE
	// later is non-breaking.
	MCPServers []MCPServer `toml:"mcp_servers"`
	Theme      ThemeConfig `toml:"theme"`
	// Experimental gates non-default features behind named opt-ins.
	// Mirrors the --experimental CLI flag and the
	// $YOTTACODE_EXPERIMENTAL env var. Each entry is a feature name
	// from internal/experimental; values must be `true` to enable.
	// Unrecognized names load without error and emit a startup
	// warning so graduated/removed feature names don't break old
	// configs.
	Experimental map[string]bool `toml:"experimental"`
	// Skills carries persistent Agent Skills preferences — currently
	// just the default-on list seeded into SkillTool.SetEnabled at
	// session start. Absent block keeps the default-off behavior so
	// users without preferences see today's small-prompt experience.
	Skills SkillsConfig `toml:"skills"`
}

Config bundles every tunable yottacode reads from disk. Sub-structs map 1:1 to TOML sections so the file shape mirrors the Go shape.

func Default

func Default() Config

func Load

func Load(path string) (Config, error)

Load reads config.toml at the given path, returning the parsed config merged onto Default(). A missing file is not an error — defaults are returned. Invalid values (out-of-range, malformed, unknown sections) ARE an error.

func LoadDefault

func LoadDefault() (Config, error)

LoadDefault loads the file at ~/.yottacode/config.toml.

func (Config) ContextWindowOverride added in v0.3.0

func (c Config) ContextWindowOverride(model string) int

ContextWindowOverride returns the user-configured context_window for the given model, or 0 when no provider entry sets one. The active provider's entry wins when the same model name is listed under more than one provider (e.g. two proxies fronting the same model). 0 means "no override" — the caller then falls back to the model-tag table and default_window via contextwindow.EffectiveWindow.

This is the read side of the per-model window override: the wizard's registration probe writes Model.ContextWindow (captured from the provider's list-models endpoint), and this surfaces it to the window math so the status bar and auto-summarize threshold honor the real, provider-reported window instead of a stale built-in guess.

func (*Config) FindProvider

func (c *Config) FindProvider(name string) *Provider

FindProvider returns a pointer to the provider with the given name, or nil. Pointer receiver lets callers mutate the slice element if they need to (e.g. /provider use updating Active.Model on switch).

func (Config) ProviderKindForModel added in v0.3.0

func (c Config) ProviderKindForModel(model string) string

ProviderKindForModel returns the Kind of the provider entry that serves the given model: the active provider when it explicitly names the model (models list or default_model), then any provider that does, then — for models config never enumerates, like openai-auth's scanned set or ollama's local tags — the active provider's Kind. Empty only when nothing matches and no provider is active.

Keying per-backend facts on Kind is what keeps namesake models separated: gpt-5.5 served through "openai-auth" must not inherit numbers from gpt-5.5 served through "openai" (see catalog.ResolveWindowForProvider).

func (*Config) ResolveCandidates

func (c *Config) ResolveCandidates() ([]ResolvedCandidate, error)

ResolveCandidates parses each router.candidates entry and resolves it against the provider catalog. Validate has already been called by Load, so the caller knows every candidate refers to a real provider and a real model — but ResolveCandidates is callable independently for tests and for /router introspection.

func (*Config) ResolveRouterModels added in v0.3.0

func (c *Config) ResolveRouterModels() (fast, smart ResolvedCandidate, err error)

ResolveRouterModels resolves the fast and smart models named in the [router] block. Callable only when routing is enabled (Mode != off); Validate has already confirmed both strings resolve.

type ContextConfig

type ContextConfig struct {
	WarnThreshold float64 `toml:"warn_threshold"`
	AutoThreshold float64 `toml:"auto_threshold"`
	DefaultWindow int     `toml:"default_window"`
}

ContextConfig governs context-window watermark behavior.

type MCPServer added in v0.3.0

type MCPServer struct {
	// Name is the unique identifier used in tool namespacing and in
	// the /mcp slash command. Must match mcpNameRE.
	Name string `toml:"name"`

	// Command is the executable that runs the MCP server. Resolved
	// via exec.LookPath at session start.
	Command string `toml:"command"`

	// Args are passed to Command verbatim. Typical shape:
	//   command = "npx"
	//   args    = ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
	Args []string `toml:"args"`

	// Env supplies additional environment variables to the subprocess
	// on top of yottacode's inherited environment. Values may use
	// $VAR substitution from yottacode's process env, resolved at
	// spawn time. Unresolved $VARs surface a startup warning but
	// don't fail load.
	Env map[string]string `toml:"env"`

	// Disabled skips this entry at session start without removing it
	// from the config file. Useful for temporarily quieting a
	// misbehaving server.
	Disabled bool `toml:"disabled"`
}

MCPServer describes one Model Context Protocol server launched as a stdio subprocess at session start. The MCP client connects over stdin/stdout, lists the server's tools, and registers each tool in the agent tool registry under mcp/<Name>/<tool>.

The exec.LookPath / spawn / initialize-handshake is performed at session start by internal/mcp.Manager — config.Validate only checks structural well-formedness. Runtime failures (missing binary, init timeout, subprocess crash) are surfaced via /mcp and the next tool invocation rather than refusing the entire session.

type MemoryConfig added in v0.3.0

type MemoryConfig struct {
	// FinalTurnOnQuit, when true, runs one last agent turn on a
	// graceful exit (/quit or Ctrl+D while idle) prompting the model
	// to persist durable learnings via memory_save before the session
	// context is gone. The turn renders in the transcript like any
	// other and is skippable (Ctrl+C / Esc cancels it and quits).
	// Ctrl+C as the quit gesture always exits immediately without the
	// final turn. Default true; set false to make every exit immediate.
	FinalTurnOnQuit bool `toml:"final_turn_on_quit"`
}

MemoryConfig governs proactive agent-managed memory behavior beyond retrieval (which has its own [retrieval] section).

type Model

type Model struct {
	// Name is the model identifier passed to the API (e.g.
	// "claude-sonnet-4-6"). Required.
	Name string `toml:"name"`

	// Tier is a coarse cost/capability bucket used by the future
	// auto-router. Empty means unspecified. Validated at load time
	// against the whitelist below.
	Tier string `toml:"tier"`

	// ContextWindow overrides yottacode's built-in context-window
	// table for this model. 0 means use the built-in fallback.
	ContextWindow int `toml:"context_window"`
}

Model is one entry in a provider's catalog.

type Provider

type Provider struct {
	// Name is the user-chosen label for this configuration, unique
	// within the file. Used by /provider use <name>.
	Name string `toml:"name"`

	// Kind selects the adapter family. One of:
	//
	//   anthropic           — native Messages API (claude-*)
	//   openai              — OpenAI's own endpoints (chat completions
	//                         + responses; auto-routes for o-series and
	//                         gpt-5*)
	//   openai-compatible   — anything that speaks /v1/chat/completions
	//                         (vLLM, Llama Stack, OpenRouter, Together,
	//                         NVIDIA NIM, Groq, …)
	//   xai                 — xAI's OpenAI-compatible Grok endpoint
	//   ollama              — Ollama's local server (OpenAI-shim variant)
	Kind string `toml:"kind"`

	// BaseURL is the HTTPS endpoint for the API. For Anthropic this is
	// typically https://api.anthropic.com; for OpenAI-compatible
	// endpoints include the /v1 suffix where the upstream expects it.
	BaseURL string `toml:"base_url"`

	// APIKeyEnv is the name of the OS environment variable that holds
	// the bearer token. Empty for local providers like Ollama. Looked
	// up at adapter-construction time, NOT stored here.
	APIKeyEnv string `toml:"api_key_env"`

	// DefaultModel is the model name to adopt when /provider use
	// switches to this provider. Must appear in Models when set.
	DefaultModel string `toml:"default_model"`

	// Models is the catalog of models available through this provider.
	// Used by /model list and as the source of truth for the future
	// auto-router.
	Models []Model `toml:"models"`

	// APIKey is reserved as a tripwire: declaring it inline produces a
	// load-time error that points the user at .env. We don't read its
	// value — declaring it at all is the failure.
	APIKey string `toml:"api_key"`
}

Provider describes one upstream model vendor configuration. Two provider entries can share the same Kind (e.g. OpenRouter and Together both Kind = "openai-compatible") but differ in name + base_url + models.

type ResolvedCandidate

type ResolvedCandidate struct {
	Provider Provider
	Model    string
	Tier     string
}

ResolvedCandidate is the fully-resolved view of one router.candidates entry: provider profile + concrete model + tier (looked up from providers.models). Returned by ResolveCandidates so callers (cli.BuildRouter) don't repeat the lookup.

type RetrievalConfig

type RetrievalConfig struct {
	Enabled        bool    `toml:"enabled"`
	TopK           int     `toml:"top_k"`
	MaxBytes       int     `toml:"max_bytes"`
	MinScore       float64 `toml:"min_score"`
	Strategy       string  `toml:"strategy"`
	EmbeddingModel string  `toml:"embedding_model"`

	// SemanticWeight is the fraction of the "semantic" blend given to
	// embedding cosine similarity; BM25 keyword scoring gets the remaining
	// (1 - SemanticWeight). Range [0,1]; default 0.4 (the classic 60/40
	// BM25/cosine split). 0 = pure BM25, 1 = pure cosine. Only used when the
	// effective strategy is "semantic". The blended score is re-normalized
	// afterward, so only the ratio matters — one knob covers the full space.
	SemanticWeight float64 `toml:"semantic_weight"`
}

RetrievalConfig governs the per-turn retrieval orchestrator that scores agent-managed memory entries against the user's prompt and injects only the most relevant ones into the system prompt.

type RouterConfig

type RouterConfig struct {
	Enabled                bool     `toml:"enabled"`
	Policy                 string   `toml:"policy"`
	Candidates             []string `toml:"candidates"`
	HealthWindowSeconds    int      `toml:"health_window_seconds"`
	HealthFailureThreshold int      `toml:"health_failure_threshold"`

	// Mode controls cache-safe task routing between a smart and a fast
	// model. "off" (default) disables it entirely. "manual" resolves the
	// fast/smart models but only routes when an agent declares an explicit
	// model. "auto" additionally routes read-only/search subagents and
	// summarization to FastModel. Routing never touches the main-thread
	// model mid-conversation (that would invalidate the prompt cache and
	// cost more) — only isolated contexts are routed.
	Mode string `toml:"mode"`
	// FastModel and SmartModel name the cheap and capable models as
	// "<provider>" or "<provider>:<model>" (same grammar as Candidates).
	// Required when Mode is not "off".
	FastModel  string `toml:"fast_model"`
	SmartModel string `toml:"smart_model"`
}

RouterConfig describes the multi-provider routing policy. When Enabled is false, yottacode dispatches to the single configured provider (the legacy behavior). When true, Candidates names an ordered list of "<provider>" or "<provider>:<model>" entries and Policy selects the dispatch strategy.

Capability gating across providers is a Phase 2 concern: candidates listed here must be capability-aligned (e.g. all support web_search, or none do) for predictable system-prompt composition. The first candidate is the representative for connection probes and system-prompt rendering.

HealthWindowSeconds and HealthFailureThreshold control the router-level sliding-window failure tracker. After HealthFailureThreshold failures within HealthWindowSeconds for a candidate, the router demotes that candidate to the back of the dispatch order on subsequent requests. A successful turn clears the candidate's failure history. Set either to 0 to disable observation entirely; defaults are 60 seconds / 3 failures.

func (RouterConfig) RoutingAuto added in v0.3.0

func (r RouterConfig) RoutingAuto() bool

RoutingAuto reports whether automatic (heuristic) routing of subagents and summarization is active.

func (RouterConfig) RoutingEnabled added in v0.3.0

func (r RouterConfig) RoutingEnabled() bool

RoutingEnabled reports whether task routing is active (Mode is "manual" or "auto"). Empty/"off" means disabled.

type SkillsConfig added in v0.3.0

type SkillsConfig struct {
	DefaultOn []string `toml:"default_on"`
}

SkillsConfig declares persistent Agent Skills behavior. DefaultOn is the set of skill names to mark as enabled when each new TUI session starts (or a session is resumed). Names that don't match any loaded skill produce a startup warning so a typo surfaces instead of silently no-op'ing — same pattern as Experimental.

type ThemeConfig added in v0.3.0

type ThemeConfig struct {
	Name string `toml:"name"`
}

ThemeConfig selects the TUI color palette. Name must match a theme registered in internal/tui/themes (terminal, catppuccin, dimmed, gruvbox, high-contrast, low-contrast, no-color, nord, one-dark, solarized-dark, tokyo-night). Empty value falls through to the package default; unknown values are rejected at load time so a typo surfaces immediately instead of silently snapping back to the default.

Jump to

Keyboard shortcuts

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