config

package
v0.3.0 Latest Latest
Warning

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

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

Documentation

Overview

Package config loads and resolves the on-disk configuration of baifo. See .agents/AGENTS.md and .agents/CONFIG.md for the full reference.

Index

Constants

View Source
const (
	RetryStrategyBackoff    = "backoff"
	RetryStrategyRetryAfter = "retry-after"
)

Retry strategy identifiers for RetryConfig.Strategy.

View Source
const (
	DefaultRetryMaxAttempts    = 4
	DefaultRetryInitialBackoff = time.Second
	DefaultRetryMaxBackoff     = 30 * time.Second
	DefaultRetryMultiplier     = 2.0
	DefaultRetryStrategy       = RetryStrategyBackoff
)

Retry policy defaults. Exposed as constants so the decorator and the config accessors agree on the same numbers.

View Source
const (
	// DefaultLimitExecOutputChars is the default per-stream (stdout / stderr)
	// character cap applied to the exec and process_status tools.
	DefaultLimitExecOutputChars = 48000

	// DefaultLimitReadFileChars is the default total-character cap applied to
	// a single read_file call across all its fragments.
	DefaultLimitReadFileChars = 120000

	// DefaultLimitSearchOutputChars is the default total-character cap applied
	// to a single search call across all its matches and their context.
	DefaultLimitSearchOutputChars = 50000
)

Output-cap defaults for the built-in filesystem MCP. These are the values returned by EffectiveExecOutputChars and EffectiveReadFileChars when the operator did not set a field explicitly (0 / absent).

View Source
const (
	MCPRegistrationAuto = "auto"
	MCPRegistrationCIMD = "cimd"
	MCPRegistrationDCR  = "dcr"
)

MCP OAuth client-registration mode constants.

View Source
const (
	MCPAuthKindNone  = "none"
	MCPAuthKindOAuth = "oauth"
)

MCP auth kind constants.

View Source
const (
	SpawnModeNone    = "none"
	SpawnModeStatic  = "static"
	SpawnModeDynamic = "dynamic"
	SpawnModeBoth    = "both"
)

Spawn mode constants.

View Source
const AgentsFileName = "agents.yaml"

AgentsFileName is the canonical name of the static-worker templates file inside .baifo/.

View Source
const DefaultTrimOversizedUserTextMaxChars = 30000

DefaultTrimOversizedUserTextMaxChars is the per-part character cap used when MaxChars is 0 (absent / unset). Value: 30000.

View Source
const FileName = "baifo.yaml"

FileName is the canonical filename of the main config inside .baifo/.

Variables

View Source
var ErrDirNotFound = errors.New(".baifo directory not found")

ErrDirNotFound is returned by DiscoverDir when no .baifo/ directory can be located using the resolution rules. Callers should treat it as the trigger for first-run initialisation.

Functions

func AgentsFilePath

func AgentsFilePath(dir string) string

AgentsFilePath returns the absolute path of agents.yaml inside dir.

func DefaultDir

func DefaultDir() (string, error)

DefaultDir returns the path of the .baifo directory that the first-run wizard should create when no config is found anywhere.

func DiscoverDir

func DiscoverDir(flagDir string) (string, error)

DiscoverDir locates the .baifo/ configuration directory according to the priority order documented in DECISIONS.md #1:

  1. flagDir (--config-dir), if non-empty
  2. $BAIFO_HOME
  3. $PWD/.baifo/, walking up the tree
  4. $XDG_CONFIG_HOME/baifo/
  5. $HOME/.baifo/

The first hit wins. Returns ErrDirNotFound when nothing matches.

func FilePath

func FilePath(dir string) string

FilePath returns the absolute path of baifo.yaml inside dir.

func ValidateAgents

func ValidateAgents(agents []AgentTemplate) error

ValidateAgents is the exported wrapper around validateAgents so other packages (notably internal/app) can run the same schema rules without going through LoadAgents and disk I/O.

Types

type A2AConfig

type A2AConfig struct {
	Enabled   bool   `yaml:"enabled"`
	Host      string `yaml:"host"`
	Port      int    `yaml:"port"`
	PublicURL string `yaml:"public_url"`

	// Credentials gates incoming A2A requests. When empty the server
	// is unauthenticated (the historical behaviour); when a token is
	// set, every request must present it as a bearer token.
	Credentials A2ACredentials `yaml:"credentials"`
}

A2AConfig describes the A2A server endpoint.

type A2ACredentials

type A2ACredentials struct {
	// Token is the expected bearer credential. A literal string is
	// used verbatim; a ${secret:NAME} placeholder is expanded from
	// the secrets store at boot so the token never lives in
	// baifo.yaml in plaintext. Empty disables authentication.
	Token string `yaml:"token"`
}

A2ACredentials carries the optional bearer token that protects the A2A endpoints. Auth is opt-in: set Token to turn it on, leave it empty to serve without authentication.

type AgentLLM

type AgentLLM struct {
	Provider string `yaml:"provider"`
	Model    string `yaml:"model"`

	// Reasoning is the optional reasoning-effort knob for models that
	// support it: one of "minimal" / "low" / "medium" / "high" (empty
	// or "off" leaves the model's own default). Use list_models to see
	// which models accept reasoning and at which levels. Applied to
	// openai (reasoning_effort), gemini (thinking) and anthropic
	// (extended-thinking budget).
	Reasoning string `yaml:"reasoning"`

	// ReasoningAPI optionally overrides which Anthropic reasoning API the
	// model uses: "enabled" (classic budget-based, for Claude 3.7 /
	// Sonnet 4 / Opus 4) or "adaptive" (effort-based, for Opus 4.5+).
	// Empty auto-detects from the catalogue. Only anthropic uses it;
	// other providers ignore it.
	// Ref: https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
	ReasoningAPI string `yaml:"reasoning_api"`
}

AgentLLM mirrors LLMRef and defines the provider and model settings. The effective value is exposed via the Provider accessor.

func (AgentLLM) Effective

func (l AgentLLM) Effective() string

Effective returns the provider name.

type AgentTemplate

type AgentTemplate struct {
	// Root marks the always-on entry-point agent. Exactly one
	// entry in agents.yaml must set this to true; the loader
	// rejects zero and more-than-one root setups. The flagged
	// agent receives the spawn / memory / todos tools and a
	// secrets allower of AllowAll regardless of AllowedSecrets;
	// all other entries are treated as ordinary spawnable
	// sub-agents.
	Root bool `yaml:"root,omitempty"`

	// Utility marks the background utility agent: the cheap model
	// baifo uses for internal chores that don't deserve the root's
	// (usually expensive) model — today, titling sessions and
	// summarising conversations for context-window compaction. At
	// most one entry may set it; when none does, those chores fall
	// back to the root's LLM. The utility agent never chats, never
	// receives tools and is not spawnable — only its llm block is
	// consumed.
	Utility bool `yaml:"utility,omitempty"`

	Name           string             `yaml:"name"`
	Description    string             `yaml:"description"`
	Prompt         string             `yaml:"prompt"`
	LLM            AgentLLM           `yaml:"llm"`
	Skills         []string           `yaml:"skills"`
	MCPs           []string           `yaml:"mcps"`
	ContextGuard   ContextGuardConfig `yaml:"context_guard"`
	AllowedSecrets []string           `yaml:"allowed_secrets"`
}

AgentTemplate is the on-disk definition of one agent in agents.yaml. Both the root agent (the one the user talks to in the TUI / over A2A) and the spawnable sub-agents share this shape. The single distinguishing flag is Root.

Field names follow CONFIG.md > agents.yaml. The LLM section uses `provider` (the baifo term, see Phase 2).

type AgentsFile

type AgentsFile struct {
	Version int             `yaml:"version"`
	Agents  []AgentTemplate `yaml:"agents"`
}

AgentsFile is the root of agents.yaml.

func LoadAgents

func LoadAgents(path string) (*AgentsFile, error)

LoadAgents reads and parses agents.yaml from path. Environment variables are expanded before parsing. A missing file yields an empty list (not an error) so installations without static workers boot cleanly.

func (*AgentsFile) RootAgent

func (f *AgentsFile) RootAgent() *AgentTemplate

RootAgent returns a pointer to the entry flagged with root: true, or nil if the file has no agents at all (a fresh install before the wizard ran). Callers should treat a nil return as ErrNoRoot equivalent.

The loader's exactly-one-root validation guarantees that when the slice is non-empty there is exactly one matching entry, so we can stop at the first hit.

func (*AgentsFile) SubAgents

func (f *AgentsFile) SubAgents() []AgentTemplate

SubAgents returns the entries that are NOT the root, in the same order they appear on disk. Useful for the spawn-tools machinery and for listing what the user can /agents talk to.

func (*AgentsFile) UtilityAgent

func (f *AgentsFile) UtilityAgent() *AgentTemplate

UtilityAgent returns a pointer to the entry flagged utility: true, or nil when no entry opts in. Callers must treat nil (and an entry with an unset llm) as "fall back to the root's LLM" — the utility agent is an optional cost optimisation, never a requirement.

type BackoffConfig

type BackoffConfig struct {
	// Initial is the wait before the first retry (a duration string
	// like "1s", "500ms"). Subsequent waits grow by Multiplier.
	Initial string `yaml:"initial"`

	// Max caps how long a single wait can grow to, so the exponential
	// growth does not blow up to minutes. Duration string.
	Max string `yaml:"max"`

	// Multiplier is the exponential growth factor between attempts.
	// Values <= 1 fall back to the default so the backoff still grows.
	Multiplier float64 `yaml:"multiplier"`

	// Jitter, when true, randomises each wait in the range
	// [delay/2, delay] to avoid synchronised retry storms across
	// concurrent workers. Default true.
	Jitter *bool `yaml:"jitter"`
}

BackoffConfig groups the exponential-backoff tunables under the retry.backoff block. The delay before retry N is:

delay = min(Initial * Multiplier^(N-1), Max)

optionally jittered.

type Config

type Config struct {
	Version       int              `yaml:"version"`
	EncryptionKey string           `yaml:"encryption_key"`
	Runtime       RuntimeConfig    `yaml:"runtime"`
	Guardrails    GuardrailsConfig `yaml:"guardrails"`
	Theme         ThemeConfig      `yaml:"theme"`
	A2A           A2AConfig        `yaml:"a2a"`
	Providers     []ProviderEntry  `yaml:"providers"`
	MCPs          []MCPEntry       `yaml:"mcps"`
	Spawn         SpawnConfig      `yaml:"spawn"`
	Secrets       SecretsConfig    `yaml:"secrets"`
}

Config is the root of baifo.yaml.

func Default

func Default() *Config

Default returns a Config populated with sane defaults.

func Load

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

Load reads baifo.yaml from path. Environment variables are expanded before parsing. A missing file yields the default configuration so the rest of the program can run on a fresh install.

type ContextGuardConfig

type ContextGuardConfig struct {
	Enabled   bool   `yaml:"enabled"`
	Strategy  string `yaml:"strategy"`
	MaxTokens int    `yaml:"max_tokens"`
	MaxTurns  int    `yaml:"max_turns"`
}

ContextGuardConfig wires the adk-utils-go context guard.

type GuardrailsConfig

type GuardrailsConfig struct {
	// TrimOversizedUserText truncates oversized user-role text parts
	// in the request sent to the model. "User text" covers more than
	// what the human types: when a session is resumed under a different
	// agent name, the ADK injects the old transcript (tool dumps
	// included) AS user-role text ("For context: [agent] ..."), which
	// can flood the context window. Model turns and native tool-result
	// blocks are never touched. The trim is ephemeral per-request; the
	// stored session keeps full fidelity.
	TrimOversizedUserText TrimOversizedUserTextConfig `yaml:"trim_oversized_user_text"`
}

GuardrailsConfig groups the optional protections baifo can apply around the model call. Each guardrail is independently toggleable and names the threat it mitigates. Guardrails are OPT-IN: every sub-block defaults to disabled when absent, because they may alter what the user's own content looks like to the model and that must never happen silently. (Producer-side caps — mcps[].options limit_* — are the always-on layer instead: they only bound tool outputs, which the model knows how to re-fetch.)

type MCPAuth

type MCPAuth struct {
	// Kind selects the auth mechanism: "none" (default), "oauth".
	Kind string `yaml:"kind"`

	// ClientID is the OAuth client identifier. Optional; empty enables
	// CIMD/DCR discovery on first authenticate.
	ClientID string `yaml:"client_id"`

	// ClientSecretRef is the name of an entry in secrets.yaml whose
	// value is the OAuth client secret. Never the secret itself.
	ClientSecretRef string `yaml:"client_secret_ref"`

	// Registration selects how baifo obtains an OAuth client when no
	// pre-registered ClientID is set. One of:
	//
	//   - "auto" (default): advertise both CIMD (Client ID Metadata
	//     Document) and DCR (RFC 7591). The MCP SDK prefers CIMD when
	//     the authorization server announces support for it, otherwise
	//     it registers dynamically.
	//   - "cimd": advertise ONLY CIMD. Use when you know the AS
	//     supports it and want to avoid creating a DCR client.
	//   - "dcr": advertise ONLY DCR. Use this when the AS announces
	//     CIMD support but rejects our client_id URL (e.g. the domain
	//     is not whitelisted in the IdP), which would otherwise make
	//     the SDK pick CIMD and fail without falling back.
	//
	// Ignored when ClientID/ClientSecretRef are set (those force the
	// client_credentials grant).
	Registration string `yaml:"registration"`
}

MCPAuth describes how baifo authenticates against an HTTP MCP. The zero value means no authentication. For oauth, leaving ClientID and ClientSecretRef empty opts into discovery: baifo first tries CIMD (its hardcoded Client ID Metadata Document URL) and falls back to Dynamic Client Registration (RFC 7591) if CIMD is not supported by the authorization server. When ClientID/ClientSecretRef are set, the OAuth client_credentials flow is used directly.

Scopes are NOT modelled here on purpose: they are discovered at authentication time from the protected resource metadata (RFC 9728, /.well-known/oauth-protected-resource).

func (MCPAuth) EffectiveKind

func (a MCPAuth) EffectiveKind() string

EffectiveKind returns the auth kind with the documented default ("none") applied when the user left it blank.

func (MCPAuth) EffectiveRegistration

func (a MCPAuth) EffectiveRegistration() string

EffectiveRegistration returns the registration mode with the documented default ("auto") applied when the user left it blank.

func (MCPAuth) UsesDiscovery

func (a MCPAuth) UsesDiscovery() bool

UsesDiscovery reports whether this OAuth entry should try CIMD/DCR instead of using statically configured credentials. It returns true only for oauth entries with both ClientID and ClientSecretRef empty; anything else is treated as a pre-registered client.

type MCPEntry

type MCPEntry struct {
	Name string `yaml:"name"`
	Type string `yaml:"type"`

	// builtin
	Builtin string `yaml:"builtin"`

	// http
	Endpoint string            `yaml:"endpoint"`
	Headers  map[string]string `yaml:"headers"`
	Insecure bool              `yaml:"insecure"`

	// stdio
	Command string            `yaml:"command"`
	Args    []string          `yaml:"args"`
	Env     map[string]string `yaml:"env"`
	Workdir string            `yaml:"workdir"`

	// Auth holds the optional authentication block. When absent or with
	// kind=none, the MCP is treated as unauthenticated (Headers may still
	// carry static tokens — they are orthogonal to auth.kind).
	Auth MCPAuth `yaml:"auth"`

	// Options carries per-entry tuning for builtin MCPs. Flat by design:
	// option keys are prefixed by category (limit_*) instead of nested,
	// so the block stays one level deep and easy to autocomplete. Only
	// meaningful for type=builtin (each builtin reads the keys it knows;
	// unknown-to-that-builtin keys are ignored).
	Options MCPOptions `yaml:"options"`
}

MCPEntry is one MCP server declaration. Built-in MCPs use Type=builtin and a Builtin slug; HTTP and stdio MCPs use the corresponding fields.

type MCPOptions

type MCPOptions struct {
	// LimitExecOutputChars caps stdout and stderr (each, separately)
	// returned by the exec and process_status tools of the builtin
	// filesystem MCP. 0 = default (48000). -1 = unlimited.
	LimitExecOutputChars int `yaml:"limit_exec_output_chars"`

	// LimitReadFileChars caps the total content returned by a single
	// read_file call of the builtin filesystem MCP. 0 = default
	// (120000). -1 = unlimited.
	LimitReadFileChars int `yaml:"limit_read_file_chars"`

	// LimitSearchOutputChars caps the total content (matched lines plus
	// their context) returned by a single search call of the builtin
	// filesystem MCP. Independent of max_results, which only bounds the
	// number of matches, not their size. 0 = default (50000).
	// -1 = unlimited.
	LimitSearchOutputChars int `yaml:"limit_search_output_chars"`
}

MCPOptions is the flat option set for builtin MCPs. The limit_* fields follow a three-state convention: 0 / absent = built-in default, positive = explicit cap in characters, -1 = unlimited (no cap). Disabling a single limit is done with -1; there is no per-option enabled flag (unlike guardrails) because granularity here is per-field.

func (MCPOptions) EffectiveExecOutputChars

func (o MCPOptions) EffectiveExecOutputChars() int

EffectiveExecOutputChars returns the resolved stdout/stderr cap:

  • 0 (absent/unset) → DefaultLimitExecOutputChars
  • negative → 0, meaning unlimited
  • positive → the value as-is

func (MCPOptions) EffectiveReadFileChars

func (o MCPOptions) EffectiveReadFileChars() int

EffectiveReadFileChars returns the resolved read_file total-output cap:

  • 0 (absent/unset) → DefaultLimitReadFileChars
  • negative → 0, meaning unlimited
  • positive → the value as-is

func (MCPOptions) EffectiveSearchOutputChars added in v0.2.0

func (o MCPOptions) EffectiveSearchOutputChars() int

EffectiveSearchOutputChars returns the resolved search total-output cap:

  • 0 (absent/unset): DefaultLimitSearchOutputChars
  • negative: 0, meaning unlimited
  • positive: the value as-is

type ProviderEntry

type ProviderEntry struct {
	Name    string            `yaml:"name"`
	Type    string            `yaml:"type"`
	URL     string            `yaml:"url"`
	Auth    string            `yaml:"auth"` // "api_key" (default) | "oauth"
	APIKey  string            `yaml:"api_key"`
	Headers map[string]string `yaml:"headers"`

	// Streaming controls whether agents backed by this provider run
	// in SSE streaming mode. A pointer so an omitted field means "use
	// the default" (streaming ON) rather than the zero value. Set it
	// to false only for OpenAI-compatible endpoints that do not
	// implement Server-Sent Events; those reject a streaming request
	// or hang. Streaming is required for long Anthropic turns (the API
	// refuses non-streamed responses that may exceed 10 minutes, which
	// high reasoning budgets can), so leave it on for Anthropic.
	Streaming *bool `yaml:"streaming"`
}

ProviderEntry is one LLM provider declaration. Reference by `Name` from root.llm and agent specs.

func (ProviderEntry) StreamingEnabled

func (p ProviderEntry) StreamingEnabled() bool

StreamingEnabled reports the resolved streaming setting: true unless the operator explicitly set streaming: false. Centralised so every consumer agrees on the default.

type RetryConfig

type RetryConfig struct {
	// Enabled turns retries on. Default false (no retries) when the
	// whole block is absent; the loader flips it on when the user
	// provides any retry field, so writing a block implies intent.
	Enabled *bool `yaml:"enabled"`

	// MaxAttempts is the TOTAL number of tries, including the first.
	// 1 means "no retry". Values < 1 are treated as the default.
	MaxAttempts int `yaml:"max_attempts"`

	// Strategy selects how the wait before each retry is computed:
	//
	//   "backoff"      exponential backoff from the Backoff block (default).
	//   "retry-after"  honour the provider's Retry-After header when the
	//                  failure carries one (e.g. a 429 rate limit), and
	//                  fall back to the exponential backoff otherwise.
	Strategy string `yaml:"strategy"`

	// Backoff holds the exponential-backoff knobs. They drive the
	// "backoff" strategy and act as the fallback for "retry-after"
	// when no header is present.
	Backoff BackoffConfig `yaml:"backoff"`
}

RetryConfig describes the exponential-backoff retry policy applied to every LLM provider call. The delay before attempt N is:

delay = min(InitialBackoff * Multiplier^(N-1), MaxBackoff)

optionally jittered. With MaxAttempts=4, InitialBackoff=1s and Multiplier=2 the waits are roughly 1s, 2s, 4s before giving up — so a flaky provider gets several escalating chances before the turn fails.

func (RetryConfig) Attempts

func (r RetryConfig) Attempts() int

Attempts returns the effective total attempt count, applying the default and a floor of 1.

func (RetryConfig) InitialBackoffDuration

func (r RetryConfig) InitialBackoffDuration() time.Duration

InitialBackoffDuration parses the backoff initial wait, falling back to the default on empty or invalid input.

func (RetryConfig) JitterEnabled

func (r RetryConfig) JitterEnabled() bool

JitterEnabled returns the effective jitter flag, defaulting to true.

func (RetryConfig) MaxBackoffDuration

func (r RetryConfig) MaxBackoffDuration() time.Duration

MaxBackoffDuration parses the backoff cap, falling back to the default.

func (RetryConfig) MultiplierOr

func (r RetryConfig) MultiplierOr() float64

MultiplierOr returns the effective multiplier, applying the default when the configured value would not grow the backoff (<= 1).

func (RetryConfig) RetryEnabled

func (r RetryConfig) RetryEnabled() bool

RetryEnabled reports whether retries are on. A wholly-absent block is off; an explicit enabled flag wins; otherwise providing any field implies the user wants retries.

func (RetryConfig) StrategyOr

func (r RetryConfig) StrategyOr() string

StrategyOr returns the effective retry strategy, normalising the input and falling back to the default on empty or unknown values.

type RuntimeConfig

type RuntimeConfig struct {
	LogLevel              string `yaml:"log_level"`
	LogFormat             string `yaml:"log_format"`
	LogFile               string `yaml:"log_file"`
	RedactLogs            *bool  `yaml:"redact_logs"`
	AutoResumeSession     *bool  `yaml:"auto_resume_session"`
	ChatAutoScroll        *bool  `yaml:"chat_auto_scroll"`
	ChatKeepToolsExpanded *bool  `yaml:"chat_keep_tools_expanded"`

	// Retry controls how baifo retries failing LLM provider API calls
	// (rate limits, overloads, transient network errors) with an
	// incremental exponential backoff. Absent / disabled means no
	// retries (the historical behaviour).
	Retry RetryConfig `yaml:"retry"`
}

RuntimeConfig groups process-level knobs.

func (RuntimeConfig) AutoResumeSessionEnabled

func (r RuntimeConfig) AutoResumeSessionEnabled() bool

AutoResumeSessionEnabled returns the effective value of AutoResumeSession, defaulting to true when the field is absent.

func (RuntimeConfig) ChatAutoScrollEnabled

func (r RuntimeConfig) ChatAutoScrollEnabled() bool

ChatAutoScrollEnabled returns the effective value of ChatAutoScroll, defaulting to true when the field is absent. The TUI calls this to decide whether new events should pin the chat viewport to the bottom.

func (RuntimeConfig) ChatKeepToolsExpandedEnabled

func (r RuntimeConfig) ChatKeepToolsExpandedEnabled() bool

ChatKeepToolsExpandedEnabled returns the effective value of ChatKeepToolsExpanded, defaulting to false when the field is absent.

func (RuntimeConfig) RedactLogsEnabled

func (r RuntimeConfig) RedactLogsEnabled() bool

RedactLogsEnabled returns the effective value of RedactLogs, defaulting to true when the field is absent.

type SecretsConfig

type SecretsConfig struct {
	RedactInLogs *bool `yaml:"redact_in_logs"`
	RedactInTUI  *bool `yaml:"redact_in_tui"`

	// ScrubToolResults toggles the comprehensive-redaction pass that
	// runs after every tool call. The targeted pass (scrubbing the
	// raw values the BeforeToolCallback just substituted) is always
	// on; this knob controls the *additional* sweep that scans the
	// result for ANY value currently in `secrets.yaml`, even ones
	// the model never asked for.
	//
	// Recommended: leave it on. It defends against the "tools that
	// emit secrets they were not given" class of leak — e.g. an MCP
	// echoing a debug header that happens to contain the value of a
	// secret stored under a different name. The cost is a small
	// number of substring scans per tool call; for typical
	// deployments (a few dozen secrets, tool results under a few
	// hundred KB) it adds milliseconds.
	//
	// Default when omitted: true.
	ScrubToolResults *bool `yaml:"scrub_tool_results"`

	// MinScrubLength is the minimum length (in bytes) a stored
	// secret value must have to be eligible for the comprehensive
	// pass. Below this floor the value is skipped to avoid
	// catastrophic false positives — e.g. a secret stored with
	// value "1234" would otherwise redact every "1234" anywhere in
	// any tool result, mangling file contents, JSON numbers, port
	// numbers, you name it.
	//
	// Choose a floor high enough that legitimate substrings of that
	// length almost never appear by accident in tool output, but
	// not so high that real, short secrets stop being protected.
	// The trade-off is direct: HIGHER values → FEWER false
	// positives but MORE secrets bypassed; LOWER values → MORE
	// values protected but MORE chance of redacting unrelated text.
	//
	// Reference points:
	//   -  8 bytes (default) — protects every API key worth
	//      protecting; lets values up to 7 bytes (PINs, short
	//      passwords) escape the comprehensive pass.
	//   - 12 bytes — most modern API keys fit (`ghp_*`, `sk-*`,
	//      `AKIA…`). Short personal secrets are filtered out.
	//   - 16 bytes — only long, high-entropy values are scanned.
	//
	// Short secrets (below the floor) remain protected by the
	// targeted pass when the LLM explicitly references them via
	// `${secret:NAME}`. Only the "leaked from nowhere" scenario is
	// excluded for those values — which is generally acceptable
	// because short, low-entropy secrets are not the threat model
	// the comprehensive pass exists for.
	//
	// 0 or negative disables the floor entirely (every length is
	// scrubbed). Documented as dangerous and not recommended.
	//
	// Default when omitted: 8.
	MinScrubLength *int `yaml:"min_scrub_length"`
}

SecretsConfig groups runtime behaviour of the secrets pipeline.

func (SecretsConfig) EffectiveMinScrubLength

func (c SecretsConfig) EffectiveMinScrubLength() int

EffectiveMinScrubLength returns the effective value of MinScrubLength, defaulting to 8 when the field is absent. The default balances real API keys (always 16+ bytes) against accidental matches on short values. Values below 8 are accepted but documented as dangerous because they raise the false-positive rate sharply.

func (SecretsConfig) LogRedactionEnabled

func (c SecretsConfig) LogRedactionEnabled() bool

LogRedactionEnabled returns the effective value of RedactInLogs, defaulting to true when the field is absent.

func (SecretsConfig) ScrubToolResultsEnabled

func (c SecretsConfig) ScrubToolResultsEnabled() bool

ScrubToolResultsEnabled returns the effective value of ScrubToolResults, defaulting to true when the field is absent. Defense in depth is the right default; operators opt out explicitly when a debugging session needs raw output.

func (SecretsConfig) TUIRedactionEnabled

func (c SecretsConfig) TUIRedactionEnabled() bool

TUIRedactionEnabled returns the effective value of RedactInTUI, defaulting to true when the field is absent.

type SpawnConfig

type SpawnConfig struct {
	Mode           string        `yaml:"mode"`
	CollectTimeout time.Duration `yaml:"collect_timeout"`
}

SpawnConfig governs which spawn tools the root agent receives. mode is one of: none, static, dynamic, both. See DECISIONS.md #6.

func (SpawnConfig) DynamicEnabled

func (s SpawnConfig) DynamicEnabled() bool

DynamicEnabled reports whether the root should receive the dynamic spawn tools ("dynamic" or "both"). Dynamic tools land in Phase 6; the helper is exposed already so the wiring is symmetric.

func (SpawnConfig) EffectiveMode

func (s SpawnConfig) EffectiveMode() string

EffectiveMode returns the spawn mode with the documented default ("both") applied when the user did not set one.

func (SpawnConfig) StaticEnabled

func (s SpawnConfig) StaticEnabled() bool

StaticEnabled reports whether the root should receive the static spawn / supervise tools ("static" or "both").

type ThemeConfig

type ThemeConfig struct {
	NerdFonts bool `yaml:"nerd_fonts"`
}

ThemeConfig controls terminal-capability rendering options. The colour palette itself is fixed (the Canarias theme) and is NOT user-configurable; the only knob here is whether the terminal can render Nerd Font glyphs.

type TrimOversizedUserTextConfig

type TrimOversizedUserTextConfig struct {
	// Enabled toggles this guardrail. Default FALSE when absent:
	// guardrails are opt-in (pointer-bool kept for symmetry with the
	// rest of the config and so an explicit `enabled: false` is
	// distinguishable from an absent block in future migrations).
	Enabled *bool `yaml:"enabled"`

	// MaxChars caps each user-role text part, in characters.
	// 0 / absent = default (DefaultTrimOversizedUserTextMaxChars).
	// Positive = explicit cap.
	// Disabling is done via enabled: false, not via this field.
	MaxChars int `yaml:"max_chars"`
}

TrimOversizedUserTextConfig controls the guardrail that caps oversized user-role text parts before each model call.

func (TrimOversizedUserTextConfig) EffectiveCap

func (c TrimOversizedUserTextConfig) EffectiveCap() int

EffectiveCap returns 0 when the guardrail is disabled (IsEnabled()==false), and EffectiveMaxChars() otherwise. Callers can pass the single returned int to BuildContextTrimPlugin: 0 disables the plugin, positive caps it.

func (TrimOversizedUserTextConfig) EffectiveMaxChars

func (c TrimOversizedUserTextConfig) EffectiveMaxChars() int

EffectiveMaxChars returns the resolved per-part cap:

  • 0 / absent (unset) → DefaultTrimOversizedUserTextMaxChars
  • negative → DefaultTrimOversizedUserTextMaxChars (negative no longer means disabled; use enabled: false for that)
  • positive → the value as-is

func (TrimOversizedUserTextConfig) IsEnabled

func (c TrimOversizedUserTextConfig) IsEnabled() bool

IsEnabled reports whether the trim_oversized_user_text guardrail is active. The default (nil Enabled pointer) is FALSE — guardrails are opt-in; the operator turns this one on with enabled: true.

Directories

Path Synopsis
Package yamledit provides comment-preserving edits to baifo.yaml.
Package yamledit provides comment-preserving edits to baifo.yaml.

Jump to

Keyboard shortcuts

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