config

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: May 17, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

README

config

Loads agent.toml into a typed Config. Follows the same composable-primitives pattern as agentkit/credentials and agentkit/policy — individual sources are constructed explicitly, and the caller assembles layers when needed. No discovery logic lives here; that belongs in the application.

Core API

// Single file
cfg, err := config.FromFile("agent.toml").Get()

// Layered (later sources override earlier ones)
cfg, err := config.NewUnion(
    config.FromFile("~/.agent/agent.toml"),
    config.FromFile("./agent.toml"),
).Get()

// Direct merge of two known Config values
a, _ := config.FromFile("base.toml").Get()
b, _ := config.FromFile("override.toml").Get()
cfg := config.Merge(a, b)
Symbol Role
Source Interface every source implements: Get() (Config, error)
FromFile(path) Source backed by a TOML file; returns ErrNotFound on Get() if absent
NewUnion(sources...) Source that merges left to right; silently skips ErrNotFound
Merge(base, override) Explicit Config merge — override wins on non-zero fields
ErrNotFound Sentinel returned when the underlying file does not exist

NewUnion skips missing files silently; any other error (parse error, invalid duration) aborts. This lets callers include optional locations without extra nil-checks:

cfg, err := config.NewUnion(
    config.FromFile(globalPath),   // silently skipped if absent
    config.FromFile("./agent.toml"),
).Get()

Credentials are not in agent.toml

API keys live in credentials.toml and are managed by agentkit/credentials. Inject them into each llm.Config before calling llm.New:

// Typical credential store: credentials.toml merged with env vars.
credStore := credentials.NewUnionStore(
    credentials.NewFileStore("credentials.toml"),
    credentials.NewEnvStore(),
)

cred, _ := credStore.Get(cfg.Models.Default.Service)
cfg.Models.Default.APIKey = cred.APIKey
model, err := llm.New(cfg.Models.Default)

Apply the same pattern to cfg.Models.Supervisor and each cfg.Models.Profiles[name].

Policy is not in agent.toml

Policy is sourced independently (CLI flag, env var, or by convention) and loaded via agentkit/policy. This lets the caller choose enforcement behaviour:

// fail-close
pol, err := policy.FromFile(policyPath, workspace, home)

// fail-open
pol, _ := policy.FromFile(policyPath, workspace, home)
if pol == nil { pol = policy.New() }

Wiring into workflow.Runtime

cfg, err := config.NewUnion(
    config.FromFile(globalPath),
    config.FromFile("./agent.toml"),
).Get()

// Build a credential store. Typically a union of a file store and env vars
// so that CI/CD environments can override credentials.toml entries via
// environment variables (e.g. ANTHROPIC_API_KEY).
credStore := credentials.NewUnionStore(
    credentials.NewFileStore("credentials.toml"),
    credentials.NewEnvStore(),
)

// Inject credentials and construct live objects
cred, _ := credStore.Get(cfg.Models.Default.Service)
cfg.Models.Default.APIKey = cred.APIKey
defaultModel, _ := llm.New(cfg.Models.Default)

supervisorCred, _ := credStore.Get(cfg.Models.Supervisor.Service)
cfg.Models.Supervisor.APIKey = supervisorCred.APIKey
supervisorModel, _ := llm.New(cfg.Models.Supervisor)

profiles := make(map[string]llm.Model, len(spec.Profiles()))
for _, name := range spec.Profiles() {
    pcfg := cfg.Models.Profiles[name]
    pc, _ := credStore.Get(pcfg.Service)
    pcfg.APIKey = pc.APIKey
    profiles[name], _ = llm.New(pcfg)
}

mgr := mcp.NewManager()
for name, srv := range cfg.MCP.Stdio {
    client, _ := mcp.Stdio(ctx, srv)
    mgr.Register(name, client)
}
for name, srv := range cfg.MCP.HTTP {
    client, _ := mcp.HTTP(ctx, srv)
    mgr.Register(name, client)
}

skillRoots := make([]*os.Root, len(cfg.Skills))
for i, p := range cfg.Skills {
    skillRoots[i], _ = os.OpenRoot(p)
}

Implementing your own discovery (application concern)

config is a kit — it provides composable primitives. Discovery of which files to load (filesystem hierarchy, env vars, command-line flags) is the application's concern. Here is one typical implementation an application might write:

// In your application — NOT in agentcore/config.
// Uses environment variable, project file, and user-global fallback
// to replicate Git-style config layering.
func loadAgentConfig() (config.Config, error) {
    var sources []config.Source

    // 1. User-global defaults (~/.agent/agent.toml)
    if home, err := os.UserHomeDir(); err == nil {
        sources = append(sources, config.FromFile(
            filepath.Join(home, ".agent", "agent.toml"),
        ))
    }

    // 2. Project-level overrides (./agent.toml)
    sources = append(sources, config.FromFile("agent.toml"))

    // 3. Explicit override via environment variable
    if v := os.Getenv("AGENT_CONFIG"); v != "" {
        sources = append(sources, config.FromFile(v))
    }

    return config.NewUnion(sources...).Get()
}

Other applications might use a --config flag, walk up the directory tree, or fetch configuration from a remote store by implementing the Source interface:

type remoteSource struct{ url string }

func (r remoteSource) Get() (config.Config, error) {
    // fetch from URL, unmarshal, return config.Config
}

cfg, err := config.NewUnion(
    config.FromFile("./agent.toml"),
    remoteSource{url: "https://config.internal/agent"},
).Get()

agent.toml reference


# skills must appear before any [section] headers (TOML table scope rule)
skills = ["./skills", "~/.agent/skills"]

[security]
level = "default"   # "default" | "paranoid" | "research"; fallback when Agentfile has no SECURITY directive
# scope = "..."     # required when level = "research"

[model]
service = "anthropic"       # required
model = "claude-opus-4-7"   # required
max_tokens = 8192
base_url = ""               # optional; empty = provider default
max_retries = 3
max_backoff = "30s"
init_backoff = "1s"

[model.thinking]
level = "auto"              # "auto" | "off" | "low" | "medium" | "high"
budget_tokens = 5000

[supervisor]
service = "anthropic"
model = "claude-opus-4-7"
# Absent → Models.Supervisor defaults to Models.Default after merge.
# Retry fields same as [model]; each model tunes independently.

[profiles.reasoning-heavy]
service = "anthropic"
model = "claude-opus-4-7"
max_tokens = 8192
max_retries = 5

[profiles.fast]
service = "anthropic"
model = "claude-haiku-4-5-20251001"

# MCP servers — transport determined by which field is set.
# Set command OR endpoint, not both.
[mcp.filesystem]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
# env = { KEY = "value" }

[mcp.remote-tools]
endpoint = "https://tools.example.internal/mcp"

Merge semantics

When using NewUnion or Merge:

Field Rule
Name, Security.Level Right (higher-priority) source wins when non-empty
Models.Default, Models.Supervisor Right source wins when Service is non-empty
Models.Profiles Union; right source wins on name collision
MCP.Stdio, MCP.HTTP Union; right source wins on name collision
Skills Union with right source's paths first (shadow precedence)
Supervisor default Applied after merge: if Models.Supervisor.Service == "", uses Models.Default

Documentation

Overview

Package config loads agent.toml into a typed Config.

The package follows the same composable-primitives pattern as agentkit/credentials and agentkit/policy: individual sources are constructed explicitly, and the caller assembles layers when needed. No discovery logic lives here — that belongs in the consuming application.

Core API:

cfg, err := config.FromFile("agent.toml").Get()

cfg, err := config.NewUnion(
    config.FromFile("~/.agent/agent.toml"),
    config.FromFile("./agent.toml"),
).Get()

Credentials are not in agent.toml. Inject APIKey from your credential store into each llm.Config before calling llm.New:

cred, _ := credStore.Get(cfg.Models.Default.Service)
cfg.Models.Default.APIKey = cred.APIKey
model, err := llm.New(cfg.Models.Default)

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("config: not found")

ErrNotFound is returned by a Source when the underlying config file does not exist. NewUnion silently skips sources that return this error.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Models holds all LLM configurations: the default, supervisor, and
	// named profiles. Inject APIKey from credentials before calling llm.New.
	Models Models

	// MCP holds configured MCP servers grouped by transport type.
	MCP MCPServers

	// Skills are directories searched for skill bundles. The caller opens
	// each path as an *os.Root before passing them to agentfile.Config.Skills.
	Skills []string

	// Security is the fallback content-guard configuration used when the
	// Agentfile has no SECURITY directive.
	Security Security
}

Config holds the parsed contents of agent.toml as ready-to-wire agentkit types. Fields with empty/zero values were absent from the source file(s).

agent.toml is runtime configuration (models, MCP, security, skills). Workflow identity — name, inputs, goals — belongs in the Agentfile.

func Merge

func Merge(base, override Config) Config

Merge returns base with override applied. Fields in override take precedence when non-zero; zero values leave the base field unchanged.

Models.Profiles and MCP maps are unioned: override entries win on name collision. Skills are concatenated with override paths first so higher-priority skills shadow lower-priority ones on bare-name lookup.

The supervisor default (Models.Supervisor → Models.Default when unset) is applied after merging so it reflects the merged Default, not either layer's individual Default.

type MCPServers

type MCPServers struct {
	Stdio map[string]mcp.ServerConfig
	HTTP  map[string]mcp.HTTPConfig
}

MCPServers groups MCP server configs by transport. The MCP spec treats stdio and HTTP as distinct transports with separate configuration shapes.

type Models

type Models struct {
	// Default is the primary model for the workflow.
	Default llm.Config

	// Supervisor is the model for the supervision layer. Defaults to Default
	// when no [supervisor] section is present in agent.toml.
	Supervisor llm.Config

	// Profiles maps REQUIRES profile names to their LLM configurations.
	Profiles map[string]llm.Config
}

Models holds all LLM model configurations for a workflow.

type Security

type Security struct {
	// Level is the inspection regime: "default" (cheap heuristics on triggers),
	// "paranoid" (full inspection on every tool call), or "research" (full
	// inspection + permitted scope). Empty means use the Agentfile's own
	// SECURITY directive, or "default" if the Agentfile has none.
	Level string

	// Scope describes permitted operations for the "research" level.
	// Must be non-empty when Level is "research".
	Scope string
}

Security describes the content-guard posture for the workflow. Level selects the inspection regime; Scope is required only for the research level and declares the boundary within which security-sensitive operations are permitted.

type Source

type Source interface {
	Get() (Config, error)
}

Source provides configuration. Use FromFile to construct file-backed sources and NewUnion to layer multiple sources.

func FromFile

func FromFile(path string) Source

FromFile returns a Source backed by the file at path. Get() returns ErrNotFound when the file does not exist.

func NewUnion

func NewUnion(sources ...Source) Source

NewUnion returns a Source that merges sources in left-to-right priority order (right-most source wins). Sources that return ErrNotFound are silently skipped. Any other error aborts Get().

Jump to

Keyboard shortcuts

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