12. Configuration

In plain words: Design rule 12: Configuration

Available 15 min read 24 glossary terms 23 connected pages
The short version written for the Snayu team

Defines how settings are loaded: one typed Settings model from lychd.toml in the Settings Folder (Codex), plus validated Service Config Files (Runes) for models and services, all checked before they can generate infrastructure.

Why read it: Read this before adding a setting, a config section or a new kind of Service Config File.
  1. 1Precedence is fixed: explicit values, then environment (SECTION__FIELD), then lychd.toml, then file secrets, then defaults.
  2. 2Unknown or obsolete fields are rejected; loading is read-only and never repairs or creates files.
  3. 3Each process keeps one loaded settings generation; a live config writer is designed separately.

Available Settings and Rune loading work; a live config writer and some selectors are designed.

Words on this page, decoded click one for its card

The original text Underlined words open their plain-English card.

Context and decision

The CodexSettings Folder holds declared operator intent. A single typed Settings root and anchored RuneService Config File instances are read, validated, attributed, and assembled before they can project infrastructure.

Settings: one immutable generation

lychd.toml is the global Settings document under the CodexSettings Folder. Its only top-level sections are server, orchestration, extensions, weaver, and optional archive. Settings is the sole BaseSettings model; nested strict BaseModel sections reject unknown and obsolete fields. The public Python entry is lychd.config.settings, not its internal section modules.

Load and retain one generation

Source precedence is fixed:

explicit construction → environment → lychd.toml → Pydantic file secrets → model defaults

Environment names use the root SECTION__FIELD grammar. There is no dotenv source and nested sections do not load separate environment, TOML, or secret sources. Loading is read-only: it does not create CodexSettings Folder files, repair input, generate credentials, or mutate the environment. get_settings() retains one loaded generation per process. Runtime consumers use its stored values; they never reopen environment variables or secret files. Reload requires an explicitly constructed new Settings instance or a process restart. SettingsSnapshot retains a secret-free serialized declaration and the already-loaded credentials separately in memory as SecretStr. Each preview/apply phase revalidates its own copy without running settings sources again.

An accepted Settings field needs a real consumer. server.port is exposed today, but runtime policy fixes the managed image listener independently of TOML. The obsolete server.host, server.reload, server.keep_alive, and server.web.url inputs are rejected and omitted from generated configuration. Launcher flags and environment cannot reintroduce them as CodexSettings Folder intent.

Current selections

[extensions] selects permitted built-in and CryptData Folder packages; it neither selects an application nor creates a runtime. Settings also owns the fixed runs and rites physical queues and their concurrency; routing can name only those queues. Global port claims and RuneService Config File port claims are arbitrated before any unit is written.

The bounded Core BridgeChat selector uses optional [weaver.bridge] to select the registered bridge_chat@2; omission keeps bridge_chat@1 active. Revision 2 admits exactly one of an exact capability_key or a versioned preference. The preference grammar has schema_version = 1 and exactly two distinct route entries, each containing a literal canonical registry capability_key of at most 512 characters and a strict integer weight from 0 through 1,000,000. Booleans, coercion, aliases and a zero total are refused. Zero disables that route's eligibility; larger weights rank first, with ascending canonical key breaking a tie. Weights are unitless ordinal preferences without normalization, not traffic share or measured quality. Both declarations must satisfy the local Chat/tools contract in Dispatcher, including a disabled route.

Admission resolves an existing idempotent RunJob Record before considering current policy or readiness. A fresh preference admission retains its immutable policy and weights, canonical policy digest, safe phase observations, server-observed observation and batch times, closed exclusion codes and selected exact key in the existing RunJob Record intent JSONB before publication. The digest is SHA-256 of canonical typed policy bytes, including schema_version = 1, not a generated JSON Schema fingerprint. Concurrent admission losers return the retained winner. This metadata is server-owned; callers cannot supply or replace it. Graph state retains the selected key across pauses; replay and restart use that key without another preference selection. A changed Settings generation affects new admissions only. Retention excludes free probe reasons, endpoints, principals, credentials and authentication generations. This remains capability identity pinning rather than a durable executable/declaration-generation fingerprint or the general portable Resolution Lock.

This admission policy preserves the existing bridge_chat@2 PatternWorkflow, calls, tools, consent, retries and token bounds. It supplies no post-selection fallback. The AltarControl Panel must explain the retained policy, observations, exclusions and selection at admission, the absence of fallback, and the distinct replay/restart and new-admission semantics before this feature is published. Display neither grants authority nor establishes current readiness. Implementation and delivery evidence remain owned by State of Work.

An explicit revision = "3" selects the read-only ArchiveLong-term Memory answer profile and additionally requires an archive binding with exact local-public-notes@1 profile, namespace UUID, trusted local subject, and policy revision. It is valid only with PostgreSQL and the same-host bootstrap custody profile. The whole binding is retained at RunJob Record admission; changed settings cannot rewrite an admitted casting. This selector grants no remote identity, namespace access, ingestion, or embedding capability. Intake and promotion remain separate explicit ArchiveLong-term Memory operations. Revisions 3 and 4 continue to require their exact capability_key and their own ArchiveLong-term Memory or ScoutWeb Fetcher binding respectively; neither accepts preference.

Exact delegated casting selection

Optional [weaver.delegation] selects revision = "2", one exact registered runtime, and profile (read, candidate, or verify) for new /delegate admissions. Omission retains the effect-free delegated_rite@1 reference route. The configured revision retains its runtime binding in RunJob Record intent and GraphStep Map state; idempotent admission and restart use that retained binding, not the current Settings generation. Unknown adapter names refuse assembly. Registration and selection do not establish host readiness, containment, privacy, or permission to launch.

The adapter's trusted host remains responsible for effect-time admission. This selector carries no command, executable, environment, provider credential, model alias, alternate list, or fallback switch. A failure, policy refusal, or uncertain start leaves the exact casting in place; it cannot redirect to another runtime. Provider/Gate configuration and compatible-road fallback require their own admitted contracts.

Exact Creation investigation selection

Optional [weaver.creation] selects revision = "2" and one exact capability_key for creation.investigation@2 / creation.investigate@2. Omission disables its admission. This bounded application requires PostgreSQL, current local operator policy and its fixed public-source profile. The captured local shared vLLM/Qwen Chat declaration must match its generation and policy; no alias, fallback, remote route or hardware transition is supplied by selection.

Creation retains source bytes, criteria, complete role bindings and reservation under its own case before releasing held RunJob Record delivery. Current settings cannot rewrite an existing request; an eligible explicit continuation retains the same case/profile and its original deadline. Settings carries neither source/prompt material nor a credential or authority grant. The application rechecks current credential-backed object/action policy at use. This typed selection does not introduce a general SDLC coordinator or portable Resolution Lock.

Exact finite Scavenger selection

Optional [weaver.scavenger] selects CompositionApp revision = "3" and one explicit scout configuration with rss-public-feed@1 for the source-built scavenger.observe_market@2 PatternWorkflow. Omission disables new Scavenger admission while retaining its exact registered PatternWorkflow for historical resolution. The selection requires PostgreSQL and the actual same-host startup credential owner; settings loading and assembly perform no acquisition, model readiness, reservation or migration. It accepts no capability key, model, arbitrary source locator, implementation name or fallback. A separately configured ordinary BridgeChat remains independent.

The first native profile permits one active ScoutWeb Fetcher binding in a fresh profile database. It cannot coexist with BridgeChat revision4's page binding. Existing page/RSS budget rows reject a changed binding without mutation; changing the selector never resets spent counters or unknown claims. The profile pins its exact native resolver/custody assertion, CA/extractor runtime, current policy, finite allowance/host ceilings and review expiry. These are declarations, not containment or source-publicness evidence. The exact advertised Bazoš PC feed and consumer projection remain owned by Scout and Scavenger.

The complete supplied campaign seed and initial filter enter Scavenger's protected application admission, never Settings or a model prompt. Their immutable consumer/digests bind the held RunJob Record before publication. Current application read/filter/delete policy is distinct from acquisition consent and expiry; configuration cannot refresh a retained grant, refetch lost material, rewrite a committed field or resurrect a tombstone. Selected assembly, API/UI and deployed evidence remain owned by State of Work.

Independent public Archive selection

Optional [archive] selects profile independently of BridgeChat. Its profile retains the exact local-public-notes@1 schema. Existing weaver.bridge.archive configuration remains valid; when both are supplied they must match exactly, and assembly uses one effective binding. Omission preserves the existing BridgeChat selection and disables independent derivation.

Optional archive.derivation supplies a generation UUID and an exact Core EmbeddingBinding (capability key, profile digest, model.embed@1). The configured registry must admit that local static profile before assembly succeeds. An HTTP caller cannot provide an endpoint, model, manifest or fallback. Loading settings and assembling services neither registers a generation in PostgreSQL nor prepares a model. Explicit authorized registration retains the configured manifest; explicit derivation requests perform bounded synchronous work.

The derivation DispatcherTraffic Controller shares the application's exact registry and lease ledger but has no RunJob Record event sink. A supplied RunJob Record UUID is caller attribution only: it neither establishes a RunJob Record relationship nor permits events or writes to that RunJob Record. The existing GraphStep Map dispatcher is unchanged.

Runes: location, provenance, semantics

A RuneService Config File is one validated top-level TOML instance in the CodexSettings Folder runes/ tree, not a runtime object or generated unit. Each concrete RuneConfig supplies one safe path_fragment; direct Python subclassing forms one anchor ancestry, and relative_path is computed from it. A fragment is one segment matching ^[a-z0-9](?:[a-z0-9_-]{0,48}[a-z0-9])?$. Distinct registered schemas cannot own the same exact anchor; nested anchors remain distinct and express declared class ancestry. Nested non-Rune Pydantic value objects may contribute shared validated structure without joining or branching that anchor ancestry. The delivered QuadletConfig is embedded under the quadlet field of SoulstoneLocal Model and Phoenix RunesService Config Files and shares only the minimum OCI image invariant; it supplies neither a RuneService Config File path nor raw unit, lifecycle, mount, network, secret, or command authority. Generic sample generation renders required embedded values as typed TOML inline tables; maintained hand-authored examples may use the equivalent named table form such as [quadlet]. Branch classes are namespaces and cannot own TOML files; only leaf schemas may have one or more instances. A file's path supplies its identity and source_file provenance. Duplicate identity, files in branch anchors, arrays-of-tables instance encoding, unsafe fragments, and schema violations abort discovery.

Three terms describe a RuneService Config File's location. An Anchor owns a directory territory; a Fragment is its safe local path segment; and an Instance is one leaf TOML document. The instance carries provenance into runtime, but provenance is not a TOML field. Validation freezes instances so that resolvers can derive effective state without changing CodexSettings Folder intent.

Filesystem ancestry names type, not semantic defaults. Named leaf profile instances supply family-specific defaults; a capability-bearing RuneService Config File references profiles and applies local overlays. Resolvers combine profile, runtime/family defaults, local overlay, then request-time override. Presets such as a llama.cpp router .ini are typed, readable references: they tune their runtime but cannot change port arbitration, coven exclusivity, or host ownership. Upstream precedence is CLI arguments > model-specific preset section > global [*] section; a generated CLI override that deliberately shadows a preset value must remain visible to the operator.

General-service declarations and current model blocks

The accepted general-service RuneService Config File shape uses first-class [[capabilities]] entries. Each entry references one registered semantic interface and exact immutable profile, declares its permitted operations and invocation mode, and pins the runtime driver/dialect, conformance evidence, resource envelope, and containment profile required to make that instance honest. Definitions are typed Contributions governed by their receiving Core office or Extension DomainPlug-in Area and retain the Registrant's registrant_id; an implementation profile separately names its concrete Provider. A RuneService Config File selects those definitions and supplies instance-local endpoint, secret reference, lifecycle, and explicit overlay values. It cannot redefine their schemas, licenses, or proved limits inline.

Current source delivers only [[models]]: models behind one RuneService Config File instance with closed families, input modalities, Chat or Responses surface, tool support, context size, and generation overlays. Streaming support and output modalities have no configurable v1 fields. Those blocks remain v1 compatibility sugar for exact admitted model-interface projections; non-model services never invent a model_id or generation overlay merely to become loadable. Neither form encodes multiple RuneService Config File instances.

The single GenerationProfile owns the common context, output-token, temperature and top-p overlays. Its optional closed thinking = "qwen3.8-non-thinking" policy is model-local: only an explicit [[models]] generation block for local vLLM Qwen3.8-27B on the Chat surface may select it. Runtime defaults, Soulstone-wide defaults, PortalsCloud Models and other model/runtime/surface combinations refuse a non-null policy before publication. Omission preserves the existing request. This is one admitted self-hosted chat-template dialect, not arbitrary provider settings or model-name inference.

For the current v1 path, capability synthesis begins with text input. Field precedence is RuneService Config File hint, then live probe or adapter-discovered runtime fact, then runtime profile default. An explicit modality hint replaces discovered and default modalities; when omitted, probed modalities may enrich the runtime base. In v2, open facts are profile-specific and a live probe may establish readiness but never invent an interface, operation, language, format, dialect, or permission. Dispatcher (22) may verify a declared capability only by downgrading it.

Extension activation and application selection

Selected extension registration shims add RuneConfig types to context.runes; the loader is given that explicit schema list and never scans packages. A Configurable extension registers its schema through this contract, then separately registers any runtime definition or adapter in its own domain store. Importing a package does not register it; registering a schema does not create a service. Extensions cannot introduce custom loaders, source precedence, parsers, or type= dispatch. Extensions (05) owns compatibility tiers.

The complete preauthorization RuneService Config File generation is validated before durable reconciliation. Duplicate slugs fail deterministically, and an incoming RuneService Config File cannot replace a row whose durable owner is not codex:rune. Only after those checks may one transaction refresh Rune-owned rows, retain their usage and operator-enabled state, mark absent Rune-owned policies unavailable, and publish newly admitted policies.

Realization and the writable Codex

init and init --dry-run derive the same LifecyclePlan. The real command rejects UID 0, inscribes missing anchors and inactive leaf samples, and must round-trip a generated Settings TOML through fresh validation. Marked samples are ignored until their marker is removed. bind first uses one immutable Settings/extension/RuneService Config File generation to compile declarations, then revalidates the foundation, secret presence, generations, and receipts under the lifecycle lock immediately before mutation. A content-identical reconciliation is a no-op; an indeterminate mutation keeps recovery evidence. Layout (13) owns path creation, locks, receipts, and filesystem attestation; Privilege (10) owns trusted host executables and their permissions.

Assembly proceeds from Settings to selected schemas, then to discovered and validated RuneService Config File instances. It enforces identity, domain policy, and ports before projecting exact Scribe-owned units. Downstream registries consume that generation rather than reopening the RuneService Config File filesystem. Read, syntax, and schema-validation failures identify the source file; schema failures also retain their field diagnostics and original validation cause.

A sanctioned live CodexSettings Folder writer is designed separately from current sample writing. It must stage a typed request, validate the complete staged tree as bind would, atomically rename only after that validation, and use an explicit reload signal. It has no ambient authority from Smith or AltarControl Panel. Core promotion needs live HitLApproval Step; a narrower preauthorization must be expressly lawful. No hot reload is delivered. State of Work records this path as Designed.

Secrets, privacy, autonomy, and projections

CodexSettings Folder stores only secret references (including *_secret), never values. Settings sources resolve the database password and application signing key once during construction into excluded, non-repr SecretStr fields. Explicit construction and root-grammar environment values take precedence over the existing LYCHD_DB_PASSWORD / LYCHD_APP_SECRET_KEY environment aliases, then their *_FILE paths, then /run/secrets/<declared-name>. TOML credential values are rejected. An absent default mount leaves the credential unset so host init and caged bind can run before provisioning; database/web assembly rejects unset runtime credentials without further I/O. Explicit file overrides must be readable and nonempty at Settings construction. Nested settings models perform validation only; explicitly supplied section instances are complete overrides. Bind preflight requires the CodexSettings Folder secret file to be Magus-owned with group and other permissions closed. Generated caged units use file form and scope mounts to the unit that needs them. Filesystem permissions do not isolate code within that unit.

Retired native credential selection

The host-native LYCHD_RUNTIME_SECRETS=podman-core@1 Settings source and its capture/provenance fields are retired. Explicit use of that selector refuses before credential I/O rather than falling back to another owner. Container startup consumes its narrowly mounted /run/secrets inputs through the ordinary sources above. The host operator's trusted Podman secret adapter retains its separate bind/access responsibilities; it is not application startup credential transport. No replacement source, automatic conversion, rotation or credential export is added.

Policy and derived projections

In the accepted design, CodexSettings Folder also sets the privacy/egress baseline (thresholds, anonymization requirement, destination and purpose eligibility, non-declassifiable categories, transformer/verifier profile, receipt lifetime, revision) and autonomy baseline. The designed Policy WardSecurity Desk rejects adaptive PhylacteryMemory Vault state that is more permissive than CodexSettings Folder. Absent explicit authorization, effects require HitLApproval Step or are denied; confidence does not authorize core promotion, migrations, destructive deletion, secret changes, egress broadening, host authority, excessive spending, or cross-identity memory sharing.

VesselEngine Room configuration is the source of truth. A future TombSandbox envelope is derived, secret-free, and cannot alter queues, network, mounts, privacy, autonomy, approval, or authority. TombSandbox receives no CodexSettings Folder mount. Security (09) owns credentials and isolation; the TombSandbox delivery boundary remains Designed.

Future selectors

Application and Gateway profiles

Any further application selector requires its own accepted SpellweaverWorkflow Engine schema and may resolve only one registered exact profile revision, such as one of the mutually exclusive Reach deployment profiles. In Reach, for each Discord application and Habitat partition, that immutable selection binds one authority epoch, one Discord edge epoch, one active PhylacteryMemory Vault, one Gateway/delivery credential owner, and the exact per-host role set. Unknown mixtures and boolean authority switches such as trusted, use_vps, local_db, or tether fail before Bind. The selected profile contributes no raw units: one immutable generation resolves its exact CompositionApp/PatternWorkflow revisions and registered service roles into the ApplicationDeploymentManifest@1, then revalidates global ports, routes, secrets, mounts, migrations, dependencies, and resource policy before Bind.

A change of profile or authority location requires a typed Evolution effect. Settings reload cannot perform it. The transition quiesces admission, settles or preserves external-effect identities, fences the old epochs, and revokes old routes and credential owners. Where authority moves, it transactionally restores an admitted partition. Only then does it activate the new generation; an old or simultaneous generation fails closed.

Gateway placement follows the same exact-profile law. Home and Remote are reference placements of one separate Gateway Host role, not applications, Extension Domains, or free configuration literals. A selected deployment profile either omits that role or binds its exact per-host manifest, Veil routes, optional Tether generation, backend identity, service Principals, edge secrets, firewall and management boundaries, and recovery contract. Loose fields such as gateway=true, rpi, vps, or an arbitrary proxy target cannot assemble a partial edge.

Palette configuration

Presentation configuration obeys the same typed-source law when it is admitted. In particular, a future Altar palette may enter only through an explicitly owned validated Settings field or another Covenant-owned typed source with declared precedence; it is never an unmodelled TOML table, raw CSS file, selector, or extension side channel. Frontend owns the finite semantic colour roles and accessibility rules, while Configuration owns loading, validation, attribution, and immutable generation. Current Settings contains no palette field and changing the accepted root shape requires an implementation and State update.

General casting selection

A future Spellweaver configuration-to-casting selector follows the same root-shape law. Local TOML may select exact already-registered ScrollWorkflow Version, SpellStep implementation, AgentSpec/Posture, and ContextBriefing Pack projection revisions plus bounded policy, with the Agent references resolved only through an exact placement; the portable ScrollWorkflow Version remains canonical JSON. Configuration never names Python imports, BaseNodes, graph edges, callables, prompts, source bytes, credentials, or live handles, and it cannot turn schema registration into executable activation.