config

package
v0.2.0-alpha.7 Latest Latest
Warning

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

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

Documentation

Overview

Package config provides configuration loading and defaults.

Index

Constants

View Source
const (
	DefaultMaxParallelTools = 4
	MinMaxParallelTools     = 1
	MaxMaxParallelTools     = 16
)

Parallel tool execution bounds. The ceiling protects file descriptors, memory for large reads, and remote rate limits for WebFetch and MCP; real batches from a model are two to five calls, so the default captures nearly all of the available win while keeping the failure modes boring.

View Source
const (
	DefaultMaxIterations = 200
	MinMaxIterations     = 1
	MaxMaxIterations     = 5000
)

Agent loop iteration bounds. The cap exists so a run that stopped making progress ends instead of spending until the credential does, and 200 covers ordinary interactive work several times over. The ceiling is what a long autonomous task may raise it to: an agent still calling tools after five thousand iterations is looping, not working, and no honest task needs the difference between that and unbounded.

View Source
const (
	// CacheModeAuto asks for the provider's economical default on a call whose
	// prefix will be sent again, and asks for nothing on a one-shot call. It is
	// the default.
	CacheModeAuto = "auto"
	// CacheModeOff never asks, on any call.
	CacheModeOff = "off"
	// CacheModeForce asks on every call, including ones whose prefix nothing
	// will read back. It is for a caller that knows something the runtime
	// cannot see.
	CacheModeForce = "force"
)

Prompt-cache modes. A mode says what to ask a provider for; whether the ask is made on a given call also depends on what that call is for, which travels with the request as a core/llm.CallProfile.

View Source
const (
	// CacheTTLProviderDefault leaves retention to the provider.
	CacheTTLProviderDefault = "provider_default"
	CacheTTL5m              = "5m"
	CacheTTL1h              = "1h"
	CacheTTL24h             = "24h"
)

Prompt-cache retention. A value other than CacheTTLProviderDefault is only valid where the target's protocol documents it; the client refuses the rest rather than sending a field the provider will ignore.

View Source
const (
	// TransportDirect calls an OpenAI-compatible provider from this machine
	// using the entry's own credential. It is the default.
	TransportDirect = "direct"
	// TransportBuildMax calls a BuildMax server's managed gateway, which holds
	// the provider credential and decides which model the team may use.
	TransportBuildMax = "buildmax"
)

LLM connection modes for a model entry.

The two are never mixed and never fall back to one another: a run either calls a provider from this machine or calls a BuildMax deployment, and the user can tell which from the entry. See docs/design/llm-gateway.md.

View Source
const (
	// ReasoningOff does no extra reasoning. It is the default.
	ReasoningOff    = "off"
	ReasoningLow    = "low"
	ReasoningMedium = "medium"
	ReasoningHigh   = "high"
)

Reasoning effort levels. They are a neutral scale: each protocol maps them to its own vocabulary, and a level a model does not support fails that model's call rather than being silently downgraded.

View Source
const (
	ModelGPT35Turbo        = "openai/gpt-3.5-turbo"
	ModelGemma327bItFree   = "google/gemma-3-27b-it:free"
	ModelGLM45AirFree      = "z-ai/glm-4.5-air:free"
	ModelGPT4oMini         = "openai/gpt-4o-mini"
	ModelGemini25FlashLite = "google/gemini-2.5-flash-lite"
	ModelGemini31FlashLite = "google/gemini-3.1-flash-lite"
)

Model names on OpenRouter (switch DefaultModel to use one).

View Source
const (
	// BUILDMAX_HOME — path to the data directory; tells every binary where to find its
	// config files (settings.yaml, server.yaml). Must remain an env var because the
	// config files cannot be located until this path is known.
	EnvKeyBuildmaxHome = "BUILDMAX_HOME"

	// BUILDMAX_SERVER_URL — address this process uses to reach buildmax-server.
	// It overrides settings.yaml server_url for CLI/Desktop and server.yaml
	// worker.server_url for workers, so one deployed image can target a stage or
	// production control plane without rewriting its config file.
	EnvKeyBuildmaxServerURL = "BUILDMAX_SERVER_URL"

	// BUILDMAX_JWT_SECRET — optional override for jwt_secret in server.yaml.
	// In production, inject via env var (Kubernetes Secret, Docker secret) instead of
	// storing the value in the YAML file on disk.
	EnvKeyBuildmaxJWTSecret = "BUILDMAX_JWT_SECRET"

	// BUILDMAX_RUN_TOKEN — the credential one task run presents to the managed LLM
	// gateway. The scheduler mints it per run and puts it in the worker process or
	// Job pod; nothing inherits it, which is why it is not marked WorkerNeeds
	// below. See docs/design/worker-run-token.md.
	EnvKeyBuildmaxRunToken = "BUILDMAX_RUN_TOKEN"

	// BUILDMAX_RUN_INTERRUPT_GRACE — how long a worker asked to stop may spend
	// uploading what its run produced and reporting the outcome. The scheduler
	// sets it from the server's own shutdown budget so the two windows nest;
	// unset, the worker uses its own default. See
	// docs/design/graceful-shutdown.md §6.3.
	EnvKeyBuildmaxRunInterruptGrace = "BUILDMAX_RUN_INTERRUPT_GRACE"

	// BUILDMAX_CREDENTIAL_STORE — set to "file" to keep a login's tokens in
	// auth.json instead of the operating system's credential store. It is for a
	// machine whose credential store is present but unusable, which the probe
	// in internal/interface/auth cannot tell from a working one.
	EnvKeyBuildmaxCredentialStore = "BUILDMAX_CREDENTIAL_STORE"

	// Test only.
	EnvKeyBuildmaxTestDSN = "BUILDMAX_TEST_DSN"

	// BUILDMAX_CACHE_QUALIFY_* name the provider the prompt-cache qualification
	// suite runs against. The suite calls a real, paid provider and is not part
	// of any check; unset, it skips. See docs/design/prompt-cache-control.md
	// section 9, phase 4.
	EnvKeyBuildmaxCacheQualifyProvider = "BUILDMAX_CACHE_QUALIFY_PROVIDER"
	EnvKeyBuildmaxCacheQualifyModel    = "BUILDMAX_CACHE_QUALIFY_MODEL"
	EnvKeyBuildmaxCacheQualifyAPIKey   = "BUILDMAX_CACHE_QUALIFY_API_KEY"
	EnvKeyBuildmaxCacheQualifyBaseURL  = "BUILDMAX_CACHE_QUALIFY_BASE_URL"
	// BUILDMAX_CACHE_QUALIFY_SLOW opts into the scenarios that must wait out a
	// retention window. They take minutes of wall clock, so they are off by
	// default rather than silently making a run look hung.
	EnvKeyBuildmaxCacheQualifySlow = "BUILDMAX_CACHE_QUALIFY_SLOW"
)

Environment variable key names.

View Source
const (
	PermissionAllow = "allow"
	PermissionAsk   = "ask"
	PermissionDeny  = "deny"
)

Permission actions as written in settings.yaml.

View Source
const (
	PluginSkillsSubdir = "skills"
	PluginAgentsSubdir = "agents"
)

Plugin content subdirectories. A plugin contributes only what a workspace .buildmax directory already supports, under the same names.

View Source
const (
	// SandboxNetworkTierNone pre-allows no domain. The strictest tier and the
	// default for an agent that declares nothing, matching today's
	// SandboxSurfaceWorker baseline.
	SandboxNetworkTierNone SandboxNetworkTier = "none"
	// SandboxNetworkTierRegistries pre-allows DefaultRegistryDomains: enough
	// to install a dependency without an operator hand-authoring policy.yaml.
	SandboxNetworkTierRegistries SandboxNetworkTier = "registries"
	// SandboxNetworkTierOpen pre-allows any outbound HTTPS destination. The
	// filesystem tier is unaffected.
	SandboxNetworkTierOpen SandboxNetworkTier = "open"

	// SandboxFilesystemTierWorkspace confines writes to the run's own
	// workspace, exactly as SandboxSurfaceWorker already does. The default
	// for an agent that declares nothing.
	SandboxFilesystemTierWorkspace SandboxFilesystemTier = "workspace"
	// SandboxFilesystemTierWorkspacePlusSharedRead additionally allows
	// reading a deployment-configured shared cache path.
	SandboxFilesystemTierWorkspacePlusSharedRead SandboxFilesystemTier = "workspace_plus_shared_read"
	// SandboxFilesystemTierWorkspacePlusExternalWrite additionally allows
	// writing one deployment-configured external output path.
	SandboxFilesystemTierWorkspacePlusExternalWrite SandboxFilesystemTier = "workspace_plus_external_write"
)
View Source
const (
	// BUILDMAX_DATABASE_PASSWORD overrides database.password.
	EnvKeyBuildmaxDatabasePassword = "BUILDMAX_DATABASE_PASSWORD"
	// BUILDMAX_STORAGE_MINIO_ACCESS_KEY overrides storage.minio.access_key.
	EnvKeyBuildmaxMinIOAccessKey = "BUILDMAX_STORAGE_MINIO_ACCESS_KEY"
	// BUILDMAX_STORAGE_MINIO_SECRET_KEY overrides storage.minio.secret_key.
	EnvKeyBuildmaxMinIOSecretKey = "BUILDMAX_STORAGE_MINIO_SECRET_KEY"
	// BUILDMAX_CONVERSATION_MODEL_API_KEY overrides conversation.model.api_key.
	EnvKeyBuildmaxConversationAPIKey = "BUILDMAX_CONVERSATION_MODEL_API_KEY"
)

Environment overrides for secret-bearing server.yaml fields. The file stays the source of truth for shape and non-secret values; these exist so a deployment can inject credentials from a Kubernetes Secret, a Docker secret, or a CI variable without writing them to disk. Same pattern as jwt_secret.

View Source
const (
	ProviderLocalFS = "local_fs"
	ProviderMinIO   = "minio"
)
View Source
const DefaultCallTimeoutSecs = 300

DefaultCallTimeoutSecs is the per-LLM-call timeout used when a model entry does not specify call_timeout. 300 seconds (5 minutes) is generous enough for long reasoning responses while still bounding hung connections.

View Source
const DefaultContextWindow = 32_000

DefaultContextWindow is the fallback context window token limit used when a model entry does not specify context_window (i.e. the value is 0). 32 000 tokens is a conservative default that fits most hosted models.

View Source
const DefaultDBTLSMode = "preferred"

DefaultDBTLSMode is used when database.tls is unset.

"preferred" upgrades a connection whenever the server advertises TLS and behaves exactly as before against one that does not, so it has no failure mode a plaintext connection did not already have. It does not verify the certificate; a deployment that needs that sets "true".

View Source
const DefaultMaxTokens = 8_192

DefaultMaxTokens caps one response when a model entry does not set max_tokens and the protocol requires the field. The Anthropic Messages API rejects a request without it, so its adapter substitutes this value; the OpenAI protocols leave the cap to the provider when it is unset. 8 192 tokens fits a long tool-calling turn without truncating mid-thought.

View Source
const DefaultModel = ModelGemini25FlashLite

DefaultModel is the model used when no model is configured.

View Source
const DefaultOllamaBaseURL = "http://localhost:11434"

DefaultOllamaBaseURL is where a local Ollama daemon listens. It is the daemon root, not the /v1 compatibility endpoint, because llm.ProviderOllama speaks the native API under /api.

View Source
const DefaultOpenRouterBaseURL = "https://openrouter.ai/api/v1"

DefaultOpenRouterBaseURL is the OpenRouter OpenAI-compatible API base URL.

View Source
const EnvKeyBuildmaxCORSOrigin = "BUILDMAX_CORS_ORIGIN"

BUILDMAX_CORS_ORIGIN overrides cors_origin.

The one override here that carries no secret. cors_origin has to name the origin the Portal is actually served from, which is a host port the deployment chooses and the file cannot know: the Compose stack publishes the Portal on BUILDMAX_PORTAL_PORT, so a committed server.yaml that spells the default out is wrong for every other value. Deriving it where the port is chosen is what keeps moving that port a one-variable change.

View Source
const EnvKeyBuildmaxSandboxBackendInstalled = "BUILDMAX_SANDBOX_BACKEND_INSTALLED"

EnvKeyBuildmaxSandboxBackendInstalled marks an image as one where the sandbox's OS backend (bwrap + socat) is actually installed. Set via `ENV` in Dockerfile.buildmax and Dockerfile.release, not by any Go code -- Kubernetes does not strip an image's own ENV entries from a Job's container, so this is visible inside a k8s_job worker pod without any pod-spec change.

View Source
const EnvKeyBuildmaxSandboxEnabled = "BUILDMAX_SANDBOX_ENABLED"

Env override key. Phase A only honors BUILDMAX_SANDBOX_ENABLED; later phases may add more.

View Source
const EnvKeyBuildmaxTraceDisabled = "BUILDMAX_TRACE_DISABLED"

EnvKeyBuildmaxTraceDisabled, when truthy, turns off durable run traces. Per-subsystem env constant (kept here next to the resolver, mirroring the sandbox convention) and registered by env_spec.go EnvVars.

View Source
const MCPVarWorkspaceRoot = "WORKSPACE_ROOT"

MCPVarWorkspaceRoot is the variable name available in mcp.json $VAR expansion that resolves to the workspace directory passed to LoadMCPConfigForWorkspace. MCP config authors use it as $WORKSPACE_ROOT in command, args, env, or url fields.

View Source
const PluginStateFile = ".state.json"

PluginStateFile is the name of the supplemental state file. It begins with a dot because §4.1 reserves dot-prefixed entries in the plugins directory for BuildMax's own staging, cache, and state.

View Source
const PluginStateVersion = 1

PluginStateVersion is the schema version written into .state.json. The file is machine-authored, so stamping it costs an author nothing and lets a later format change be detected instead of guessed at.

View Source
const PluginVarRoot = plugin.VarPluginRoot

PluginVarRoot names the plugin-root variable, defined with the rest of the document format in internal/core/plugin.

Each plugin's configuration is expanded with its own root before layers are merged, which is the only order that gives two plugins two different answers for the same text. BuildMax supplies the value; a plugin cannot override it by exporting an environment variable of the same name.

Variables

View Source
var (
	// Version is the BuildMax application version, without a leading "v".
	Version = "dev"

	// Commit is the short git commit SHA the binary was built from.
	Commit = "dev"
)

Version and Commit identify the build. The release pipeline and ./make build inject both at link time so the git tag stays the single source of truth for what a binary calls itself:

-ldflags "-X github.com/gougoujiang/buildmax/internal/config.Version=0.1.0 \
          -X github.com/gougoujiang/buildmax/internal/config.Commit=abc1234"

When the linker sets neither — `go install module@version`, `go build`, `go run`, `go test` — init falls back to the Go build info, so a binary installed with `go install` reports the released version it was built from instead of a bare "dev". See resolveBuildInfo.

Functions

func AgentDefSources

func AgentDefSources(workspace string, plugins []DiscoveredPlugin) []plugin.Source

AgentDefSources returns the priority-ordered directories to scan for subagent definitions, in the same layering as SkillSources.

func AgentDefsSearchPaths

func AgentDefsSearchPaths(workspace string) []string

AgentDefsSearchPaths returns the ordered list of directories to scan for agent definitions. Priority: workspace-local first, then global DataDir.

func AuthPath

func AuthPath() string

AuthPath returns the path to the auth credentials file under DataDir.

func CacheModes

func CacheModes() []string

CacheModes and CacheTTLs are the accepted values, for validation messages.

func CacheTTLs

func CacheTTLs() []string

func DataDir

func DataDir() string

DataDir returns the application data folder path. BUILDMAX_HOME overrides; default is ~/.buildmax. Does not create the directory; callers must create it if needed.

func DefaultRegistryDomains

func DefaultRegistryDomains() []string

DefaultRegistryDomains returns the BuildMax-maintained default allow-list for SandboxNetworkTierRegistries, copied so a caller cannot mutate the shared default. A deployment extends it, never replaces it, via policy.yaml's own network.allowed_domains -- see docs/design/agent-sandbox-policy.md §4.6.

func FilterWorkerEnv

func FilterWorkerEnv(environ []string, managedLLM bool) []string

FilterWorkerEnv returns environ with the BUILDMAX_ variables a worker does not read removed.

Everything outside the BUILDMAX_ prefix passes through untouched: PATH, HOME and the rest are what let the worker binary run at all. Use this when handing a local worker process the server's environment.

func KnownCacheMode

func KnownCacheMode(mode string) bool

KnownCacheMode and KnownCacheTTL report whether a value names something this build understands. Empty is accepted as "unset" and resolves to the default.

func KnownCacheTTL

func KnownCacheTTL(ttl string) bool

func KnownLLMProvider

func KnownLLMProvider(name string) bool

KnownLLMProvider reports whether name is a wire protocol BuildMax implements. The empty string is known: it means the default.

This is the config boundary's own reading of the vocabulary, not a second copy of it. An unset provider is a valid thing to write in settings.yaml and LLMProvider resolves it; llm.KnownProvider answers about a stated protocol and rejects the empty one.

func KnownReasoningEffort

func KnownReasoningEffort(level string) bool

KnownReasoningEffort reports whether level is one BuildMax implements. The empty string is known: it means off.

func LoadMCPConfigForWorkspace

func LoadMCPConfigForWorkspace(workspaceDir string) (*coremcp.ConfigRoot, error)

LoadMCPConfigForWorkspace loads and validates MCP config, or returns (nil, nil) if none.

It merges <DataDir>/mcp.json (global) with <workspace>/.buildmax/mcp.json when workspaceDir is non-empty: all servers from both files are combined, and when a server id appears in both, the workspace entry replaces the global one.

After loading, $VAR and ${VAR} in each server's command, args, env values, and url are expanded against a variable table: snapshot of the process environment (os.Environ) plus MCPVarWorkspaceRoot set to workspaceDir (overrides the same key from the env if present).

func LoadWorkspaceHooks

func LoadWorkspaceHooks(workspace string) (corehook.Config, error)

LoadWorkspaceHooks reads <workspace>/.buildmax/hooks.yaml. A missing file is not an error — returns (corehook.Config{}, nil) so callers can merge unconditionally. A malformed file is reported as an error so misconfig surfaces at startup instead of silently dropping rules.

The file shape mirrors the "hooks:" block of settings.yaml; the top-level keys are pre_tool_use / post_tool_use / pre_compact / post_compact / run_end (the same snake_case event keys).

func LogLevel

func LogLevel(fromSettings string) string

LogLevel returns the effective log level from the config file, defaulting to "info".

func LogsDir

func LogsDir() string

LogsDir returns the path to the logs directory under DataDir.

func MergeHooks

func MergeHooks(layers ...corehook.Config) corehook.Config

MergeHooks returns a single corehook.Config containing every entry from every layer, in the order the layers are given, per event. The merge is additive: every layer runs for the same event; the dispatcher's first-block-wins rule still applies, but every matching hook still executes.

The documented order is global settings, then plugins in name order, then the workspace. A workspace cannot remove a global hook, which is what makes the global layer usable as an operator control — and the same is true of a plugin.

Mutating the returned config does not affect the inputs.

func PersistentWorkspaceDir

func PersistentWorkspaceDir(workspacesDir, workspaceID string) string

PersistentWorkspaceDir returns the persistent home directory for a team's workspace.

func PluginRootFor

func PluginRootFor(p DiscoveredPlugin) string

PluginRootFor returns the value BUILDMAX_PLUGIN_ROOT takes inside one plugin's configuration.

func PluginsDir

func PluginsDir() string

PluginsDir is where installed plugins live. Respecting BUILDMAX_HOME is what keeps tests, workers, and isolated installations out of a contributor's real plugins directory.

func PolicyPath

func PolicyPath() string

PolicyPath returns the operator-controlled policy file path. Optional; missing file means "no operator lock-out."

func ProjectsDir

func ProjectsDir() string

ProjectsDir returns the path to the local Project bundles under DataDir. Sessions stay under SessionsDir and are related to a Project by id, not by living beneath one; see docs/design/local-project-memory.md §8.2.

func ReasoningEfforts

func ReasoningEfforts() []string

ReasoningEfforts returns every level an operator may set, for help text and error messages that must not drift from the list above.

func ReasoningEnabled

func ReasoningEnabled(level string) bool

ReasoningEnabled reports whether a configured level asks for reasoning.

func ResolveMCPConfigPath

func ResolveMCPConfigPath(workspaceDir string) string

ResolveMCPConfigPath returns one existing MCP config path for display or tooling, or "". Order: <workspace>/.buildmax/mcp.json, then <DataDir>/mcp.json. LoadMCPConfigForWorkspace merges both files when they exist; this helper returns only the highest-priority existing path for display purposes.

func ResolveMaxIterations

func ResolveMaxIterations(cfg AgentConfig, override int) int

ResolveMaxIterations settles the loop cap for one run. A per-run override outranks settings.yaml, which outranks the default; zero at either level means unset rather than "no iterations", because a cap of nothing is a value nobody can mean.

Out-of-range is clamped rather than rejected, for the reason ResolveMaxParallelTools gives.

func ResolveMaxParallelTools

func ResolveMaxParallelTools(cfg AgentConfig) int

ResolveMaxParallelTools clamps the configured value into the supported range. Out-of-range is clamped rather than rejected: a number that is merely too large should not stop the agent starting.

func ResolvePricing

func ResolvePricing(in *ModelPricing) (cllm.Pricing, error)

ResolvePricing parses a configured price list.

A nil entry is not an error: pricing is optional, and a model without it reports its cost as unavailable rather than as zero. A malformed one is an error, because someone wrote a price and meant it.

func RuntimeTaskRunArtifactsDir

func RuntimeTaskRunArtifactsDir(workspacesDir, workspaceID, taskID, taskRunID string) string

RuntimeTaskRunArtifactsDir returns the run's artifacts dir.

func RuntimeTaskRunDir

func RuntimeTaskRunDir(workspacesDir, workspaceID, taskID, taskRunID string) string

RuntimeTaskRunDir returns the run directory for a specific task run.

func RuntimeTaskRunGlobalDir

func RuntimeTaskRunGlobalDir(workspacesDir, workspaceID, taskID, taskRunID string) string

RuntimeTaskRunGlobalDir returns the run's global dir (BUILDMAX_HOME for that run).

func RuntimeTaskRunHomeDir

func RuntimeTaskRunHomeDir(workspacesDir, workspaceID, taskID, taskRunID string) string

RuntimeTaskRunHomeDir returns the run's home dir (materialized workspace home).

func ServerConfigPath

func ServerConfigPath() string

ServerConfigPath returns the path to the server config file (BUILDMAX_HOME/server.yaml).

func SessionsDir

func SessionsDir() string

SessionsDir returns the path to the sessions directory under DataDir.

func SettingsPath

func SettingsPath() string

SettingsPath returns the path to the local settings file (BUILDMAX_HOME/settings.yaml).

func SkillSearchPaths

func SkillSearchPaths(workspace string) []string

SkillSearchPaths returns the ordered list of directories to scan for skills. Priority: workspace-local first, then global DataDir.

func SkillSources

func SkillSources(workspace string, plugins []DiscoveredPlugin) []plugin.Source

SkillSources returns the priority-ordered directories to scan for skills: workspace, then global, then each plugin in name order.

Plugins come last because a workspace or a user's own configuration may deliberately override what a plugin ships. Plugins are sorted by name so loading is deterministic — not so that order can settle a collision between two of them, which resolution refuses to do.

func TraceEnabled

func TraceEnabled() bool

TraceEnabled reports whether durable run traces should be written. Traces are on by default; set BUILDMAX_TRACE_DISABLED to a truthy value (1/true/yes/on) to turn them off.

func TracesDir

func TracesDir() string

TracesDir returns the traces root under DataDir. It holds what belongs to no single session: <DataDir>/traces/jobs/<job_id>.jsonl. A run's own trace lives inside its session bundle instead — see sessionstore.SessionTracesDir. Does not create the directory; the recorder creates it on demand.

func TurnDigestRecap

func TurnDigestRecap(cfg TurnDigestConfig) bool

TurnDigestRecap and TurnDigestSuggest report whether each part is on.

func TurnDigestSuggest

func TurnDigestSuggest(cfg TurnDigestConfig) bool

func UpdatePluginStates

func UpdatePluginStates(pluginsDir string, mutate func(*PluginStates) error) error

UpdatePluginStates applies mutate to the state file under a lock held across the read and the write.

Every writer goes through here rather than through a Load/Save pair, because the file is one shared map: a read-modify-write that is not held together loses whichever entry the other writer added. A CLI install racing a running Desktop is the ordinary case, not a rare one.

func UserAgent

func UserAgent(surface string, viaGateway bool) string

UserAgent identifies BuildMax and the calling surface in outbound requests. viaGateway says BuildMax forwarded the call through its managed gateway.

func ValidSandboxFilesystemTier

func ValidSandboxFilesystemTier(tier string) bool

ValidSandboxFilesystemTier reports whether tier is a known filesystem tier, on the same empty-string terms as ValidSandboxNetworkTier.

func ValidSandboxNetworkTier

func ValidSandboxNetworkTier(tier string) bool

ValidSandboxNetworkTier reports whether tier is a known network tier. The empty string is valid and equivalent to SandboxNetworkTierNone, so an agent that predates this field is not rejected on write.

func ValidateCacheControl

func ValidateCacheControl(c CacheControl) error

ValidateCacheControl reports a policy this build cannot act on. It checks the vocabulary only; whether a *target* supports the requested retention is the client's question, because it depends on the protocol the target speaks.

func VersionString

func VersionString() string

VersionString returns the human-readable version string, e.g. "0.1.0 (abc1234)". The commit is omitted when it is unknown, which is the normal case for a `go install` build.

func WorkerEnvKeys

func WorkerEnvKeys(managedLLM bool) []string

WorkerEnvKeys returns the environment variable names a worker is given, in declaration order.

func WorkerNeedsEnv

func WorkerNeedsEnv(name string, managedLLM bool) bool

WorkerNeedsEnv reports whether a task-run worker reads name.

managedLLM says whether this deployment's task runs reach models through the server. When they do, provider credentials are withheld: the run has a gateway credential instead and never calls a provider itself.

It answers false for an unrecognized BUILDMAX_ variable as well as for a known one a worker does not use, so a variable added to the server without a thought for workers stays on the server.

func WorkspaceHooksPath

func WorkspaceHooksPath(workspace string) string

WorkspaceHooksPath returns the per-workspace hooks config path (<workspace>/.buildmax/hooks.yaml). It does not check existence.

Types

type AgentConfig

type AgentConfig struct {
	// MaxParallelTools bounds how many tool calls from one assistant message
	// may run at once. 1 disables parallel execution; 0 means unset.
	MaxParallelTools int `mapstructure:"max_parallel_tools" json:"max_parallel_tools,omitempty" yaml:"max_parallel_tools,omitempty"`
	// MaxIterations bounds how many times the agent loop may call the model in
	// one run. 0 means unset.
	MaxIterations int `mapstructure:"max_iterations" json:"max_iterations,omitempty" yaml:"max_iterations,omitempty"`
	// TurnDigest controls the after-the-turn side call. See TurnDigestConfig.
	TurnDigest TurnDigestConfig `mapstructure:"turn_digest" json:"turn_digest" yaml:"turn_digest"`
}

AgentConfig is the "agent" block of settings.yaml.

type CacheControl

type CacheControl struct {
	Mode string `mapstructure:"mode"`
	TTL  string `mapstructure:"ttl"`
}

CacheControl is one model's prompt-cache policy (snake_case on disk).

func ResolveCacheControl

func ResolveCacheControl(in *CacheControl) CacheControl

ResolveCacheControl fills in what a model entry left unset.

An absent block, an absent mode, and an absent ttl all mean the same thing — nobody chose — and all take the default. There is no legacy shorthand to fold in: BuildMax is pre-release, so a wrong shape is corrected everywhere rather than carried alongside its replacement.

type DiscoveredPlugin

type DiscoveredPlugin struct {
	// Dir is the directory name. It is the state key and the only identity a
	// plugin has when its manifest does not parse.
	Dir  string
	Path string

	Manifest plugin.Manifest
	// Findings are this plugin's own problems, including a name collision with
	// another directory, so Loadable can be answered without looking around.
	Findings []plugin.Finding

	State PluginState
	// StateKnown is false when nothing recorded this directory, which is the
	// normal condition of a manual `git clone`.
	StateKnown bool

	// PolicyRefused says the operator's source restriction is what stopped this
	// plugin, so a surface can tell a decision from a defect. The reason is
	// also in Findings, which is what carries it to every surface without each
	// one having to know about policy.
	PolicyRefused bool
}

DiscoveredPlugin is one directory under the plugins directory that holds a plugin.yaml, whether or not that manifest turned out to be usable.

func (DiscoveredPlugin) Loadable

func (d DiscoveredPlugin) Loadable() bool

Loadable reports whether this plugin should contribute to a runtime.

func (DiscoveredPlugin) Name

func (d DiscoveredPlugin) Name() string

Name is the plugin's identity: the manifest name, falling back to the directory when the manifest could not supply one.

func (DiscoveredPlugin) Source

func (d DiscoveredPlugin) Source() PluginSource

Source is where this directory came from.

A recorded source is the answer when there is one. Otherwise the directory is classified by looking: a checkout is a repository plugin and anything else is a local one. That is decided here rather than persisted, because the directory is the source of truth and a stored answer would go stale the first time somebody ran `git init` in it.

The look is a stat for `.git`, not a call to Git. Asking Git would answer for the nearest enclosing repository, so a plugins directory inside somebody's home checkout would make every plugin in it look like a clone.

type EnvVar

type EnvVar struct {
	Name        string
	Default     string
	Description string
	// WorkerNeeds marks a variable that a task-run worker reads.
	//
	// A worker executes model-chosen code, so a credential it does not read is
	// exposure with no purpose behind it. Only the marked variables are handed
	// to a worker process or Job pod. internal/bootstrap/worker.go is the
	// authority on what that set is: if a worker starts reading a new variable,
	// mark it here, and it will reach the worker. Nothing else will.
	WorkerNeeds bool
	// DirectLLMOnly narrows WorkerNeeds to deployments whose task runs call a
	// provider themselves. A managed run reaches models through the server and
	// holds no provider credential, so passing one would hand a model-driven
	// process a key it has no use for.
	DirectLLMOnly bool
}

EnvVar describes one environment variable used by BuildMax.

func EnvVars

func EnvVars() []EnvVar

EnvVars returns every environment variable read by BuildMax binaries.

type LLM

type LLM struct {
	APIKey  string
	BaseURL string
	Model   string
}

LLM holds resolved LLM provider settings.

func EffectiveLLM

func EffectiveLLM() (LLM, string)

EffectiveLLM returns the LLM config and display name using the first model from settings or the env-var fallback.

func EffectiveLLMWithModelName

func EffectiveLLMWithModelName(modelName string) (LLM, string, error)

EffectiveLLMWithModelName returns the LLM config and display name to use at startup. When modelName is empty: uses the first model from settings.yaml. When modelName is set: must match an entry by name or model id. Returns an error when settings.yaml has no models configured.

type MCPResolution

type MCPResolution struct {
	// Config is nil when no layer declared a server.
	Config *coremcp.ConfigRoot
	// Shadowed lists plugin servers a higher layer replaced, so a plugin does
	// not appear fully active when part of it never runs.
	Shadowed []plugin.Shadowed
	Findings []plugin.Finding
}

MCPResolution is the merged MCP configuration plus what merging noticed.

func ResolveMCPConfig

func ResolveMCPConfig(workspaceDir string, plugins []DiscoveredPlugin) (MCPResolution, error)

ResolveMCPConfig merges the plugin layer under the global and workspace ones.

Each plugin's file is expanded with its own PluginVarRoot before anything is merged, which is the only order in which two plugins can read the same text and get their own directory. Layer precedence then works as it always has: a later layer replaces a server id an earlier one declared.

type ModelEntry

type ModelEntry struct {
	Model         string `mapstructure:"model"`
	Name          string `mapstructure:"name"`
	APIURL        string `mapstructure:"api_url"`
	APIKey        string `mapstructure:"api_key"`
	ContextWindow int    `mapstructure:"context_window"` // 0 = uses DefaultContextWindow
	CallTimeout   int    `mapstructure:"call_timeout"`   // seconds; 0 = uses DefaultCallTimeoutSecs
	// MaxTokens caps one response; 0 = uses the adapter's own default. The
	// Anthropic Messages protocol requires the field, so its adapter substitutes
	// DefaultMaxTokens; the OpenAI protocols send it only when set.
	MaxTokens int `mapstructure:"max_tokens"`
	// Reasoning is how much the model should reason before answering:
	// ReasoningOff (the default), ReasoningLow, ReasoningMedium, or
	// ReasoningHigh. Any level other than off also replays the reasoning on
	// later turns. It has no effect on a protocol that carries none.
	Reasoning string `mapstructure:"reasoning"`
	// Vision says this model accepts image input. When false, an image a tool
	// returns is described in text rather than sent, because a model that
	// cannot read images rejects the request rather than ignoring the image.
	Vision bool `mapstructure:"vision"`
	// CacheControl is this model's prompt-cache policy: which calls ask the
	// provider to cache the stable prefix of a request — the tool definitions
	// and system prompt — and for how long.
	CacheControl *CacheControl `mapstructure:"cache_control"`
	// Pricing is what this model charges. Optional: without it a run reports
	// its cost as unavailable rather than as zero, because BuildMax does not
	// know what any provider charges and guessing would be worse than silence.
	Pricing *ModelPricing `mapstructure:"pricing"`
	// Integration names a qualified OpenAI-compatible gateway, for the cache
	// fields that gateway is known to honour. Empty is the normal case:
	// speaking the protocol is not a promise to implement its cache behaviour,
	// so nothing is sent unless a named profile says the endpoint was tested.
	Integration string `mapstructure:"integration"`
	// KeepAlive is how long a local runtime keeps the model loaded after a
	// call — a duration string, "0" to unload at once, "-1" to stay resident.
	// Only llm.ProviderOllama reads it; on a hosted provider there is no model
	// to keep loaded. Empty means the runtime's own default.
	KeepAlive string `mapstructure:"keep_alive"`
	// Provider is the wire protocol this endpoint speaks: llm.ProviderOpenAICompatible
	// (the default), llm.ProviderOpenAI, llm.ProviderAnthropic, or llm.ProviderOllama.
	Provider string `mapstructure:"provider"`
}

ModelEntry is one LLM model entry in settings.yaml (snake_case on disk).

func (ModelEntry) LLMProvider

func (m ModelEntry) LLMProvider() string

LLMProvider returns the wire protocol this entry speaks, defaulting to llm.ProviderOpenAICompatible so a configuration written before providers existed keeps calling what it always called.

type ModelPricing

type ModelPricing struct {
	// Currency is the ISO 4217 code the rates are quoted in. Required: rates
	// with no currency price nothing, because nothing can be added to them.
	Currency string `mapstructure:"currency"`
	// InputPerMTok is fresh prompt input, excluding anything cached.
	InputPerMTok string `mapstructure:"input_per_mtok"`
	// CacheReadPerMTok is prompt served from the provider's cache, and
	// CacheWritePerMTok is prompt written into it. Left empty they are zero,
	// which is a real price on a provider that does not charge for one.
	CacheReadPerMTok  string `mapstructure:"cache_read_per_mtok"`
	CacheWritePerMTok string `mapstructure:"cache_write_per_mtok"`
	// OutputPerMTok is generated tokens.
	OutputPerMTok string `mapstructure:"output_per_mtok"`
}

ModelPricing is what one model charges, as it is written in a settings file (snake_case on disk).

The rates are decimal strings quoted per million tokens, which is how every provider publishes them: a configured value can be checked against a price page without arithmetic, and a YAML float would have rounded it before anything here saw it. They are parsed into the fixed-point form in core/llm.Pricing, because a run of a few hundred calls accumulates float error into a figure someone will compare against an invoice.

The four rates are separate because prompt caching prices them differently: a cache read is cheaper than fresh input and a cache write is dearer, which is the whole reason caching is a decision rather than a free win.

type PermissionEntry

type PermissionEntry struct {
	// Key is the match key, lowercased. Viper lowercases every map key it
	// loads, so a rule written as "Write" arrives as "write" and matching has
	// to be case-insensitive or no rule would ever fire against a tool name.
	Key string
	// Display is the key as the user wrote it, for output.
	Display string
	Action  string
	Source  string
}

PermissionEntry is one resolved rule, carrying where it came from so `buildmax tools status` can name the source.

type PermissionResolution

type PermissionResolution struct {
	Entries []PermissionEntry
	// Invalid lists keys whose action was not recognised. They are ignored
	// rather than fatal: a typo in one rule must not stop the agent starting.
	Invalid []string
}

PermissionResolution is the resolved permission table.

There is one configurable source, settings.yaml. An operator-controlled policy.yaml block was specified and dropped: a worker's BUILDMAX_HOME is created fresh per run, so nothing there could reach the surface that needs it. See docs/design/tool-permissions.md §2 and §7.

func ResolvePermissions

func ResolvePermissions(tools ToolsConfig) PermissionResolution

ResolvePermissions validates and orders the configured rules.

func (PermissionResolution) Lookup

func (r PermissionResolution) Lookup(name, scope string) (PermissionEntry, bool)

Lookup returns the action configured for a call, and whether one matched.

Most specific wins: the exact scope, then the longest matching prefix pattern, then the bare tool name. Without that order a broad "CallMcpTool: deny" would swallow the narrow exception written next to it.

type PluginDiscovery

type PluginDiscovery struct {
	Dir     string
	Plugins []DiscoveredPlugin

	// Findings belong to the directory rather than to any one plugin.
	Findings []plugin.Finding

	// StateErr is set when .state.json existed but could not be read. Every
	// valid plugin still loads; what is lost is provenance and the disabled
	// flag, and a caller must say so rather than report a clean scan.
	StateErr error

	// Policy is the source restriction this scan applied, so a surface can say
	// that a plugin is missing by decision rather than by accident.
	Policy PluginPolicy
}

PluginDiscovery is the result of scanning the plugins directory.

func DiscoverPlugins

func DiscoverPlugins() PluginDiscovery

DiscoverPlugins scans <BUILDMAX_HOME>/plugins under the deployment's policy.

A policy that cannot be read is reported and treated as asserting nothing. Refusing to load any plugin because policy.yaml has a typo would turn one mistake into an outage, and the scan says what it could not apply.

func DiscoverPluginsIn

func DiscoverPluginsIn(dir string, policy PluginPolicy) PluginDiscovery

DiscoverPluginsIn scans one plugins directory.

Directory contents are the source of truth: a manually cloned repository is a plugin the moment it holds a valid plugin.yaml, with no registry to generate and no state file to write. Nothing here touches the network or Git.

func (PluginDiscovery) Loadable

func (d PluginDiscovery) Loadable() []DiscoveredPlugin

Loadable returns the plugins that should contribute to a runtime, in directory order.

type PluginHooks

type PluginHooks struct {
	Config   corehook.Config
	Findings []plugin.Finding
}

PluginHooks is the plugin layer's contribution, already concatenated in name order, plus what loading it noticed.

func ResolvePluginHooks

func ResolvePluginHooks(plugins []DiscoveredPlugin) PluginHooks

ResolvePluginHooks reads every plugin's hooks.yaml in name order.

A plugin whose file will not parse contributes nothing and is reported: hook configuration fails open by design, and refusing to start the agent over one plugin's typo would be a worse failure than running without its hooks.

type PluginPolicy

type PluginPolicy struct {
	// AllowedSources lists the source types that may load. Empty means every
	// source loads, which is the state of a deployment that asserted nothing.
	AllowedSources []string `mapstructure:"allowed_sources" json:"allowed_sources,omitempty" yaml:"allowed_sources,omitempty"`
}

PluginPolicy is the operator-controlled `plugins` block of policy.yaml.

It constrains where plugins may come from, not what they may do. Restricting sources says which bytes are allowed to load; tool permissions, hook gates, and the sandbox are what constrain the bytes that do.

It is fleet management rather than a security boundary: policy.yaml sits in the user's own BUILDMAX_HOME, so a local user can edit it. It is worth having where an operator controls the machine — a managed device, a built image, a container — and worth nothing against somebody who could equally write the configuration by hand.

func (PluginPolicy) Allows

func (p PluginPolicy) Allows(source PluginSource) bool

Allows reports whether a source may load under this policy.

func (PluginPolicy) IsSet

func (p PluginPolicy) IsSet() bool

IsSet reports whether the operator constrained anything.

type PluginSource

type PluginSource string

PluginSource is how a plugin directory came to exist. It is recorded by whatever put the directory there, never inferred from the directory itself.

const (
	// PluginSourceRepository is a Git working tree the user cloned or checked out.
	PluginSourceRepository PluginSource = "repository"
	// PluginSourceMarketplace is a release this machine downloaded and verified.
	PluginSourceMarketplace PluginSource = "marketplace"
	// PluginSourceLocal is an ordinary directory with no other provenance.
	PluginSourceLocal PluginSource = "local"
	// PluginSourceUnknown is a directory nothing recorded, which is the normal
	// state of a manual `git clone` until something inspects it.
	PluginSourceUnknown PluginSource = ""
)

type PluginState

type PluginState struct {
	Source   PluginSource `json:"source,omitempty"`
	Disabled bool         `json:"disabled,omitempty"`

	// Repository provenance, when the installer knew it. A manual clone has
	// none until something inspects the checkout.
	RepositoryURL string `json:"repository_url,omitempty"`
	LastCommit    string `json:"last_commit,omitempty"`

	// Marketplace provenance, which identifies the exact bytes installed.
	MarketplaceServer string `json:"marketplace_server,omitempty"`
	CatalogID         string `json:"catalog_id,omitempty"`
	ReleaseVersion    string `json:"release_version,omitempty"`
	Digest            string `json:"digest,omitempty"`

	InstalledAt time.Time `json:"installed_at,omitempty"`
	UpdatedAt   time.Time `json:"updated_at,omitempty"`
}

PluginState is the installer's record for one plugin directory.

It holds only what the directory cannot tell BuildMax itself. Nothing here is required to discover or load a plugin: a lost state file costs provenance and the disabled flag, not the plugin.

type PluginStates

type PluginStates struct {
	Version int                    `json:"version"`
	Plugins map[string]PluginState `json:"plugins"`
}

PluginStates is the on-disk shape of .state.json.

Entries are keyed by directory name rather than by plugin name, because the directory is the only identity that exists before a manifest parses — and a manifest that fails to parse is exactly when the disabled flag still matters.

func LoadPluginStates

func LoadPluginStates(pluginsDir string) (PluginStates, error)

LoadPluginStates reads pluginsDir/.state.json.

A missing file returns empty state and no error: discovery does not depend on it. A damaged one is an error the caller reports as lost provenance, having still loaded every valid plugin directory.

func (PluginStates) Get

func (s PluginStates) Get(dir string) (PluginState, bool)

Get returns the record for a directory, and whether one was recorded.

func (*PluginStates) Remove

func (s *PluginStates) Remove(dir string)

Remove drops a directory's record.

func (*PluginStates) Set

func (s *PluginStates) Set(dir string, st PluginState)

Set records state for a directory.

type PolicyFile

type PolicyFile struct {
	Sandbox SandboxConfig `mapstructure:"sandbox" json:"sandbox,omitempty" yaml:"sandbox,omitempty"`
	Plugins PluginPolicy  `mapstructure:"plugins" json:"plugins,omitempty" yaml:"plugins,omitempty"`
}

PolicyFile is the on-disk shape of <BUILDMAX_HOME>/policy.yaml, the operator-controlled layer above settings.yaml.

func LoadPolicyFile

func LoadPolicyFile() (PolicyFile, error)

LoadPolicyFile reads <BUILDMAX_HOME>/policy.yaml. A missing file is not an error: it is the state of every deployment that asserted nothing.

type RedactedDBConfig

type RedactedDBConfig struct {
	Host string `json:"host,omitempty"`
	Port int    `json:"port,omitempty"`
	User string `json:"user,omitempty"`
	Name string `json:"name,omitempty"`
	// TLS is the effective mode, not the raw setting, so an unset value reads
	// as what the connection actually does.
	TLS      string       `json:"tls"`
	Password SecretStatus `json:"password"`
}

RedactedDBConfig shows where the database is, never how to open it.

type RedactedLLMConfig

type RedactedLLMConfig struct {
	DefaultModel  string        `json:"default_model,omitempty"`
	ConversationM RedactedModel `json:"conversation_model"`
}

RedactedLLMConfig shows which model this deployment defaults to. The name is an identifier rather than a credential; the credentials are in the llm_model table and are never served anywhere.

type RedactedModel

type RedactedModel struct {
	Name        string       `json:"name,omitempty"`
	Model       string       `json:"model,omitempty"`
	APIURL      string       `json:"api_url,omitempty"`
	ModelTarget string       `json:"model_target,omitempty"`
	APIKey      SecretStatus `json:"api_key"`
}

RedactedModel describes the Tier 1 model without its credential.

type RedactedServerConfig

type RedactedServerConfig struct {
	LogLevel             string `json:"log_level,omitempty"`
	Port                 int    `json:"port"`
	AllowSignup          bool   `json:"allow_signup"`
	CORSOrigin           string `json:"cors_origin,omitempty"`
	WorkspacesDir        string `json:"workspaces_dir,omitempty"`
	DefaultQuotaTier     string `json:"default_quota_tier,omitempty"`
	AccessTokenTTL       string `json:"access_token_ttl,omitempty"`
	RefreshTokenTTL      string `json:"refresh_token_ttl,omitempty"`
	RefreshRotationGrace string `json:"refresh_rotation_grace,omitempty"`
	ShutdownGrace        string `json:"shutdown_grace,omitempty"`

	JWTSecret SecretStatus `json:"jwt_secret"`

	Database RedactedDBConfig      `json:"database"`
	Storage  RedactedStorageConfig `json:"storage"`
	Worker   RedactedWorkerConfig  `json:"worker"`
	LLM      RedactedLLMConfig     `json:"llm"`

	// Warnings are configuration states worth an operator's attention. They are
	// not errors — the server is running — and they are computed rather than
	// stored, so the list reflects the process's own view of itself.
	Warnings []string `json:"warnings"`
}

RedactedServerConfig is the effective server configuration, safe to show a System Administrator.

type RedactedStorageConfig

type RedactedStorageConfig struct {
	PersistBackend  string `json:"persist_backend,omitempty"`
	ArtifactBackend string `json:"artifact_backend,omitempty"`
	// MaxArtifactMB is shown because an operator diagnosing a refused upload
	// needs to see the limit that refused it. Zero means the built-in default.
	MaxArtifactMB int `json:"max_artifact_mb,omitempty"`
	// ArtifactPurgeAfterDays is shown for the same reason: an operator asking
	// why a deleted artifact's bytes are still in the bucket is reading for
	// this number. Zero means the next sweep reclaims them.
	ArtifactPurgeAfterDays int          `json:"artifact_purge_after_days,omitempty"`
	MinIOEndpoint          string       `json:"minio_endpoint,omitempty"`
	MinIOBucket            string       `json:"minio_bucket,omitempty"`
	MinIORegion            string       `json:"minio_region,omitempty"`
	MinIOAccessKey         SecretStatus `json:"minio_access_key"`
	MinIOSecretKey         SecretStatus `json:"minio_secret_key"`
}

RedactedStorageConfig shows which backends are in use.

type RedactedWorkerConfig

type RedactedWorkerConfig struct {
	RunMode      string `json:"run_mode,omitempty"`
	ServerURL    string `json:"server_url,omitempty"`
	RunTokenTTL  string `json:"run_token_ttl,omitempty"`
	RunTimeout   string `json:"run_timeout,omitempty"`
	LLMTransport string `json:"llm_transport,omitempty"`
	LLMModel     string `json:"llm_model,omitempty"`
	K8sNamespace string `json:"k8s_namespace,omitempty"`
	K8sImage     string `json:"k8s_image,omitempty"`
}

RedactedWorkerConfig shows how runs are launched.

type SandboxConfig

type SandboxConfig struct {
	// Enabled is the master switch.
	Enabled bool `mapstructure:"enabled" json:"enabled,omitempty" yaml:"enabled,omitempty"`

	// FailIfUnavailable: refuse to start (rather than fall back to
	// unsandboxed) when the OS backend cannot run. Intended for managed
	// deployments that require sandboxing as a hard gate.
	FailIfUnavailable bool `mapstructure:"fail_if_unavailable" json:"fail_if_unavailable,omitempty" yaml:"fail_if_unavailable,omitempty"`

	// AutoAllowBashIfSandboxed: when true and the sandbox wraps the bash
	// call, skip the approval prompt. When false ("regular permissions
	// mode"), sandboxed bash still goes through the regular approval
	// flow.
	AutoAllowBashIfSandboxed *bool `` /* 135-byte string literal not displayed */

	// AllowUnsandboxedCommands: honor the per-call
	// dangerously_disable_sandbox arg. When false ("strict sandbox
	// mode") the arg is ignored.
	AllowUnsandboxedCommands *bool `` /* 129-byte string literal not displayed */

	// ExcludedCommands lists bash patterns that should run outside the
	// sandbox (convenience, not a security boundary).
	ExcludedCommands []string `mapstructure:"excluded_commands" json:"excluded_commands,omitempty" yaml:"excluded_commands,omitempty"`

	Filesystem SandboxFSConfig      `mapstructure:"filesystem" json:"filesystem,omitempty" yaml:"filesystem,omitempty"`
	Network    SandboxNetConfig     `mapstructure:"network"    json:"network,omitempty"    yaml:"network,omitempty"`
	Process    SandboxProcessConfig `mapstructure:"process"   json:"process,omitempty"    yaml:"process,omitempty"`

	// IgnoreViolations: per-tool list of violation kinds to hide from
	// status/trace. Internal counts are still kept.
	IgnoreViolations map[string][]string `mapstructure:"ignore_violations" json:"ignore_violations,omitempty" yaml:"ignore_violations,omitempty"`

	// EnableWeakerNestedSandbox: allow running inside Docker without
	// privileged namespaces by bind-mounting the container's existing
	// /proc instead of mounting a fresh one. Documented as weaker.
	EnableWeakerNestedSandbox bool `` /* 135-byte string literal not displayed */

	// EnableWeakerNetworkIsolation: macOS only; allow access to
	// com.apple.trustd.agent so Go-based CLIs can verify TLS through a
	// MITM proxy. Documented as weaker.
	EnableWeakerNetworkIsolation bool `` /* 144-byte string literal not displayed */
}

SandboxConfig is the "sandbox" block of settings.yaml (and policy.yaml). Key names mirror Claude Code's sandbox schema (snake_case per CLAUDE.md §6.1) so users and operators familiar with that product can port configuration directly. Detail design lives in docs/design/sandbox-boundaries.md.

The enforced subset and remaining gaps are tracked in that design record.

func LoadPolicySandbox

func LoadPolicySandbox() (SandboxConfig, error)

LoadPolicySandbox reads the sandbox block of <BUILDMAX_HOME>/policy.yaml. A missing file is not an error — returns (SandboxConfig{}, nil) so callers can merge unconditionally.

func TierSandboxConfig

func TierSandboxConfig(networkTier SandboxNetworkTier, filesystemTier SandboxFilesystemTier, shared SandboxSharedPaths) SandboxConfig

TierSandboxConfig translates an agent's declared network/filesystem tier pair into the SandboxConfig fragment ResolveSandboxForRun merges as one layer. An unrecognized tier translates to the zero value -- the strictest baseline -- rather than an error, so a run is never blocked by a tier this binary does not recognize; ValidSandboxNetworkTier/ValidSandboxFilesystemTier are what reject one on write. See docs/design/agent-sandbox-policy.md §4.1.

func (SandboxConfig) EffectiveAllowUnsandboxed

func (c SandboxConfig) EffectiveAllowUnsandboxed() bool

EffectiveAllowUnsandboxed returns the resolved AllowUnsandboxedCommands flag, applying the documented default (true) when unset.

func (SandboxConfig) EffectiveAutoAllowBash

func (c SandboxConfig) EffectiveAutoAllowBash() bool

EffectiveAutoAllowBash returns the resolved AutoAllowBashIfSandboxed flag, applying the documented default (true) when unset.

func (SandboxConfig) EffectiveMode

func (c SandboxConfig) EffectiveMode() string

EffectiveMode returns "auto_allow" or "regular" based on the resolved AutoAllowBashIfSandboxed flag. Returns "" when the sandbox is disabled.

func (SandboxConfig) IgnoredViolationsFor

func (c SandboxConfig) IgnoredViolationsFor(toolName string) []string

IgnoredViolationsFor returns the violation patterns suppressed for the named tool. Lookup is case-insensitive because Viper lowercases map keys when loading YAML; users may write "Bash:" matching the tool name.

type SandboxFSConfig

type SandboxFSConfig struct {
	AllowWrite []string `mapstructure:"allow_write" json:"allow_write,omitempty" yaml:"allow_write,omitempty"`
	DenyWrite  []string `mapstructure:"deny_write"  json:"deny_write,omitempty"  yaml:"deny_write,omitempty"`
	AllowRead  []string `mapstructure:"allow_read"  json:"allow_read,omitempty"  yaml:"allow_read,omitempty"`
	DenyRead   []string `mapstructure:"deny_read"   json:"deny_read,omitempty"   yaml:"deny_read,omitempty"`

	// AllowManagedReadPathsOnly: policy-only knob. When set in
	// policy.yaml, lower sources' allow_read entries are ignored;
	// deny_read still merges from every source.
	AllowManagedReadPathsOnly bool `` /* 138-byte string literal not displayed */
}

SandboxFSConfig mirrors Claude Code's sandbox.filesystem schema. Paths follow standard conventions documented in docs/design/sandbox-boundaries.md §4.3.

type SandboxFilesystemTier

type SandboxFilesystemTier string

SandboxFilesystemTier is the filesystem half of the same pair.

type SandboxNetConfig

type SandboxNetConfig struct {
	AllowedDomains      []string `mapstructure:"allowed_domains"        json:"allowed_domains,omitempty"        yaml:"allowed_domains,omitempty"`
	DeniedDomains       []string `mapstructure:"denied_domains"         json:"denied_domains,omitempty"         yaml:"denied_domains,omitempty"`
	AllowUnixSockets    []string `mapstructure:"allow_unix_sockets"     json:"allow_unix_sockets,omitempty"     yaml:"allow_unix_sockets,omitempty"`
	AllowAllUnixSockets bool     `mapstructure:"allow_all_unix_sockets" json:"allow_all_unix_sockets,omitempty" yaml:"allow_all_unix_sockets,omitempty"`
	AllowLocalBinding   bool     `mapstructure:"allow_local_binding"    json:"allow_local_binding,omitempty"    yaml:"allow_local_binding,omitempty"`
	HTTPProxyPort       int      `mapstructure:"http_proxy_port"        json:"http_proxy_port,omitempty"        yaml:"http_proxy_port,omitempty"`
	SOCKSProxyPort      int      `mapstructure:"socks_proxy_port"       json:"socks_proxy_port,omitempty"       yaml:"socks_proxy_port,omitempty"`

	// AllowManagedDomainsOnly: policy-only knob. When set in
	// policy.yaml, lower sources' allowed_domains are ignored;
	// denied_domains still merges from every source.
	AllowManagedDomainsOnly bool `` /* 129-byte string literal not displayed */
}

SandboxNetConfig mirrors Claude Code's sandbox.network schema.

type SandboxNetworkTier

type SandboxNetworkTier string

SandboxNetworkTier and SandboxFilesystemTier name a coarse, agent-declared sandbox capability level for the worker surface. See docs/design/agent-sandbox-policy.md §4.1: an agent author picks a tier instead of authoring a raw domain or path list, and each tier is a fixed, strictly-ordered superset of the one before it on its own axis.

type SandboxProcessConfig

type SandboxProcessConfig struct {
	// MaxCPUSeconds bounds CPU time (ulimit -t).
	MaxCPUSeconds int `mapstructure:"max_cpu_seconds" json:"max_cpu_seconds,omitempty" yaml:"max_cpu_seconds,omitempty"`
	// MaxMemoryMB bounds virtual memory (ulimit -v, in MB). Not enforced on
	// macOS: Darwin's setrlimit does not support RLIMIT_AS the way Linux
	// does, so bash's `ulimit -v` reports an error there rather than
	// applying a limit. Seatbelt has no resource-limit primitive either
	// (docs/design/sandbox-boundaries.md §7.1) -- this field is Linux-only
	// in practice until a macOS-native mechanism exists.
	MaxMemoryMB int `mapstructure:"max_memory_mb" json:"max_memory_mb,omitempty" yaml:"max_memory_mb,omitempty"`
	// MaxProcesses bounds the number of processes/threads the command's
	// user may hold (ulimit -u).
	MaxProcesses int `mapstructure:"max_processes" json:"max_processes,omitempty" yaml:"max_processes,omitempty"`
	// MaxOpenFiles bounds open file descriptors (ulimit -n).
	MaxOpenFiles int `mapstructure:"max_open_files" json:"max_open_files,omitempty" yaml:"max_open_files,omitempty"`
}

SandboxProcessConfig bounds a sandboxed Bash command's own resource use. Zero means unset -- no limit from this layer -- the same convention SandboxNetConfig's proxy ports already use, and the same restraint worker.k8s.resources documents: BuildMax chooses no numbers, because the right ones depend on the work a deployment runs.

Enforced as `ulimit` shell builtins prefixed onto the wrapped command string (internal/infra/sandbox/bwrap_linux.go, seatbelt_darwin.go), not a Go-side syscall.Setrlimit call: both backends already invoke the command as `/bin/sh -c <command>`, so a shell builtin reaches the sandboxed child on both platforms without new process-spawning machinery, where os/exec.Cmd offers no pre-exec hook to apply a limit to only the child and not the parent buildmax process. See docs/design/sandbox-boundaries.md §9.

type SandboxResolution

type SandboxResolution struct {
	Config SandboxConfig

	// Sources lists every layer that contributed a non-default value, in
	// resolution order: "default", "settings", "env", "run", "policy".
	Sources []string

	// Downgraded reports whether Config is weaker than surface's own
	// baseline on a dimension the worker-hardening promise in
	// docs/design/trust-harness.md §3.2 depends on: enabled, fail-closed on
	// an unavailable backend, or the dangerously_disable_sandbox escape
	// hatch. A layer strengthening the baseline is not a downgrade, only one
	// weakening it — see ResolveSandboxForRun. Runtime fallback (the backend
	// itself turns out to be unavailable) is a second, distinct signal
	// agentapp combines with this one; see sandboxInfo's own comment.
	Downgraded bool
}

SandboxResolution is the resolved sandbox plus a per-field source map for display via `buildmax sandbox status`.

func ResolveSandbox

func ResolveSandbox(global, policy SandboxConfig, surface SandboxSurface) SandboxResolution

ResolveSandbox merges settings + env + policy + surface defaults into a final SandboxConfig. It is the no-run-override, no-agent-tier form used by surfaces that do not expose per-run sandbox controls or agent-declared tiers.

func ResolveSandboxForRun

func ResolveSandboxForRun(global SandboxConfig, run SandboxRunOverride, policy SandboxConfig, surface SandboxSurface, agentTier SandboxConfig) SandboxResolution

ResolveSandboxForRun also applies a narrow per-run override and an agent's declared network/filesystem tier. Mirrors the layering in docs/design/sandbox-boundaries.md §4.1, extended by docs/design/agent-sandbox-policy.md §4.3.

Precedence (highest wins for scalars; arrays union):

  1. Policy file.
  2. Per-run override.
  3. Env (BUILDMAX_SANDBOX_ENABLED).
  4. Agent-declared tier (config.TierSandboxConfig; network/filesystem arrays only).
  5. Settings file.
  6. Surface default.

For the managed-only flags (AllowManagedDomainsOnly, AllowManagedReadPathsOnly) set in policy.yaml, the corresponding allow array in lower sources is suppressed. Deny arrays always union.

type SandboxRunOverride

type SandboxRunOverride struct {
	Enable                   bool
	AutoAllowBashIfSandboxed *bool
}

SandboxRunOverride is the deliberately narrow per-run sandbox surface. A run may require the sandbox and choose its approval mode, but it cannot disable the sandbox or alter confinement boundaries. Requiring it also fails closed when the backend is unavailable. Operator policy is applied after this layer and remains authoritative.

type SandboxSharedPaths

type SandboxSharedPaths struct {
	SharedReadPath    string
	ExternalWritePath string
}

SandboxSharedPaths names the deployment-configured paths the shared-read and external-write filesystem tiers add. Both empty means those two tiers behave exactly like SandboxFilesystemTierWorkspace: a tier can only add a path a deployment actually configured, never invent one.

type SandboxSurface

type SandboxSurface string

SandboxSurface names a runtime surface so ResolveSandbox can pick a surface-appropriate default. Surfaces differ on:

  • default Enabled (off for interactive local, on for the worker)
  • default FailIfUnavailable (off for interactive, on for worker)
  • default AllowUnsandboxedCommands (on for interactive, off for worker)
const (
	// SandboxSurfaceCLI is the local CLI/Desktop default surface. Defaults
	// match today's behavior: sandbox off unless the user opts in.
	SandboxSurfaceCLI SandboxSurface = "cli"
	// SandboxSurfaceWorker is the buildmax-worker default surface.
	// Defaults satisfy docs/design/trust-harness.md §3.2's "stricter than trusted local."
	SandboxSurfaceWorker SandboxSurface = "worker"
)

func WorkerSandboxSurface

func WorkerSandboxSurface() SandboxSurface

WorkerSandboxSurface returns SandboxSurfaceWorker only when this process is running from an image that installs the sandbox's OS backend -- otherwise SandboxSurfaceWorker's own fail_if_unavailable: true baseline would refuse to start every task on a host that cannot provide one. That is exactly what selecting it unconditionally broke: a bare-host local_process deployment, the evaluation runner's black-box worker-surface adapter, and every native-Windows worker, since Windows has no sandbox backend at all -- none of those run from the Docker image this marker names. A Compose local_process deployment does run from that image, so it gets the same baseline a k8s_job worker does: this is about whether the worker's own Bash commands are confined to the run's workspace, a separate question from configuration.md's "local_process is deliberately not being hardened towards" the worker-runs-as-a-different-process-than-the-server boundary, which this does not touch.

EnvKeyBuildmaxSandboxBackendInstalled is WorkerNeeds, because a local_process worker is exec'd with a filtered environment (config.FilterWorkerEnv), not the server's raw one -- unlike a k8s_job pod, which reads the image's own ENV directly and needs no entry here at all.

An operator who has installed bwrap themselves on a bare host can still opt the sandbox in explicitly via BUILDMAX_SANDBOX_ENABLED, which this does not affect; it only changes which surface's baseline a run without an explicit opinion inherits.

type SecretStatus

type SecretStatus struct {
	Set bool `json:"set"`
}

SecretStatus reports that a credential is configured, never anything about its value. Not a prefix, not a length, not a hash: each of those narrows a search for someone who has the response and wants the secret.

type ServerAuditConfig

type ServerAuditConfig struct {
	// RetentionDays expires audit events older than the window. Zero, the
	// default, keeps them forever.
	//
	// Keeping is the default because the trail is evidence, and a deployment
	// that never chose a retention policy has not decided to discard anything.
	// Setting this is a deliberate act with a cost, which is why the sweep
	// records what it removed: a trail that begins partway through then says
	// that policy shortened it, rather than leaving a reader to guess between
	// policy and loss.
	RetentionDays int `mapstructure:"retention_days"`
}

ServerAuditConfig decides how long the governance trail is kept.

type ServerConfig

type ServerConfig struct {
	LogLevel  string `mapstructure:"log_level"`
	Port      int    `mapstructure:"port"`
	JWTSecret string `mapstructure:"jwt_secret"`
	// AccessTokenTTL is how long a signed access token stays valid. It is not
	// stored anywhere, so this is also the window in which a leaked one still
	// works — shortening it costs nothing but refresh traffic.
	AccessTokenTTL time.Duration `mapstructure:"access_token_ttl"`
	// RefreshTokenTTL is how long a login can be renewed without a new login
	// code. Every rotation restarts it, so an active session lives on and an
	// abandoned one expires.
	RefreshTokenTTL time.Duration `mapstructure:"refresh_token_ttl"`
	// RefreshRotationGrace is how long a just-rotated refresh token may be
	// exchanged again before the server treats it as reuse and revokes the
	// session. It absorbs concurrent refreshes from processes sharing one
	// credentials file; it is not a security setting to raise casually.
	RefreshRotationGrace time.Duration `mapstructure:"refresh_rotation_grace"`
	// AllowSignup opens POST /api/otp/request to self-registration. It defaults
	// to false, and the zero value is the safe one on purpose: a server that
	// forgets to configure this is closed, not open.
	AllowSignup bool `mapstructure:"allow_signup"`
	// ShutdownGrace is the whole budget for stopping: draining connections,
	// letting interrupted runs report, and stopping the background loops. The
	// phases are derived from it rather than configured separately, because two
	// knobs that must agree are a way to get them to disagree.
	//
	// It must stay below the orchestrator's own kill deadline —
	// terminationGracePeriodSeconds on Kubernetes, TimeoutStopSec under systemd
	// — or the process is killed partway through an orderly stop. See
	// docs/design/graceful-shutdown.md.
	ShutdownGrace    time.Duration       `mapstructure:"shutdown_grace"`
	CORSOrigin       string              `mapstructure:"cors_origin"`
	WorkspacesDir    string              `mapstructure:"workspaces_dir"`
	DefaultQuotaTier string              `mapstructure:"default_quota_tier"`
	Conversation     ServerConvConfig    `mapstructure:"conversation"`
	LLM              ServerLLMConfig     `mapstructure:"llm"`
	Database         ServerDBConfig      `mapstructure:"database"`
	Webhook          ServerWebhookConfig `mapstructure:"webhook"`
	Worker           ServerWorkerConfig  `mapstructure:"worker"`
	Storage          ServerStorageConfig `mapstructure:"storage"`
	Audit            ServerAuditConfig   `mapstructure:"audit"`
}

ServerConfig is the root of BUILDMAX_HOME/server.yaml.

func LoadServerConfig

func LoadServerConfig() (ServerConfig, error)

LoadServerConfig reads BUILDMAX_HOME/server.yaml via Viper and applies defaults. Secret-bearing fields, cors_origin, and worker.server_url can be overridden by the environment variables above and in env_spec.go. A missing file is not an error — returns a config with all defaults applied.

func (ServerConfig) Redacted

func (sc ServerConfig) Redacted() RedactedServerConfig

Redacted returns the operator-facing view of the configuration.

type ServerConvConfig

type ServerConvConfig struct {
	Model ServerModelEntry `mapstructure:"model"`
	// ModelTarget names a catalog model (an llm_model row) to use for Tier 1
	// inference instead of the model above. It is a catalog ID, not a team
	// alias: the server picks its own model rather than being granted one.
	ModelTarget string `mapstructure:"model_target"`
}

ServerConvConfig holds Tier 1 conversation LLM settings.

type ServerDBConfig

type ServerDBConfig struct {
	Host     string `mapstructure:"host"`
	Port     int    `mapstructure:"port"`
	User     string `mapstructure:"user"`
	Password string `mapstructure:"password"`
	Name     string `mapstructure:"name"`
	// TLS is the go-sql-driver tls parameter. Empty means DefaultDBTLSMode.
	//
	// A deployment pointing at a database it already runs — RDS, Aurora, Cloud
	// SQL — is the case this exists for: most managed MySQL either requires TLS
	// or is reached over a network where the credentials should not travel in
	// the clear.
	//
	// Values: "preferred" (TLS when the server offers it, certificate not
	// verified), "true" (require TLS and verify the certificate against the
	// system roots), "skip-verify" (require TLS, accept any certificate), or
	// "false" (never).
	TLS string `mapstructure:"tls"`
}

ServerDBConfig holds MySQL connection settings.

func (ServerDBConfig) DSN

func (d ServerDBConfig) DSN() string

DSN builds a MySQL DSN from the database config.

type ServerK8sConfig

type ServerK8sConfig struct {
	Namespace string `mapstructure:"namespace"`
	Image     string `mapstructure:"image"`
	// ConfigMap names a ConfigMap holding a server.yaml key. It is mounted into
	// every worker pod so the worker reads the same configuration the server does.
	// Empty means no config file is mounted and the worker relies on inherited
	// environment variables alone, which is rarely enough.
	ConfigMap string `mapstructure:"config_map"`
	// HomeDir is BUILDMAX_HOME inside a worker pod; server.yaml is mounted there.
	HomeDir string `mapstructure:"home_dir"`
	// Resources bounds a worker pod. Every bound is required in this run mode:
	// the server refuses to start rather than schedule a worker that model-
	// chosen commands could run unbounded.
	Resources ServerK8sResources `mapstructure:"resources"`
}

ServerK8sConfig holds Kubernetes worker job settings.

type ServerK8sResources

type ServerK8sResources struct {
	CPURequest    string `mapstructure:"cpu_request"`
	CPULimit      string `mapstructure:"cpu_limit"`
	MemoryRequest string `mapstructure:"memory_request"`
	MemoryLimit   string `mapstructure:"memory_limit"`
}

ServerK8sResources holds Kubernetes quantity strings for a worker pod.

type ServerLLMConfig

type ServerLLMConfig struct {
	// DefaultModel names the catalog model a caller gets when it names none.
	// Empty falls back to the first model in the catalog, so a single-model
	// deployment needs no configuration at all.
	DefaultModel string `mapstructure:"default_model"`
}

ServerLLMConfig is the deployment's managed-model configuration. The catalog itself lives in the llm_model table, edited with `buildmax-server model`, because it holds provider credentials and changes while the server runs.

Every catalog model is available to every user of the deployment: a team is a collaboration boundary, not a model authorization boundary. See docs/design/client-modes.md section 5.

It is optional. A server with no llm section serves Tier 1 conversations from conversation.model and lets callers name any catalog model.

type ServerMinIOConfig

type ServerMinIOConfig struct {
	Endpoint  string `mapstructure:"endpoint"`
	Region    string `mapstructure:"region"`
	AccessKey string `mapstructure:"access_key"`
	SecretKey string `mapstructure:"secret_key"`
	Bucket    string `mapstructure:"bucket"`
	Prefix    string `mapstructure:"prefix"`
	// PathStyle forces bucket-in-path addressing. Unset derives it from
	// endpoint: set means an S3-compatible store such as MinIO, which needs
	// path style; empty means real AWS S3, which does not. Set it explicitly
	// for a compatible store that uses virtual-host addressing.
	PathStyle *bool `mapstructure:"path_style"`
}

ServerMinIOConfig holds MinIO/S3 connection settings.

type ServerModelEntry

type ServerModelEntry struct {
	Model         string `mapstructure:"model"`
	Name          string `mapstructure:"name"`
	APIURL        string `mapstructure:"api_url"`
	APIKey        string `mapstructure:"api_key"`
	ContextWindow int    `mapstructure:"context_window"`
	CallTimeout   int    `mapstructure:"call_timeout"` // seconds; 0 = uses DefaultCallTimeoutSecs
	MaxTokens     int    `mapstructure:"max_tokens"`   // 0 = the adapter's own default
	// Provider is the wire protocol this model speaks. Empty means
	// LLMProviderOpenAICompatible.
	Provider string `mapstructure:"provider"`
	// Reasoning is the effort level: off (the default), low, medium, or high.
	Reasoning string `mapstructure:"reasoning"`
	// CacheControl is this model's prompt-cache policy.
	CacheControl *CacheControl `mapstructure:"cache_control"`
	// Pricing is what this model charges; without it cost is unavailable.
	Pricing *ModelPricing `mapstructure:"pricing"`
	// Vision says this model accepts image input.
	Vision bool `mapstructure:"vision"`
}

ServerModelEntry is the LLM model used for Tier 1 conversation.

func (ServerModelEntry) RuntimeModelEntry

func (m ServerModelEntry) RuntimeModelEntry() ModelEntry

RuntimeModelEntry converts the server's resolved model configuration into the model shape used by the shared agent runtime. Environment overrides have already been applied before this conversion, so credentials stay in memory.

This is the direct path: the entry carries the server's own credential and the run calls the provider itself. A managed run is assembled elsewhere, from what the server told it at dispatch — see internal/bootstrap.resolveRunModel.

type ServerStorageConfig

type ServerStorageConfig struct {
	PersistBackend  string            `mapstructure:"persist_backend"`
	ArtifactBackend string            `mapstructure:"artifact_backend"`
	MinIO           ServerMinIOConfig `mapstructure:"minio"`
	// MaxArtifactMB caps one artifact upload. Zero uses the built-in default.
	//
	// It is a per-file limit, not a team storage allowance. The allowance is a
	// stock rather than a rate and lives in the quota tier as
	// max_storage_bytes; this stays the cap on any one request.
	MaxArtifactMB int `mapstructure:"max_artifact_mb"`
	// ArtifactPurgeAfterDays delays reclaiming a deleted artifact's object.
	//
	// Zero, the default, reclaims it on the next retention sweep: deletion has
	// already taken effect at the authorization boundary, so holding the bytes
	// afterwards is cost and exposure rather than safety. A deployment that
	// wants a window in which an operator could still recover the object from
	// the bucket sets a number of days here — BuildMax itself offers no
	// undelete, so the window is for the bucket's own tooling.
	ArtifactPurgeAfterDays int `mapstructure:"artifact_purge_after_days"`
}

ServerStorageConfig holds blob storage backend selection and MinIO settings.

type ServerWebhookConfig

type ServerWebhookConfig struct {
	MessagePath string `mapstructure:"message_path"`
	UserID      string `mapstructure:"user_id"`
}

ServerWebhookConfig holds webhook handler options.

type ServerWorkerConfig

type ServerWorkerConfig struct {
	Binary    string                `mapstructure:"binary"`
	RunMode   string                `mapstructure:"run_mode"`
	ServerURL string                `mapstructure:"server_url"`
	LLM       ServerWorkerLLMConfig `mapstructure:"llm"`
	K8s       ServerK8sConfig       `mapstructure:"k8s"`
	// RunTokenTTL bounds a run token. Zero uses authtoken's default. It has to
	// outlast the longest run: the token is not renewable, so a run that outlives
	// it can no longer report anything, including its own result.
	RunTokenTTL time.Duration `mapstructure:"run_token_ttl"`
	// RunTimeout is how long a run may stay SCHEDULED or RUNNING before the
	// server records it as abandoned. Zero uses the scheduler's default.
	//
	// Only the worker moves a run out of those states, so without this a run
	// whose worker died stays there forever. Keep it at or below RunTokenTTL: a
	// run that outlived its credential cannot report an outcome, so nothing else
	// will ever close it.
	RunTimeout time.Duration `mapstructure:"run_timeout"`
}

ServerWorkerConfig holds worker launch and connection options.

type ServerWorkerLLMConfig

type ServerWorkerLLMConfig struct {
	// Transport is TransportDirect or TransportBuildMax. Empty means direct,
	// which is what every existing deployment gets.
	Transport string `mapstructure:"transport"`
	// Model is the catalog model a managed run calls. Empty uses the
	// deployment's llm.default_model.
	Model string `mapstructure:"model"`
	// ContextWindow and CallTimeout describe the alias to the run. The protocol
	// does not report them per call, so they come from configuration or stay
	// unset.
	ContextWindow int `mapstructure:"context_window"`
	CallTimeout   int `mapstructure:"call_timeout"`
}

ServerWorkerLLMConfig decides how a task run reaches a model.

The choice is the operator's and lives on the server, not in the worker's hands: a worker executes model-chosen code, so it is told which transport and alias to use rather than selecting them.

func (ServerWorkerLLMConfig) Managed

func (c ServerWorkerLLMConfig) Managed() bool

Managed reports whether task runs call the gateway instead of a provider.

type Settings

type Settings struct {
	LogLevel  string       `mapstructure:"log_level"`
	ServerURL string       `mapstructure:"server_url"`
	Models    []ModelEntry `mapstructure:"models"`
	// DefaultModel names the entry in Models a new session starts with, by name
	// or by model id. Empty uses the first entry, so a single-model file needs
	// nothing here. A name matching nothing is reported by `buildmax doctor`
	// rather than silently falling back, because the fallback would answer with
	// a model the file says is not the default.
	//
	// It applies to local mode only: in managed mode the deployment says which
	// of its models is the default. See docs/design/client-modes.md section 7.
	DefaultModel string          `mapstructure:"default_model"`
	Hooks        corehook.Config `mapstructure:"hooks"`
	Sandbox      SandboxConfig   `mapstructure:"sandbox"`
	Tools        ToolsConfig     `mapstructure:"tools"`
	Agent        AgentConfig     `mapstructure:"agent"`
}

Settings is the root structure for settings.yaml (BUILDMAX_HOME/settings.yaml). Used by the CLI and desktop app.

func LoadSettings

func LoadSettings() (Settings, error)

LoadSettings reads BUILDMAX_HOME/settings.yaml via Viper. BUILDMAX_SERVER_URL overrides server_url. A missing file is not an error; environment overrides are still returned so callers can run from deploy-time configuration alone.

type ToolsConfig

type ToolsConfig struct {
	// Permissions maps a tool key to allow, ask, or deny. A key is a tool name
	// ("Write") or a tool name plus the target it dispatches to
	// ("CallMcpTool:github/create_issue"), optionally with a trailing "*".
	Permissions map[string]string `mapstructure:"permissions" json:"permissions,omitempty" yaml:"permissions,omitempty"`
}

ToolsConfig is the "tools" block of settings.yaml.

type TurnDigestConfig

type TurnDigestConfig struct {
	// Recap prints a dim summary of the turn under the reply.
	Recap *bool `mapstructure:"recap" json:"recap,omitempty" yaml:"recap,omitempty"`
	// Suggest offers the predicted answer as ghost text in the input box.
	Suggest *bool `mapstructure:"suggest" json:"suggest,omitempty" yaml:"suggest,omitempty"`
}

TurnDigestConfig is the "agent.turn_digest" block: one extra model call at the end of a turn that writes a recap of what the turn did and predicts the answer the user is about to type. Neither ever enters the conversation.

Both parts default on, so the fields are pointers: a plain bool cannot tell "the file said false" from "the file said nothing", and the answer to a billed behavior must not depend on that distinction.

type WorkspaceStorageConfig

type WorkspaceStorageConfig struct {
	PersistProvider  string
	ArtifactProvider string
	Endpoint         string
	Region           string
	AccessKey        string
	SecretKey        string
	Bucket           string
	Prefix           string
	// PathStyle forces bucket-in-path addressing on or off. Nil derives it
	// from Endpoint, which is the right answer for both of the cases that
	// actually occur — see bootstrap.BuildS3Client.
	PathStyle *bool
}

WorkspaceStorageConfig holds resolved provider selection and S3/MinIO connection settings. Populated from ServerStorageConfig by bootstrap; not read from env directly.

Jump to

Keyboard shortcuts

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