@kaged/local-config

TOML-backed operator-local configuration with Zod validation, file I/O, provider management, tool overrides, and Langfuse tracing settings

7
source files
3
test files
~2.1k
lines
✓ 124 pass
tests
pass
typecheck
clean
lint

Test results 124

WebConfigSchema > accepts empty object [1.74ms]
WebConfigSchema > accepts preferred_provider [0.510ms]
WebConfigSchema > accepts provider_order list [0.340ms]
WebConfigSchema > accepts hard_timeout_ms integer >= 1000 [0.210ms]
WebConfigSchema > rejects hard_timeout_ms below 1000 [0.500ms]
WebConfigSchema > accepts all fields together [0.110ms]
LocalConfigSchema [web] section > accepts local.toml with [web] block + provider overrides [2.10ms]
LocalConfigSchema [web] section > accepts local.toml with [secrets.web] flat map [0.170ms]
LocalConfigSchema [web] section > accepts combined [web] + [secrets.web] [0.300ms]
LocalConfigSchema [web] section > local.toml without [web] still parses [0.120ms]
redactSecrets covers [secrets.web] > redacts [secrets.web] values to <redacted> [0.280ms]
redactSecrets covers [secrets.web] > does not mutate original config [0.150ms]
LocalConfigSchema passthrough on [web] > unknown [web.<provider>] subsections are preserved (passthrough) [0.180ms]
LocalConfigSchema passthrough on [web] > LocalConfigSchema accepts web as a top-level key [0.180ms]
resolveLocalConfigPath > per-user mode with xdgConfigHome [0.080ms]
resolveLocalConfigPath > per-user mode falls back to userHome/.config [0.030ms]
resolveLocalConfigPath > per-user mode throws without userHome or xdgConfigHome [0.060ms]
resolveLocalConfigPath > xdgConfigHome takes priority over userHome in per-user mode [0.020ms]
resolveLocalConfigPath > system-wide mode builds user-specific path [0.040ms]
resolveLocalConfigPath > system-wide mode throws without kagedHome [0.040ms]
resolveLocalConfigPath > system-wide mode throws without userId [0.030ms]
resolveLocalConfigPath > override takes precedence over everything [0.020ms]
resolveLocalConfigPath > override works in system-wide mode too [0.020ms]
serializeLocalConfig > empty config produces valid TOML [0.370ms]
serializeLocalConfig > config with operator_name round-trips [0.250ms]
serializeLocalConfig > config with aliases round-trips [0.250ms]
serializeLocalConfig > config with providers round-trips [0.310ms]
serializeLocalConfig > config with projects round-trips [0.510ms]
serializeLocalConfig > config with audit section round-trips [0.240ms]
serializeLocalConfig > config with plugins round-trips [0.340ms]
serializeLocalConfig > full config round-trips [0.300ms]
generateDefaultLocalToml > produces valid TOML [0.140ms]
generateDefaultLocalToml > starts with comment header [0.030ms]
generateDefaultLocalToml > parses to config with no projects and no aliases [0.070ms]
readLocalConfigFile > file I/O > reads and parses valid TOML file [1.68ms]
readLocalConfigFile > file I/O > throws ENOENT for missing file [0.310ms]
readLocalConfigFile > file I/O > returns parse errors for invalid TOML [1.12ms]
readLocalConfigFile > file I/O > reads empty file as empty config [0.370ms]
writeLocalConfigFile > file I/O > writes valid TOML that can be read back [0.710ms]
writeLocalConfigFile > file I/O > creates parent directories [0.390ms]
writeLocalConfigFile > file I/O > file has mode 0600 [0.330ms]
writeLocalConfigFile > file I/O > overwrites existing file [0.510ms]
ensureLocalConfigFile > file I/O > creates file if missing and returns created=true [0.640ms]
ensureLocalConfigFile > file I/O > returns existing file with created=false [0.340ms]
ensureLocalConfigFile > file I/O > created file starts with comment header [0.370ms]
ensureLocalConfigFile > file I/O > created file has mode 0600 [0.390ms]
ensureLocalConfigFile > file I/O > idempotent — second call returns created=false [0.530ms]
addProjectEntry > file I/O > adds entry to empty config [0.650ms]
addProjectEntry > file I/O > appends to existing projects list [0.730ms]
addProjectEntry > file I/O > upserts entry with same id [0.600ms]
addProjectEntry > file I/O > preserves other config sections [0.620ms]
addProjectEntry > file I/O > creates file if it does not exist [0.410ms]
addProjectEntry > file I/O > persists to disk — survives re-read [0.540ms]
removeProjectEntry > file I/O > removes existing entry [0.640ms]
removeProjectEntry > file I/O > no-op for unknown id [0.550ms]
removeProjectEntry > file I/O > preserves other entries [0.590ms]
removeProjectEntry > file I/O > preserves other config sections [0.520ms]
removeProjectEntry > file I/O > persists to disk — survives re-read [0.760ms]
TOML parsing > parses full config successfully [0.560ms]
TOML parsing > parses minimal config [0.140ms]
TOML parsing > empty string parses to empty config [0.050ms]
TOML parsing > invalid TOML returns error [0.110ms]
TOML parsing > ui section parsed correctly [0.300ms]
TOML parsing > invalid ui theme rejected [0.240ms]
TOML parsing > provider fields parsed [0.280ms]
TOML parsing > plugin entries parsed [0.250ms]
TOML parsing > project registry parsed [0.250ms]
TOML parsing > invalid project status rejected [0.120ms]
TOML parsing > audit config parsed [0.270ms]
TOML parsing > notifications section is optional [0.090ms]
notifications > accepts empty [notifications] section [0.060ms]
notifications > accepts attention_required routing channel config [0.080ms]
notifications > accepts enabled false to disable a channel [0.060ms]
notifications > accepts web_push config [0.080ms]
notifications > accepts arbitrary per-channel keys via passthrough [0.090ms]
notifications > rejects notifications as a string [0.060ms]
notifications > rejects invalid channel config type [0.070ms]
alias name validation > valid alias names accepted [0.040ms]
alias name validation > alias with colon rejected [0.030ms]
alias name validation > reserved names rejected [0.050ms]
alias name validation > invalid pattern rejected [0.020ms]
alias name validation > parse warns on invalid alias names [0.070ms]
alias target validation > valid targets accepted [0.020ms]
alias target validation > target without colon rejected [0.020ms]
alias target validation > empty provider rejected [0.020ms]
alias target validation > empty model rejected [0.010ms]
alias target validation > parse warns on invalid alias targets [0.060ms]
alias resolution > resolves known alias to provider + model [0.130ms]
alias resolution > resolves local provider alias [0.050ms]
alias resolution > unresolved alias returns alias_unresolved [0.030ms]
alias resolution > alias with missing provider returns provider_missing [0.030ms]
alias resolution > alias chaining (alias → alias) is rejected [0.030ms]
alias resolution > direct provider:model passthrough resolves [0.030ms]
alias resolution > direct provider:model with missing provider [0.030ms]
checkProjectAliases > all aliases resolved [0.080ms]
checkProjectAliases > unresolved alias reported [0.030ms]
checkProjectAliases > empty required list returns empty results [0.020ms]
secret redaction > credentials value is redacted [0.130ms]
secret redaction > credentials env is NOT redacted [0.090ms]
secret redaction > original config is not mutated [0.080ms]
secret redaction > config without providers is unchanged [0.050ms]
plugin store > local plugin is available to all projects [0.090ms]
plugin store > project-scoped plugin has project list [0.100ms]
plugin store > plugin with config [0.080ms]
plugin store > plugin with system_config [0.080ms]
project registry > project with all fields [0.150ms]
project registry > project accent_color is optional [0.070ms]
project registry > project label is parsed [0.080ms]
project registry > project label is optional [0.080ms]
project registry > legacy nickname field still parses (back-compat) [0.080ms]
project registry > multiple projects [0.070ms]
project registry > all three status values accepted [0.170ms]
provider config > provider with credentials env [0.080ms]
provider config > provider with inline credentials value [0.070ms]
provider config > provider without any auth (ollama-style) [0.050ms]
provider config > quoted provider name with dash [0.090ms]
provider config > base_url is accepted as an arbitrary string [0.070ms]
secrets (ADR-0043) > parses secrets section [0.080ms]
secrets (ADR-0043) > secrets are redacted by redactSecrets [0.050ms]
secrets (ADR-0043) > absence of secrets section is fine [0.040ms]
mcp overrides (ADR-0043) > parses mcp server overrides [0.100ms]
mcp overrides (ADR-0043) > absence of mcp section is fine [0.050ms]
mcp overrides (ADR-0043) > mcp override with only disabled field [0.060ms]
mcp overrides (ADR-0043) > mcp override with only timeout_ms field [0.070ms]

Mentioned in

Type Document
adr ADR-0008: Plugins are subprocesses over JSON-RPC on stdio
adr ADR-0010: kaged supports per-user and system-wide deployment, equally
adr ADR-0011: Projects are portable; operator-local concerns live in local config
adr ADR-0014: All LLM providers route through @kaged/llm; Mastra integrates via a LanguageModelV2 shim
adr ADR-0023: Project-plugin lifecycle hooks, per-agent declaration, isolation as a core principle
adr ADR-0024: Context compaction is kaged-owned, layered, observable, and operator-tunable
adr ADR-0033: Tool dot-namespace convention
adr ADR-0036: Unified user identity — shared SSO, three-tier roles, and route-scope authorization
adr ADR-0042: Package distribution, CI, and the release pipeline
adr ADR-0043: MCP as a tool source
adr ADR-0049: Providers are dynamically-loaded modules from an operator-local store; catalog from a self-hosted models.dev mirror; @kaged/llm becomes resolver + loader + middleware
spec Spec: Agent Tooling
spec Spec: Agent Harness
spec Spec: Daemon
spec Spec: HTTP + WebSocket API
spec Spec: LLM Provider Interface
spec Spec: Local config
spec Spec: Operational Logging
spec Spec: Session notifications (daemon side)
spec Spec: Plugin Host
spec Spec: Project DSL
spec Spec: Session Manager
spec Spec: Shared SSO Relay (@kaged/sso)