Skip to the content.

ADR-008: Functional Options Pattern for Agents

Status: Accepted
Date: 2026-05-09

Context

Each of Embercore’s five agents requires configuration: which LLM provider to use, which model, whether to use Hestia for persistence, and agent-specific settings. We needed a pattern that is:

Alternatives considered:

  1. Config struct parameterNewApollo(config ApolloConfig). Simple, but adding a field requires updating all callers. Doesn’t distinguish “not set” from “zero value.”
  2. Builder patternNewApollo().WithProvider(p).WithModel(m).Build(). Verbose, requires a separate builder type.
  3. Functional optionsNewApollo(WithProvider(p), WithModel(m)). Extensible, self-documenting, idiomatic Go.

Decision

All agents use the functional options pattern with a consistent set of option functions.

Pattern implementation

Each agent defines an option type and constructor:

// agents/apollo/apollo.go
type Option func(*Apollo)

func WithProvider(p provider.Provider) Option {
    return func(a *Apollo) { a.provider = p }
}

func WithHestia(h *hestia.Hestia) Option {
    return func(a *Apollo) { a.hestia = h }
}

func WithModel(model string) Option {
    return func(a *Apollo) { a.model = model }
}

func New(opts ...Option) *Apollo {
    a := &Apollo{ /* defaults */ }
    for _, opt := range opts {
        opt(a)
    }
    return a
}

Common options across agents

Option Purpose Used by
WithProvider(p) Set the LLM provider All agents that call LLMs
WithHestia(h) Enable persistence Athena, Hermes, Hephaestus, Apollo
WithModel(m) Override the default model Apollo, Hephaestus
WithRunID(id) Associate with a specific run Hephaestus
WithCheckpointHandler(h) Set checkpoint callback Hermes

Agent-specific options

Usage examples

// Minimal — just a provider
athena := athena.New(athena.WithProvider(p))

// Full configuration
hermes := hermes.New(
    hermes.WithProvider(p),
    hermes.WithHestia(h),
    hermes.WithCheckpointHandler(interactiveApproval),
)

// With model override for local provider
apollo := apollo.New(
    apollo.WithProvider(ollamaProvider),
    apollo.WithModel("llama3:70b"),
    apollo.WithHestia(h),
)

Consequences

Benefits:

Trade-offs:

Related decisions: