Documentation
¶
Overview ¶
Package config provides configuration loading and defaults.
Index ¶
- Constants
- Variables
- func AgentDefSources(workspace string, plugins []DiscoveredPlugin) []plugin.Source
- func AgentDefsSearchPaths(workspace string) []string
- func AuthPath() string
- func CacheModes() []string
- func CacheTTLs() []string
- func DataDir() string
- func FilterWorkerEnv(environ []string, managedLLM bool) []string
- func KnownCacheMode(mode string) bool
- func KnownCacheTTL(ttl string) bool
- func KnownLLMProvider(name string) bool
- func KnownReasoningEffort(level string) bool
- func LoadMCPConfigForWorkspace(workspaceDir string) (*coremcp.ConfigRoot, error)
- func LoadWorkspaceHooks(workspace string) (corehook.Config, error)
- func LogLevel(fromSettings string) string
- func LogsDir() string
- func MergeHooks(layers ...corehook.Config) corehook.Config
- func PersistentWorkspaceDir(workspacesDir, workspaceID string) string
- func PluginRootFor(p DiscoveredPlugin) string
- func PluginsDir() string
- func PolicyPath() string
- func ReasoningEfforts() []string
- func ReasoningEnabled(level string) bool
- func ResolveMCPConfigPath(workspaceDir string) string
- func ResolveMaxParallelTools(cfg AgentConfig) int
- func ResolvePricing(in *ModelPricing) (cllm.Pricing, error)
- func RuntimeTaskRunArtifactsDir(workspacesDir, workspaceID, taskID, taskRunID string) string
- func RuntimeTaskRunDir(workspacesDir, workspaceID, taskID, taskRunID string) string
- func RuntimeTaskRunGlobalDir(workspacesDir, workspaceID, taskID, taskRunID string) string
- func RuntimeTaskRunHomeDir(workspacesDir, workspaceID, taskID, taskRunID string) string
- func ServerConfigPath() string
- func SessionsDir() string
- func SettingsPath() string
- func SkillSearchPaths(workspace string) []string
- func SkillSources(workspace string, plugins []DiscoveredPlugin) []plugin.Source
- func TraceEnabled() bool
- func TracesDir() string
- func TurnDigestRecap(cfg TurnDigestConfig) bool
- func TurnDigestSuggest(cfg TurnDigestConfig) bool
- func UpdatePluginStates(pluginsDir string, mutate func(*PluginStates) error) error
- func UserAgent(surface string, viaGateway bool) string
- func ValidateCacheControl(c CacheControl) error
- func VersionString() string
- func WorkerEnvKeys(managedLLM bool) []string
- func WorkerNeedsEnv(name string, managedLLM bool) bool
- func WorkspaceHooksPath(workspace string) string
- type AgentConfig
- type CacheControl
- type DiscoveredPlugin
- type EnvVar
- type LLM
- type MCPResolution
- type ModelEntry
- type ModelPricing
- type PermissionEntry
- type PermissionResolution
- type PluginDiscovery
- type PluginHooks
- type PluginPolicy
- type PluginSource
- type PluginState
- type PluginStates
- type PolicyFile
- type RedactedDBConfig
- type RedactedLLMConfig
- type RedactedModel
- type RedactedServerConfig
- type RedactedStorageConfig
- type RedactedWorkerConfig
- type SandboxConfig
- type SandboxFSConfig
- type SandboxNetConfig
- type SandboxResolution
- type SandboxSurface
- type SecretStatus
- type ServerAuditConfig
- type ServerConfig
- type ServerConvConfig
- type ServerDBConfig
- type ServerK8sConfig
- type ServerK8sResources
- type ServerLLMConfig
- type ServerMinIOConfig
- type ServerModelEntry
- type ServerStorageConfig
- type ServerWebhookConfig
- type ServerWorkerConfig
- type ServerWorkerLLMConfig
- type Settings
- type ToolsConfig
- type TurnDigestConfig
- type WorkspaceStorageConfig
Constants ¶
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.
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.
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.
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.
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.
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).
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_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.
const ( PermissionAllow = "allow" PermissionAsk = "ask" PermissionDeny = "deny" )
Permission actions as written in settings.yaml.
const ( PluginSkillsSubdir = "skills" PluginAgentsSubdir = "agents" )
Plugin content subdirectories. A plugin contributes only what a workspace .buildmax directory already supports, under the same names.
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.
const ( ProviderLocalFS = "local_fs" ProviderMinIO = "minio" )
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.
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.
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".
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.
const DefaultModel = ModelGemini25FlashLite
DefaultModel is the model used when no model is configured.
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.
const DefaultOpenRouterBaseURL = "https://openrouter.ai/api/v1"
DefaultOpenRouterBaseURL is the OpenRouter OpenAI-compatible API base URL.
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.
const EnvKeyBuildmaxSandboxEnabled = "BUILDMAX_SANDBOX_ENABLED"
Env override key. Phase A only honors BUILDMAX_SANDBOX_ENABLED; later phases may add more.
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.
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.
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.
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.
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 ¶
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 ¶
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 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 FilterWorkerEnv ¶
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 ¶
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 KnownLLMProvider ¶
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 ¶
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 ¶
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 ¶
LogLevel returns the effective log level from the config file, defaulting to "info".
func MergeHooks ¶
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 ¶
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 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 ¶
ReasoningEnabled reports whether a configured level asks for reasoning.
func ResolveMCPConfigPath ¶
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 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 ¶
RuntimeTaskRunArtifactsDir returns the run's artifacts dir.
func RuntimeTaskRunDir ¶
RuntimeTaskRunDir returns the run directory for a specific task run.
func RuntimeTaskRunGlobalDir ¶
RuntimeTaskRunGlobalDir returns the run's global dir (BUILDMAX_HOME for that run).
func RuntimeTaskRunHomeDir ¶
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 ¶
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 directory holding durable run traces under DataDir. Layout: <DataDir>/traces/<session_id>/<run_id>.jsonl. 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 ¶
UserAgent identifies BuildMax and the calling surface in outbound requests. viaGateway says BuildMax forwarded the call through its managed gateway.
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 ¶
WorkerEnvKeys returns the environment variable names a worker is given, in declaration order.
func WorkerNeedsEnv ¶
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 ¶
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"`
// 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 ¶
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.
type LLM ¶
LLM holds resolved LLM provider settings.
func EffectiveLLM ¶
EffectiveLLM returns the LLM config and display name using the first model from settings or the env-var fallback.
func EffectiveLLMWithModelName ¶
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 ¶
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"`
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"`
// 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"`
// 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.
Phase A only loads and resolves these values — nothing enforces them yet.
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 (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 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 SandboxResolution ¶
type SandboxResolution struct {
Config SandboxConfig
// Sources lists every layer that contributed a non-default value, in
// resolution order: "default", "settings", "policy", "env".
Sources []string
}
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 + policy + env + surface defaults into a final SandboxConfig. Mirrors the layering in docs/design/sandbox-boundaries.md §4.1.
Precedence (highest wins for scalars; arrays union):
- Env (BUILDMAX_SANDBOX_ENABLED).
- Policy file.
- Settings file.
- 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 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" )
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 and cors_origin can be overridden by the environment variables above. 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"`
// RunAsUser is the uid a worker pod runs as. Zero uses BuildMax's default.
// Set it on clusters that assign their own uid ranges, OpenShift most
// commonly. The worker never needs a uid the image knows about — it writes
// only into mounted volumes.
RunAsUser int64 `mapstructure:"run_as_user"`
// Resources bounds a worker pod. Empty leaves the matching request or limit
// unset, so an existing deployment keeps running unbounded until an
// operator chooses values.
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 and deliberately not a team storage allowance: a
// stock of bytes held is a different measurement from the rates the quota
// model records, and it waits for its own decision. What this already
// settles is that one request cannot cost the deployment unbounded disk.
MaxArtifactMB int `mapstructure:"max_artifact_mb"`
}
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 ¶
LoadSettings reads BUILDMAX_HOME/settings.yaml via Viper. A missing file is not an error — returns (Settings{}, nil) so callers fall back gracefully.
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.