config

package
v1.0.4 Latest Latest
Warning

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

Go to latest
Published: Jun 21, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package config — provider auto-discovery from environment.

AutoDetect scans the process environment for known API-key variables and appends corresponding [[providers]] entries so the user gets a working configuration with zero TOML editing — just set an API key and run.

Naming rule: if an env var is set and no provider with the canonical name (e.g. "groq") exists yet, AutoDetect adds it. A user's ok.toml always wins.

Package config loads OK's runtime configuration from TOML. Resolution order: flag > project ./ok.toml > user ~/.config/ok/config.toml > built-in defaults. Secrets come from the environment via api_key_env and are never stored in config files.

Index

Constants

View Source
const ConfigFileName = "ok.toml"

ConfigFileName is the project-level configuration file.

View Source
const DefaultSystemPrompt = `` /* 1765-byte string literal not displayed */

DefaultSystemPrompt is used when config provides none.

View Source
const DotEnvFileName = ".env"

DotEnvFileName is the project-level environment-variable file.

View Source
const LanguagePolicy = `Mirror the user's language in every reply; switch when they switch. Think ` +
	`in that language. Never translate code, identifiers, file paths, shell commands, ` +
	`or technical terms — keep them in their original form.`

LanguagePolicy is appended to every system prompt (in boot assembly) so the model mirrors the user's language per message instead of the harness pinning one — the UI `language` setting governs only the interface, never the model. It is static English text, so it stays part of the cache-stable prefix and keeps model behavior language-stable while still adapting the reply language.

Variables

This section is empty.

Functions

func ArchiveDir

func ArchiveDir() string

ArchiveDir is where compacted conversation history is archived for traceability (one timestamped .jsonl per compaction). Empty if the user config directory cannot be resolved, in which case archiving is skipped.

func AutoDetectDefaultModel

func AutoDetectDefaultModel(cfg *Config)

AutoDetectDefaultModel replaces cfg.DefaultModel with the first auto-detected provider that has its API key set, but only when the current default has no key configured. This lets a user who never wrote ok.toml just set an API key and run — OK picks the right model automatically.

func CommandDirs

func CommandDirs() []string

CommandDirs returns the directories scanned for custom slash commands, lowest priority first, so a later (more specific) directory overrides an earlier one on a name clash. Order: home-dir convention dirs (~/.claude/commands … ~/.ok/commands), the legacy XDG user dir (~/.config/ok/commands), then the project's convention dirs (.claude/commands … .ok/commands). Scanning the .claude / .agents / .agent dirs lets commands authored for other agent tools (same .md + frontmatter format) work here unchanged.

func ConventionDirs

func ConventionDirs() []string

ConventionDirs returns a copy of the asset scan directories.

func DetectDefaultModel

func DetectDefaultModel() string

DetectDefaultModel returns the name of the first auto-detected provider that has its API key set. It checks profiles in order, so the default picks the most popular provider the user actually has credentials for.

Used by the CLI to give a sensible default when no config file exists and no --model flag is passed: the user just sets an API key and runs.

func ExpandVars

func ExpandVars(s string) string

ExpandVars substitutes ${VAR} / ${VAR:-default} references from the process environment. An unset variable with no default expands to "" (matching the MCP / Claude Code convention), so a missing secret yields an empty header rather than a literal "${TOKEN}" leaking onto the wire.

func MemoryUserDir

func MemoryUserDir() string

MemoryUserDir returns the ok user config root (…/ok), under which the user-global OK.md and the per-project auto-memory store live. Empty when the user config dir can't be resolved, which disables user-scoped memory.

func MergeModeRules

func MergeModeRules(allow, ask, deny []string, policy PolicyFile) ([]string, []string, []string)

func RenderTOML

func RenderTOML(c *Config) string

RenderTOML renders the config as annotated TOML in the `ok setup` house style: comments preserved, system_prompt as a multi-line string, helpful hints. The output round-trips back through Load (see render_test.go).

func SessionDir

func SessionDir() string

SessionDir is where chat sessions are persisted (one .jsonl per session). Used by `ok chat --continue` / `--resume` to find the recent ones. Empty if the user config dir can't be resolved — sessions then aren't saved.

func SourcePath

func SourcePath() string

SourcePath returns the highest-priority config file that exists, or "" if none.

Types

type AgentConfig

type AgentConfig struct {
	SystemPrompt       string   `toml:"system_prompt"`
	SystemPromptFile   string   `toml:"system_prompt_file"`
	SystemPromptParts  []string `toml:"system_prompt_parts"` // optional: extra prompt files appended in order
	MaxSteps           int      `toml:"max_steps"`
	Temperature        float64  `toml:"temperature"`
	PlannerModel       string   `toml:"planner_model"`
	MaxConcurrentTasks int      `toml:"max_concurrent_tasks"`
	CompileCmd         string   `toml:"compile_cmd"`
	TestCmd            string   `toml:"test_cmd"`
}

AgentConfig configures the harness loop. PlannerModel is optional: when set to another provider's name it enables two-model collaboration, where the planner handles low-frequency planning in its own session (kept separate so each model's prompt prefix stays cache-stable).

type CodegraphConfig

type CodegraphConfig struct {
	Enabled bool   `toml:"enabled"`
	Path    string `toml:"path"`
}

CodegraphConfig governs the built-in CodeGraph MCP server — symbol/call-graph code intelligence (tree-sitter + SQLite) that gives the agent codegraph_* search / context / explore / trace / node tools. Enabled defaults to true; set enabled = false to drop those tools and fall back to grep/glob. Path overrides binary resolution; empty means the bundle shipped next to the ok executable, then a `codegraph` on PATH.

type Config

type Config struct {
	DefaultModel string            `toml:"default_model"`
	Language     string            `toml:"language"` // ui language tag (e.g. "zh"); empty = auto-detect from $LANG / $OK_LANG
	Agent        AgentConfig       `toml:"agent"`
	Providers    []ProviderEntry   `toml:"providers"`
	Tools        ToolsConfig       `toml:"tools"`
	Permissions  PermissionsConfig `toml:"permissions"`
	Mode         ModeConfig        `toml:"mode"`
	Sandbox      SandboxConfig     `toml:"sandbox"`
	Plugins      []PluginEntry     `toml:"plugins"`
	Skills       SkillsConfig      `toml:"skills"`
	Codegraph    CodegraphConfig   `toml:"codegraph"`
	Team         TeamConfig        `toml:"team"`
	Reasoner     ReasonerConfig    `toml:"reasoner"`
	Router       RouterConfig      `toml:"router"`
	ECP          ECPConfig         `toml:"ecp"`

	// PluginQuiet suppresses the "auto-discovered N plugin(s)" startup notice.
	PluginQuiet bool `toml:"plugin_quiet,omitempty"`
	// contains filtered or unexported fields
}

Config is OK's runtime configuration.

func Default

func Default() *Config

Default returns the built-in default configuration (DeepSeek + MiMo presets).

func Load

func Load() (*Config, error)

Load builds the configuration: defaults, then user config, then project config, then any MCP servers from Claude Code's .mcp.json. A .env in the working directory is loaded first so api_key_env can resolve.

func LoadForEdit

func LoadForEdit(path string) *Config

LoadForEdit returns a config to seed the `ok setup` wizard when reconfiguring: the built-in defaults with the file at path (if present) decoded on top, so a reconfigure preserves the user's existing providers and agent settings instead of resetting to defaults. .env is loaded so api_key_env resolution works while the wizard decides which keys are still missing.

func (*Config) AddPermissionRule

func (c *Config) AddPermissionRule(list, rule string) error

AddPermissionRule appends a rule ("ToolName" or "ToolName(glob)") to the deny list (the only remaining rule list). The rule is validated with the same parser the gate uses, and a duplicate is a no-op so a UI can call it idempotently.

func (*Config) BashMode

func (c *Config) BashMode() string

BashMode normalises the bash-sandbox mode: only an explicit "off" disables it; empty or any other value resolves to "enforce", so the sandbox is on by default and fails safe.

func (*Config) ModeAllow

func (c *Config) ModeAllow() []string

ModeAllow returns the effective allow rule list.

func (*Config) ModeAsk

func (c *Config) ModeAsk() []string

ModeAsk returns the effective ask rule list.

func (*Config) ModeDeny

func (c *Config) ModeDeny() []string

ModeDeny returns the effective deny rule list. [mode] takes precedence; falling back to [permissions] deny for backward compatibility.

func (*Config) ModeStyle

func (c *Config) ModeStyle() string

ModeStyle returns the effective mode style ("normal" | "plan" | "yolo"). [mode] takes precedence; falling back to the old [permissions] mode for backward compatibility.

func (*Config) Provider

func (c *Config) Provider(name string) (*ProviderEntry, bool)

Provider returns the named provider entry.

func (*Config) ReadRoots

func (c *Config) ReadRoots() []string

ReadRoots returns the directories read-only tools may access. When AllowRead is set, the roots are the workspace root plus those extras. When AllowRead is empty, ReadRoots falls back to WriteRoots(), so reads and writes share the same boundary by default.

func (*Config) RemovePermissionRule

func (c *Config) RemovePermissionRule(list, rule string) (bool, error)

RemovePermissionRule drops the first exact match of rule from deny list, reporting whether anything was removed.

func (*Config) RemovePlugin

func (c *Config) RemovePlugin(name string) bool

RemovePlugin deletes the named MCP server, reporting whether it was present.

func (*Config) RemoveProvider

func (c *Config) RemoveProvider(name string) error

RemoveProvider deletes the named provider. It refuses to remove the current default_model (reassign it first, so the config never points at a missing model); if the removed provider was the planner, planner_model is cleared as a side effect since it is optional. Errors when the name isn't configured.

func (*Config) ResolveModel

func (c *Config) ResolveModel(ref string) (*ProviderEntry, bool)

ResolveModel resolves a model reference to a provider entry whose Model is the selected model string (a copy, so the config's lists stay intact). It accepts:

  • "provider/model" — that exact model under that provider;
  • a provider name — the provider's default model;
  • a bare model name — the (first) provider that lists it.

The returned entry is ready to build a provider from (NewProvider reads .Model), so a single "vendor with many models" entry yields one instance per model without duplicating base_url/api_key_env. Single-`model` entries still resolve by provider name, keeping older configs working unchanged.

func (*Config) ResolveSystemPrompt

func (c *Config) ResolveSystemPrompt() (string, error)

ResolveSystemPrompt returns the system prompt, reading system_prompt_file if set, then appending any system_prompt_parts files in order. Resolution order:

  1. system_prompt_file (when non-empty) — overrides system_prompt entirely.
  2. system_prompt (when non-empty, and no system_prompt_file) — inline text.
  3. DefaultSystemPrompt — fallback when both are empty.
  4. system_prompt_parts files (optional) — appended after the base prompt, each joined with a blank line, so parts can add tooling guidelines, security rules, or language policies without editing the base.

func (*Config) SandboxOnUnavailable

func (c *Config) SandboxOnUnavailable() string

SandboxOnUnavailable returns the sandbox unavailability mode, normalising empty to "warn" so consumers don't need their own fallback logic.

func (*Config) Save

func (c *Config) Save() error

Save writes the configuration back to the file it was loaded from (SourcePath), or to ./ok.toml when none exists yet — the conventional project-local target a fresh GUI session would create.

func (*Config) SaveTo

func (c *Config) SaveTo(path string) error

SaveTo writes the configuration to path as annotated TOML, atomically: it writes a sibling temp file then renames, so a crash mid-write can't leave a half-written ok.toml that fails to parse on next load. Parent directories are created as needed.

func (*Config) SetDefaultModel

func (c *Config) SetDefaultModel(name string) error

permission rule list name accepted by the rule mutators. SetDefaultModel points default_model at an existing provider. It errors if no provider by that name is configured, so a UI can't strand the config on a model that doesn't exist.

func (*Config) SetModeStyle

func (c *Config) SetModeStyle(style string) error

SetModeStyle sets the interaction style. Accepts "plan", "normal", or "yolo" (case-insensitive); anything else errors.

func (*Config) SetPlannerModel

func (c *Config) SetPlannerModel(name string) error

SetPlannerModel sets (or, with "", clears) agent.planner_model for two-model collaboration. A non-empty name must be a configured provider.

func (*Config) SkillCustomPaths

func (c *Config) SkillCustomPaths() []string

SkillCustomPaths returns the configured custom skill roots with ${VAR} expanded; empty entries are dropped.

func (*Config) UpsertPlugin

func (c *Config) UpsertPlugin(e PluginEntry) error

UpsertPlugin adds e, or replaces an MCP server with the same name (preserving position). The transport-specific required fields are validated: stdio needs a command, http/sse need a url.

func (*Config) UpsertProvider

func (c *Config) UpsertProvider(e ProviderEntry) error

UpsertProvider adds e, or replaces an existing provider with the same name (preserving its position). Required fields (name, kind, base_url, model) are validated; whether the kind is actually registered and the key resolves is checked later by provider.New / Validate, which give actionable errors.

func (*Config) Validate

func (c *Config) Validate(model string) error

Validate checks that the selected model's provider is usable.

func (*Config) WriteFile

func (c *Config) WriteFile(path string) error

WriteFile writes the configuration to path as annotated TOML.

func (*Config) WriteRoots

func (c *Config) WriteRoots() []string

WriteRoots returns the directories file-writer tools may modify: the workspace root (defaulting to the current working directory when unset) plus any AllowWrite extras, with ${VAR} expanded. The roots are returned as given (relative or absolute); the confiner resolves them to absolute, symlink-free paths. The result is always non-empty, so confinement is on by default.

type ECPConfig

type ECPConfig struct {
	Enabled      bool     `toml:"enabled"`
	SharedSecret string   `toml:"shared_secret"`
	Peers        []string `toml:"peers"`
	SyncInterval string   `toml:"sync_interval"` // "1h", "30m", etc.
}

ECPConfig configures cross-instance knowledge federation via the Evolution Control Protocol. When Enabled, the agent shares learned skills with peers and accepts skills from them — turning single-device evolution into a federated learning network.

type ModeConfig

type ModeConfig struct {
	Default string   `toml:"default"`
	Allow   []string `toml:"allow"`
	Ask     []string `toml:"ask"`
	Deny    []string `toml:"deny"`
}

ModeConfig replaces the old [permissions] section. The Default style selects "plan", "normal", or "yolo". Allow/Ask/Deny are "ToolName" or "ToolName(glob)" rule lists with precedence: deny > ask > allow.

type PermissionsConfig deprecated

type PermissionsConfig struct {
	Mode  string   `toml:"mode"`
	Allow []string `toml:"allow"`
	Ask   []string `toml:"ask"`
	Deny  []string `toml:"deny"`
}

PermissionsConfig declares the per-call permission policy (see internal/permission). Mode is the fallback decision for writer tools when no rule matches ("ask" | "allow" | "deny"; default "ask"); read-only tools always fall back to allow. Allow/Ask/Deny are rule lists of the form "ToolName" or "ToolName(glob)". Precedence: deny > ask > allow > fallback.

Deprecated: Use ModeConfig instead. The two are mutually exclusive; if both are present, ModeConfig takes precedence.

type PluginEntry

type PluginEntry struct {
	Name    string            `toml:"name"`
	Type    string            `toml:"type"` // "stdio" (default) | "http" | "sse"
	Command string            `toml:"command"`
	Args    []string          `toml:"args"`
	Env     map[string]string `toml:"env"`
	URL     string            `toml:"url"`
	Headers map[string]string `toml:"headers"`
}

PluginEntry declares an external MCP server. Type selects the transport: "stdio" (default) launches Command/Args/Env as a subprocess; "http" (a.k.a. streamable-http) and "sse" connect to a remote URL with optional static Headers. String fields support ${VAR} / ${VAR:-default} expansion so secrets (bearer tokens, keys) come from the environment, not the file. The fields mirror Claude Code's mcpServers spec, so entries can come from either ok.toml's [[plugins]] or a project-root .mcp.json (see loadMCPJSON).

func (PluginEntry) ExpandedPlugin

func (e PluginEntry) ExpandedPlugin() PluginEntry

ExpandedPlugin returns a copy of e with ${VAR} references expanded across the command, args, env values, url, and header values — the fields Claude Code also expands. The entry itself is left untouched.

type PolicyFile

type PolicyFile struct {
	Deny  []string `toml:"deny"`
	Allow []string `toml:"allow"`
	Ask   []string `toml:"ask"`
}

func LoadPolicy

func LoadPolicy(homeDir string) (PolicyFile, error)

type ProviderEntry

type ProviderEntry struct {
	Name          string            `toml:"name"`
	Kind          string            `toml:"kind"`
	BaseURL       string            `toml:"base_url"`
	Model         string            `toml:"model"`   // a single model (back-compat)
	Models        []string          `toml:"models"`  // a vendor's model list (one base_url/key, many models)
	Default       string            `toml:"default"` // default model when Models is set (else Models[0])
	APIKeyEnv     string            `toml:"api_key_env"`
	BalanceURL    string            `toml:"balance_url"` // optional; a provider-specific wallet-balance endpoint (DeepSeek: https://api.deepseek.com/user/balance). Empty = no balance readout.
	ContextWindow int               `toml:"context_window"`
	Price         *provider.Pricing `toml:"price"`
}

ProviderEntry declares a model provider instance. ContextWindow is the model's token budget; the harness compacts older history as a turn's prompt approaches it (see agent compaction). 0 disables compaction for the instance.

func AutoDetectProviders

func AutoDetectProviders(existing []ProviderEntry) []ProviderEntry

AutoDetectProviders scans the environment for known API-key variables and appends any that are set and whose canonical name is not already present in cfg.Providers. It returns the (possibly extended) list so Call can choose to append it to cfg.Providers or ignore it.

A previously configured ok.toml always wins — AutoDetect only fills gaps.

func (*ProviderEntry) APIKey

func (e *ProviderEntry) APIKey() string

APIKey resolves the entry's API key from its api_key_env.

func (*ProviderEntry) DefaultModel

func (e *ProviderEntry) DefaultModel() string

DefaultModel returns the provider's default model: the explicit `default`, else the first of ModelList.

func (*ProviderEntry) HasModel

func (e *ProviderEntry) HasModel(m string) bool

HasModel reports whether m is one of the provider's models.

func (*ProviderEntry) ModelList

func (e *ProviderEntry) ModelList() []string

ModelList returns the models this provider exposes: the explicit `models` list, or the single `model` as a one-element list (back-compat). Empty if neither set.

type ReasonerConfig

type ReasonerConfig struct {
	DecomposeModel string `toml:"decompose_model"`
	MaxConcurrent  int    `toml:"max_concurrent"`
}

ReasonerConfig configures the top-level multi-agent Reasoner. DecomposeModel, when set, enables LLM-based DAG decomposition. MaxConcurrent caps parallel task execution (default 3).

type RouterConfig

type RouterConfig struct {
	Enabled        bool   `toml:"enabled"`
	CheapModel     string `toml:"cheap_model"`
	ExpensiveModel string `toml:"expensive_model"`
}

RouterConfig configures model routing by task complexity. When Enabled, CheapModel handles simple tasks and ExpensiveModel handles complex ones. DefaultModel is used for normal-complexity tasks.

type SandboxConfig

type SandboxConfig struct {
	WorkspaceRoot string   `toml:"workspace_root"`
	AllowWrite    []string `toml:"allow_write"`
	AllowRead     []string `toml:"allow_read"`
	// Bash is the OS-sandbox mode for the bash tool: "enforce" (default) jails
	// each command, "off" runs it unconfined.
	Bash string `toml:"bash"`
	// Network allows network egress from inside the bash sandbox. Defaults true
	// so module/package downloads keep working; the boundary is then writes.
	Network bool `toml:"network"`
	// OnUnavailable controls behaviour when the OS sandbox is not available on
	// the current platform: "warn" (default) prints a warning and continues;
	// "block" refuses to run so you never operate without the sandbox.
	OnUnavailable string `toml:"on_unavailable"`
}

SandboxConfig bounds the blast radius of tool calls. WorkspaceRoot is the directory file writers/readers may access; empty means the current working directory. AllowWrite lists extra dirs writers may also touch; AllowRead lists extra dirs readable beyond WorkspaceRoot (defaults to AllowWrite when unset, so reads and writes share the same boundary). Both support ${VAR} expansion.

type SkillsConfig

type SkillsConfig struct {
	Paths []string `toml:"paths"`
}

SkillsConfig configures skill discovery. Paths adds extra "custom"-scope skill roots — each a directory of SKILL.md / <name>.md playbooks — scanned between the project roots (.ok/.agents/.claude under the workspace) and the global roots (the same three under the home dir). ~ and relative paths and ${VAR} expansion are supported.

type SpecialistConfig

type SpecialistConfig struct {
	Name        string   `toml:"name"`
	Model       string   `toml:"model"`
	Description string   `toml:"description"`
	Prompt      string   `toml:"prompt"`
	Tools       []string `toml:"tools"`
}

SpecialistConfig declares one specialist in a team.

type TeamConfig

type TeamConfig struct {
	Orchestrator string             `toml:"orchestrator"`
	Specialists  []SpecialistConfig `toml:"specialists"`
}

TeamConfig declares an agent team — an orchestrator model + specialist agents.

type ToolsConfig

type ToolsConfig struct {
	Enabled []string `toml:"enabled"`
}

ToolsConfig selects which built-in tools are enabled. Empty means all of them.

Jump to

Keyboard shortcuts

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