config

package
v0.0.0-...-22d78c6 Latest Latest
Warning

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

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

Documentation

Overview

Package config parses, validates, and resolves the OpenCode Advance stack.toml configuration file into typed Go structs.

Phase 1 scope covers [meta] and [mcp.servers.*]. Known-but-unimplemented top-level sections (agents, etc.) parse into a generic DeferredSections map without error. Truly unknown top-level sections produce a validation error.

Phase 3 graduates providers, permissions, watcher, and lsp into typed structs with Extra map[string]any passthrough.

See docs/design/phase1-mcp-apply.md for the full type design.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidationErrorContains

func ValidationErrorContains(err error, substr string) bool

ValidationErrorContains returns true if any ValidationError's message contains the given substring. Used by tests to assert a specific error was raised without matching the exact path+message format.

Types

type AutoupdateValue

type AutoupdateValue struct {
	Bool *bool
	Str  *string
}

AutoupdateValue represents the autoupdate field which can be a bool (true/false) or a string ("notify"). Exactly one of Bool or Str is set.

type CircuitBreaker

type CircuitBreaker struct {
	FailureThreshold int    `toml:"failure_threshold,omitempty" yaml:"failure_threshold,omitempty"`
	RecoveryTimeout  string `toml:"recovery_timeout,omitempty" yaml:"recovery_timeout,omitempty"`
}

CircuitBreaker configures fast-fail after repeated failures (Vision passthrough).

type Command

type Command struct {
	Description string         `toml:"description"`
	Template    string         `toml:"template"`
	Agent       string         `toml:"agent,omitempty"`
	Model       string         `toml:"model,omitempty"`
	Subtask     *bool          `toml:"subtask,omitempty"`
	Extra       map[string]any `toml:"-"`
}

Command describes a custom slash command declared in [commands.<name>].

func (*Command) UnmarshalTOML

func (c *Command) UnmarshalTOML(value any) error

UnmarshalTOML implements custom decoding to capture extra unknown fields into the Extra map.

type CommandsSection

type CommandsSection map[string]Command

CommandsSection is the [commands] table — a map of command name to Command.

type CompactionSection

type CompactionSection struct {
	Auto     *bool          `toml:"auto,omitempty"`
	Prune    *bool          `toml:"prune,omitempty"`
	Reserved int            `toml:"reserved,omitempty"`
	Extra    map[string]any `toml:"-"`
}

CompactionSection is the [opencode.compaction] passthrough table.

type Formatter

type Formatter struct {
	Command     []string          `toml:"command,omitempty"`
	Extensions  []string          `toml:"extensions,omitempty"`
	Disabled    bool              `toml:"disabled,omitempty"`
	Environment map[string]string `toml:"environment,omitempty"`
	Extra       map[string]any    `toml:"-"`
}

Formatter describes a code formatter declared in [formatters.<name>].

func (*Formatter) UnmarshalTOML

func (f *Formatter) UnmarshalTOML(value any) error

UnmarshalTOML implements custom decoding to capture extra unknown fields into the Extra map.

type FormattersSection

type FormattersSection map[string]Formatter

FormattersSection is the [formatters] table — a map of formatter name to Formatter.

type InstructionsSection

type InstructionsSection struct {
	Order []string `toml:"order,omitempty"`
}

InstructionsSection is the [instructions] table.

type LSP

type LSP struct {
	Command    []string       `toml:"command,omitempty"`
	Extensions []string       `toml:"extensions,omitempty"`
	Disabled   bool           `toml:"disabled,omitempty"`
	Extra      map[string]any `toml:"-"`
}

LSP describes an LSP server declared in [lsp.<name>].

func (*LSP) UnmarshalTOML

func (l *LSP) UnmarshalTOML(value any) error

UnmarshalTOML implements custom decoding to capture extra unknown fields into the Extra map.

type LSPSection

type LSPSection map[string]LSP

LSPSection is the [lsp] table — a map of LSP server name to LSP.

type MCPSection

type MCPSection struct {
	Servers    map[string]Server    `toml:"servers"`
	SlotGroups map[string]SlotGroup `toml:"slot_groups,omitempty"`
	ToolSuites map[string]ToolSuite `toml:"tool_suites,omitempty"`
}

MCPSection is the [mcp] table. Carries both regular servers and Vision slot_groups (pools of identical servers behind a single virtual port), plus tool_suite definitions for per-agent MCP exposure profiles.

type Meta

type Meta struct {
	Version     string `toml:"version"`
	Name        string `toml:"name,omitempty"`
	Description string `toml:"description,omitempty"`
}

Meta is the [meta] table.

type OpenCodeSection

type OpenCodeSection struct {
	Theme             string               `toml:"theme,omitempty"`
	DefaultAgent      string               `toml:"default_agent,omitempty"`
	Share             string               `toml:"share,omitempty"`
	Snapshot          *bool                `toml:"snapshot,omitempty"`
	Autoupdate        *AutoupdateValue     `toml:"autoupdate,omitempty"`
	Compaction        *CompactionSection   `toml:"compaction,omitempty"`
	DisabledProviders *ProviderListSection `toml:"disabled_providers,omitempty"`
	EnabledProviders  *ProviderListSection `toml:"enabled_providers,omitempty"`
	Extra             map[string]any       `toml:"-"`
}

OpenCodeSection is the [opencode] table — top-level OpenCode behavior toggles.

func (*OpenCodeSection) UnmarshalTOML

func (o *OpenCodeSection) UnmarshalTOML(value any) error

UnmarshalTOML implements custom decoding to capture extra unknown fields into the Extra map and handle the autoupdate bool/string union.

type ParseError

type ParseError struct {
	Path string
	Err  error
}

ParseError wraps a TOML decode error with the source path for better user-facing diagnostics. Exposed so callers can distinguish it from Validate-time errors.

func (*ParseError) Error

func (e *ParseError) Error() string

func (*ParseError) Unwrap

func (e *ParseError) Unwrap() error

type Paths

type Paths struct {
	OpencodeConfigDir   string // $OCA_OPENCODE_CONFIG_DIR or ~/.config/opencode
	VisionConfigDir     string // $OCA_VISION_CONFIG_DIR or ~/.config/vision
	CacheDir            string // $OCA_CACHE_DIR or $XDG_RUNTIME_DIR/opencode-advance or /tmp/opencode-advance-$UID
	PluginCheckoutRoot_ string // $OCA_PLUGIN_CHECKOUT_ROOT or ~/dev/oc-plugins
}

Paths are the resolved target directories OCA writes to. Every field honors the matching environment override; unset envs fall back to the user's XDG/home defaults.

The cache directory is where the apply-lock (flock) lives.

func ResolvePaths

func ResolvePaths() Paths

ResolvePaths returns the effective target paths for this process. Safe to call during tests — pass env overrides via os.Setenv to redirect writes to t.TempDir().

func (Paths) ApplyLockPath

func (p Paths) ApplyLockPath() string

ApplyLockPath is the file used by WriteAtomic flock to serialize concurrent oca apply runs.

func (Paths) DriftCachePath

func (p Paths) DriftCachePath() string

DriftCachePath is the cached result of read-only plugin update probes.

func (Paths) EnvStampPath

func (p Paths) EnvStampPath() string

EnvStampPath is the stamp touched after env.sh has been written.

func (Paths) OCAConfigDir

func (p Paths) OCAConfigDir() string

OCAConfigDir is the directory for OCA-owned shell integration state. It is intentionally a sibling of the OpenCode config dir so tests that override OCA_OPENCODE_CONFIG_DIR stay isolated without introducing another env var.

func (Paths) OCAEnvPath

func (p Paths) OCAEnvPath() string

OCAEnvPath is the OCA-owned environment file sourced by managed shell hooks.

func (Paths) OpencodeJSON

func (p Paths) OpencodeJSON() string

OpencodeJSON is the full path to the OpenCode JSON config file.

func (Paths) OpencodeSkillsDir

func (p Paths) OpencodeSkillsDir() string

OpencodeSkillsDir is the target directory for OCA-owned skill copies. Defaults to <OpencodeConfigDir>/skills, honoring OCA_OPENCODE_CONFIG_DIR.

func (Paths) PluginCheckoutRoot

func (p Paths) PluginCheckoutRoot() string

PluginCheckoutRoot is the default parent directory for plugin checkouts. Honors $OCA_PLUGIN_CHECKOUT_ROOT when set, otherwise ~/dev/oc-plugins.

func (Paths) VisionServersYAML

func (p Paths) VisionServersYAML() string

VisionServersYAML is the full path to Vision's servers.yaml.

type PermissionsSection

type PermissionsSection struct {
	Default           string            `toml:"default,omitempty"`
	DoomLoop          string            `toml:"doom_loop,omitempty"`
	ExternalDirectory map[string]string `toml:"external_directory,omitempty"`
	Bash              map[string]string `toml:"bash,omitempty"`
	Extra             map[string]any    `toml:"-"`
}

PermissionsSection is the [permissions] table. Shape translation (default → .permission["*"]) happens in the render layer.

type Plugin

type Plugin struct {
	Source       string             `toml:"source"`             // git URL or "npm:pkg@version"
	Ref          string             `toml:"ref,omitempty"`      // branch/tag/SHA; default "trunk"
	Checkout     string             `toml:"checkout,omitempty"` // local clone path
	Subdir       string             `toml:"subdir,omitempty"`   // subdir within checkout
	Build        []string           `toml:"build,omitempty"`    // build commands
	Path         string             `toml:"path,omitempty"`     // load path, supports {checkout}/{subdir}
	Sync         string             `toml:"sync,omitempty"`     // post-build sync script
	Provides     []ProvidesCategory `toml:"provides,omitempty"`
	Instructions []string           `toml:"instructions,omitempty"` // instruction files
	Enabled      *bool              `toml:"enabled,omitempty"`      // default true
}

Plugin describes a plugin declared in [plugins.<name>]. Plugins are either git-sourced (with checkout + optional subdir + build + sync) or npm-sourced (with a "npm:pkg@version" source string).

func (Plugin) IsEnabled

func (p Plugin) IsEnabled() bool

IsEnabled returns the effective enabled state. Nil means true.

func (Plugin) IsGitSource

func (p Plugin) IsGitSource() bool

IsGitSource returns true for git URL sources (not npm: or local: prefixed).

func (Plugin) IsLocalSource

func (p Plugin) IsLocalSource() bool

IsLocalSource returns true for local:-prefixed sources.

func (Plugin) IsNPMSource

func (p Plugin) IsNPMSource() bool

IsNPMSource returns true for npm:-prefixed sources.

type PluginsSection

type PluginsSection map[string]Plugin

PluginsSection is the [plugins] table — a map of plugin name to Plugin.

type Provider

type Provider struct {
	Models   map[string]ProviderModel `toml:"models,omitempty"`
	Options  map[string]any           `toml:"options,omitempty"`
	Variants map[string]any           `toml:"variants,omitempty"`
	Extra    map[string]any           `toml:"-"`
}

Provider describes a model provider declared in [providers.<name>].

func (*Provider) UnmarshalTOML

func (p *Provider) UnmarshalTOML(value any) error

UnmarshalTOML implements custom decoding to capture extra unknown fields (fields not in the Provider struct) into the Extra map, including at nested levels (per-model Extra via ProviderModel.UnmarshalTOML).

type ProviderListSection

type ProviderListSection struct {
	List []string `toml:"list,omitempty"`
}

ProviderListSection is used for [opencode.disabled_providers] and [opencode.enabled_providers] — each has a `list` field.

type ProviderModel

type ProviderModel struct {
	Name     string         `toml:"name,omitempty"`
	Context  int            `toml:"context,omitempty"`
	Output   int            `toml:"output,omitempty"`
	Inputs   []string       `toml:"inputs,omitempty"`
	Outputs  []string       `toml:"outputs,omitempty"`
	Options  map[string]any `toml:"options,omitempty"`
	Variants map[string]any `toml:"variants,omitempty"`
	Extra    map[string]any `toml:"-"`
}

ProviderModel describes a single model under a provider. Shape translation to opencode.json happens in the render layer.

func (*ProviderModel) UnmarshalTOML

func (m *ProviderModel) UnmarshalTOML(modelName string, value any) error

modelName is passed explicitly because ProviderModel is identified by its map key in ProvidersSection, not by an internal name field for TOML decode.

type ProvidersSection

type ProvidersSection map[string]Provider

ProvidersSection is the [providers] table — a map of provider name to Provider.

type ProvidesCategory

type ProvidesCategory string

ProvidesCategory enumerates asset categories a plugin can declare it owns. When a plugin lists a category in provides, oca apply skips rendering or copying assets in that category from its own assets/ dir.

const (
	ProvidesCommands     ProvidesCategory = "adv-commands"
	ProvidesAgents       ProvidesCategory = "adv-agents"
	ProvidesSkills       ProvidesCategory = "adv-skills"
	ProvidesOverlays     ProvidesCategory = "adv-overlays"
	ProvidesInstructions ProvidesCategory = "adv-instructions"
	ProvidesTemporal     ProvidesCategory = "adv-temporal" // Temporal config owned by OCA (Phase 5+)
)

func (ProvidesCategory) IsValid

func (p ProvidesCategory) IsValid() bool

IsValid returns true if the category is a known provides value.

type RetryConfig

type RetryConfig struct {
	MaxAttempts     int      `toml:"max_attempts,omitempty" yaml:"max_attempts,omitempty"`
	InitialDelay    string   `toml:"initial_delay,omitempty" yaml:"initial_delay,omitempty"`
	MaxDelay        string   `toml:"max_delay,omitempty" yaml:"max_delay,omitempty"`
	RetryableErrors []string `toml:"retryable_errors,omitempty" yaml:"retryable_errors,omitempty"`
}

RetryConfig configures retryable-failure behavior (Vision passthrough). Named RetryConfig (not Retry) so usage at call sites reads as a noun describing configuration data, not a verb that could be misread as an action. Field name on Server remains Retry; TOML/YAML keys remain "retry".

type Server

type Server struct {
	// Core transport (Vision)
	Port      int               `toml:"port" yaml:"port"`
	Type      string            `toml:"type,omitempty" yaml:"-"`                        // OCA "daemon"|"stdio"|"http"|"sse"
	Transport string            `toml:"transport,omitempty" yaml:"transport,omitempty"` // Vision passthrough alias
	Command   string            `toml:"command,omitempty" yaml:"command,omitempty"`
	Args      []string          `toml:"args,omitempty" yaml:"args,omitempty"`
	Env       map[string]string `toml:"env,omitempty" yaml:"env,omitempty"`
	URL       string            `toml:"url,omitempty" yaml:"url,omitempty"`
	Headers   map[string]string `toml:"headers,omitempty" yaml:"headers,omitempty"`

	// Lifecycle (Vision)
	Autostart           bool   `toml:"autostart,omitempty" yaml:"autostart,omitempty"`
	RestartPolicy       string `toml:"restart_policy,omitempty" yaml:"restart_policy,omitempty"`
	MaxRestarts         int    `toml:"max_restarts,omitempty" yaml:"max_restarts,omitempty"`
	Stateful            bool   `toml:"stateful,omitempty" yaml:"stateful,omitempty"`
	AvailabilityProfile string `toml:"availability_profile,omitempty" yaml:"availability_profile,omitempty"`
	SessionTimeout      string `toml:"session_timeout,omitempty" yaml:"session_timeout,omitempty"`
	MaxSessions         int    `toml:"max_sessions,omitempty" yaml:"max_sessions,omitempty"`
	SessionTTL          string `toml:"session_ttl,omitempty" yaml:"session_ttl,omitempty"`
	HealthCheckInterval string `toml:"health_check_interval,omitempty" yaml:"health_check_interval,omitempty"`
	RequestTimeout      string `toml:"request_timeout,omitempty" yaml:"request_timeout,omitempty"`
	Timeout             int    `toml:"timeout,omitempty" yaml:"-"` // OCA-side alias (ms) → Vision request_timeout

	// Resilience (Vision)
	Retry          *RetryConfig    `toml:"retry,omitempty" yaml:"retry,omitempty"`
	CircuitBreaker *CircuitBreaker `toml:"circuit_breaker,omitempty" yaml:"circuit_breaker,omitempty"`

	// Sharing (Vision)
	SharedReadOnlyTools   []string `toml:"shared_read_only_tools,omitempty" yaml:"shared_read_only_tools,omitempty"`
	SharedResultCacheTTL  string   `toml:"shared_result_cache_ttl,omitempty" yaml:"shared_result_cache_ttl,omitempty"`
	SharedResultCacheSize int      `toml:"shared_result_cache_size,omitempty" yaml:"shared_result_cache_size,omitempty"`
	MaxInFlightRequests   int      `toml:"max_in_flight_requests,omitempty" yaml:"max_in_flight_requests,omitempty"`

	// OCA-respected / Vision accepts after V2+V3
	Required    bool   `toml:"required,omitempty" yaml:"required,omitempty"`
	Source      string `toml:"source,omitempty" yaml:"source,omitempty"`
	Description string `toml:"description,omitempty" yaml:"description,omitempty"`

	// Enabled is tri-state (pointer) so "enabled=false" is distinguishable
	// from "field absent (default true)" at render time.
	Enabled *bool `toml:"enabled,omitempty" yaml:"enabled,omitempty"`

	// OCA-side only — stripped at render time.
	EnvFile string `toml:"env_file,omitempty" yaml:"-"`
}

Server mirrors Vision's internal/config.ServerConfig field-for-field plus OCA-only additions (Required is now in Vision post-V3; Source and Description are in Vision post-V2; EnvFile and Type="daemon" are OCA-only and stripped at render time when appropriate).

Unknown Vision-side fields under [mcp.servers.<name>] land in ExtraFields as raw map entries so OCA passes them through to servers.yaml without interpretation (forward-compat with Vision schema additions).

func (Server) IsEnabled

func (s Server) IsEnabled() bool

IsEnabled returns the effective enabled state for a server. Absent (nil) is treated as true; explicit false disables.

type SessionSection

type SessionSection struct {
	Prefix          string          `toml:"prefix,omitempty"`
	Mode            string          `toml:"mode,omitempty"`
	Reaper          bool            `toml:"reaper,omitempty"`
	ReaperThreshold time.Duration   `toml:"reaper_threshold,omitempty"`
	Theme           string          `toml:"theme,omitempty"`
	BootSplash      bool            `toml:"boot_splash,omitempty"`
	Watchdog        *WatchdogConfig `toml:"watchdog,omitempty"`
	Extra           map[string]any  `toml:"-"`
	// contains filtered or unexported fields
}

SessionSection is the [session] table. Carries session-level configuration including the watchdog subsystem for automatic hang detection and recovery.

Mode, Reaper, ReaperThreshold, Theme, and BootSplash drive `oca session new` behavior:

  • Mode: session topology. "project" (default) uses one tmux session per project with multiple worktree windows. "per-invocation" preserves the legacy Pattern A behavior that creates a new oca-<slug>-<n> session per launch.
  • Reaper: run the stale-session reaper as a fire-and-forget goroutine after creating a new session. Default true.
  • ReaperThreshold: age above which an unattached session is considered stale. Parsed as a Go duration string ("4h", "30m"). Default 4h. Floor of 5m enforced inside ReapStale to avoid pathological values.
  • Theme: name of the bundled tmux theme passed to `resolveTmuxConf`. Default "obsidian". Unknown names degrade to no -f flag.
  • BootSplash: whether to trigger the boot splash on `session new`. Default true. CLI `--no-splash` always wins.

func (*SessionSection) UnmarshalTOML

func (s *SessionSection) UnmarshalTOML(value any) error

UnmarshalTOML implements custom decoding for SessionSection to capture extra unknown fields and parse the watchdog subsection.

type ShellSection

type ShellSection struct {
	AutoRefresh       *bool  `toml:"auto_refresh,omitempty"`
	AutoRefreshNotice string `toml:"auto_refresh_notice,omitempty"`
}

ShellSection is the [shell] table. It governs OCA's managed shell block behavior without re-sourcing user-owned rc files.

func (ShellSection) IsAutoRefreshEnabled

func (s ShellSection) IsAutoRefreshEnabled() bool

IsAutoRefreshEnabled returns the effective shell auto-refresh setting. Absent means enabled; explicit false disables hook registration.

type SkillsSection

type SkillsSection struct {
	Order []string `toml:"order,omitempty"`
}

SkillsSection is the [skills] table.

type SlotGroup

type SlotGroup struct {
	// Template is the prefix for synthesized server names (<template>-1 ..
	// <template>-count). Must not collide with any [mcp.servers.*] key once
	// expanded.
	Template string `toml:"template" yaml:"template"`

	// BasePort is the port of the first synthesized slot. Subsequent slots
	// occupy base_port+1, base_port+2, ... base_port+count-1.
	BasePort int `toml:"base_port" yaml:"base_port"`

	// Count is the number of synthesized slots. Vision requires count >= 2.
	Count int `toml:"count" yaml:"count"`

	// GroupPort is the port of the virtual group listener that agents
	// connect to. Must not overlap with any slot port or other server.
	GroupPort int `toml:"group_port" yaml:"group_port"`

	// Defaults are the ServerConfig fields applied to every synthesized
	// slot. The `port` field on Defaults is rejected by validation because
	// Vision derives slot ports from BasePort.
	Defaults *Server `toml:"defaults,omitempty" yaml:"defaults,omitempty"`
}

SlotGroup mirrors Vision's internal/config.SlotGroupConfig field-for-field. A slot group declares a pool of N identical MCP servers (synthesized at load time as <template>-1 .. <template>-count on contiguous ports starting at base_port) plus a virtual listener at group_port that routes each agent session to the least-loaded healthy slot.

OCA renders slot groups into vision/servers.yaml under the top-level slot_groups: key. Vision performs the expansion at load time; OCA does NOT emit the synthesized per-slot servers itself, mirroring Vision's save round-trip contract (see vision/docs/CONFIGURATION.md § Slot Groups).

In opencode.json, OCA emits a single .mcp.<group-name> remote entry pointing at http://localhost:<group_port>/mcp so OpenCode addresses the pool through one stable URL.

type Stack

type Stack struct {
	Meta Meta       `toml:"meta"`
	MCP  MCPSection `toml:"mcp"`

	// Phase 2 typed sections
	Plugins      PluginsSection      `toml:"plugins"`
	Instructions InstructionsSection `toml:"instructions"`
	Temporal     *TemporalSection    `toml:"temporal"`

	// Phase 3 typed sections
	Providers   ProvidersSection   `toml:"providers"`
	Permissions PermissionsSection `toml:"permissions"`
	Watcher     WatcherSection     `toml:"watcher"`
	LSP         LSPSection         `toml:"lsp"`

	// Phase 3.5 typed sections
	Skills     SkillsSection     `toml:"skills"`
	Formatters FormattersSection `toml:"formatters"`
	Commands   CommandsSection   `toml:"commands"`
	OpenCode   OpenCodeSection   `toml:"opencode"`

	// Session typed section (promoted from deferred)
	Session *SessionSection `toml:"session,omitempty"`

	// Shell controls OCA-managed interactive shell behavior.
	Shell ShellSection `toml:"shell,omitempty"`

	// UpdateProbe controls read-only plugin update awareness.
	UpdateProbe UpdateProbeSection `toml:"update_probe,omitempty"`

	// DeferredSections holds known-but-unimplemented top-level sections
	// verbatim so that a complete stack.toml (including future-phase
	// sections) round-trips through Phase 1 without errors. Entries are
	// not rendered by Phase 1 target writers.
	DeferredSections map[string]any `toml:"-"`

	// Warnings are non-fatal issues surfaced during Load (e.g. env_file
	// path does not exist). Apply and Doctor surface these to the user.
	Warnings []Warning `toml:"-"`
}

Stack is the in-memory representation of a validated stack.toml file. Fields are populated by Parse, with validation run by Validate and variable expansion by Resolve. Use Load to run the full pipeline.

func Load

func Load(path string) (*Stack, error)

Load runs the full pipeline for a stack.toml file on disk:

  1. Parse (TOML decode → typed Stack with deferred sections)
  2. Resolve (variable expansion: $HOME, ~/, $XDG_*, ${VAR})
  3. Validate (aggregate ValidationErrors with field paths)
  4. Collect warnings (e.g. env_file path does not exist)

Order rationale: Resolve runs before Validate so validation sees resolved paths (e.g. env_file paths with ~/expanded). This corrects the original Parse→Validate→Resolve order from the initial design.

Load returns the Stack on success and ValidationErrors (as a wrapped error) on failure. Warnings are attached to Stack.Warnings for the caller to surface; they never fail Load.

func Parse

func Parse(data []byte) (*Stack, error)

Parse decodes TOML bytes into a Stack. Unknown top-level keys (not in knownSections) are collected into DeferredSections with their raw map representation; the caller's Validate run decides which ones are truly-unknown (error) vs known-but-deferred (ok).

This deliberately decodes permissively: BurntSushi/toml's MetaData gives us the key set so we can compare against knownSections, but we don't use DisallowUnknownFields at the root — Vision may add fields to [mcp.servers.*] that OCA wants to pass through.

func ParseFile

func ParseFile(path string) (*Stack, error)

ParseFile reads and parses a stack.toml file from disk. Returns a *ParseError wrapping any IO or TOML decode failure.

func (*Stack) Resolve

func (s *Stack) Resolve()

Resolve expands OCA-owned tokens in-place on the Stack:

  • $HOME and ~/... → user home directory
  • $XDG_CONFIG_HOME, $XDG_DATA_HOME → env lookup with defaults
  • ${VAR} / ${VAR:-default} → env lookup

Native OpenCode tokens — {env:...}, {file:...} — are left UNCHANGED so OpenCode resolves them at runtime. This is the deliberate handoff point that keeps OCA secret-blind: OCA records these tokens verbatim and never reads the underlying files or env vars.

func (*Stack) Validate

func (s *Stack) Validate() error

Validate runs all schema checks against a parsed Stack. Errors are aggregated — the returned ValidationErrors contains every problem found so the user can fix them in one pass. nil is returned when the stack is valid.

type TemporalSection

type TemporalSection struct {
	Enabled     *bool  `toml:"enabled,omitempty"`      // default true if absent
	Address     string `toml:"address,omitempty"`      // default "127.0.0.1:7233"
	Namespace   string `toml:"namespace,omitempty"`    // default "default"
	AllowRemote *bool  `toml:"allow_remote,omitempty"` // must be true for non-loopback
	NodePath    string `toml:"node_path,omitempty"`    // optional override for node binary
}

TemporalSection is the [temporal] table. Phase 5 expands this from a reserved stub to a fully-validated config section with defaults. Validation (validateTemporal) fills defaults for Address and Namespace when enabled.

func (*TemporalSection) IsEnabled

func (t *TemporalSection) IsEnabled() bool

IsEnabled returns the effective enabled state. Nil means true.

type ToolSuite

type ToolSuite struct {
	Servers     []string `toml:"servers"`
	Description string   `toml:"description,omitempty"`
}

ToolSuite defines a named group of MCP servers that can be included or excluded in agent profiles. This allows OCA to manage per-agent MCP exposure without manually listing every tool in agent frontmatter.

Example stack.toml:

[mcp.tool_suites.research]
servers = ["kagi", "context7", "firecrawl", "gh-grep"]
description = "Web search, docs, scraping, code examples"

[mcp.tool_suites.code-intel]
servers = ["lgrep"]
description = "Local code intelligence"

type UpdateProbeSection

type UpdateProbeSection struct {
	Default            string `toml:"default,omitempty"`
	TimeoutPerPluginMS int    `toml:"timeout_per_plugin_ms,omitempty"`
	TimeoutGlobalMS    int    `toml:"timeout_global_ms,omitempty"`
	CacheTTLMinutes    int    `toml:"cache_ttl_minutes,omitempty"`
	// contains filtered or unexported fields
}

UpdateProbeSection is the [update_probe] table. It powers both `oca update --check` and the shell drift surfacer.

func (*UpdateProbeSection) UnmarshalTOML

func (u *UpdateProbeSection) UnmarshalTOML(value any) error

UnmarshalTOML captures whether numeric fields were present so validation can distinguish "absent, apply default" from "explicit zero, invalid".

type ValidationError

type ValidationError struct {
	Path    string // e.g. mcp.servers.kagi.port
	Message string
}

ValidationError is a single field-scoped problem with the input.

func (ValidationError) Error

func (e ValidationError) Error() string

type ValidationErrors

type ValidationErrors []ValidationError

ValidationErrors aggregates multiple ValidationError instances so callers can surface every issue in one pass.

func (ValidationErrors) Error

func (es ValidationErrors) Error() string

func (ValidationErrors) HasErrors

func (es ValidationErrors) HasErrors() bool

HasErrors returns true when the slice is non-empty.

type Warning

type Warning struct {
	Path    string // e.g. "mcp.servers.kagi.env_file"
	Message string
	Hint    string // optional remediation suggestion
}

Warning carries a non-fatal diagnostic from Load. Surfaced by apply and doctor commands but does not abort operations.

type WatchdogConfig

type WatchdogConfig struct {
	Enabled     bool          `toml:"enabled"`
	IdleTimeout time.Duration `toml:"idle_timeout,omitempty"`
	MaxBumps    int           `toml:"max_bumps,omitempty"`
}

WatchdogConfig configures automatic hang detection and recovery for OpenCode agent sessions. The plugin detects hangs by tracking session events; the CLI handles recovery via oca pane restart-tui.

Default is opt-in (enabled = false) for v1.

func (*WatchdogConfig) UnmarshalTOML

func (w *WatchdogConfig) UnmarshalTOML(value any) error

UnmarshalTOML implements custom decoding for WatchdogConfig to parse idle_timeout as a Go duration string (e.g. "5m", "30s").

type WatcherSection

type WatcherSection struct {
	Ignore []string       `toml:"ignore,omitempty"`
	Extra  map[string]any `toml:"-"`
}

WatcherSection is the [watcher] table.

Jump to

Keyboard shortcuts

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