12. Configuration
Context and decision
The Codex holds declared operator intent. A single typed Settings root and anchored Rune 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 Codex. 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 Codex 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.
Every accepted field must have one real consumer. Current Settings exposes server.port, but the
managed image listener is fixed by runtime policy rather than TOML. Obsolete server.host,
server.reload, server.keep_alive, and server.web.url inputs are rejected and do not appear in
generated configuration; launcher flags or environment cannot smuggle them back as Codex intent.
Current selections
[extensions] selects permitted built-in and Crypt 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 Rune port claims are
arbitrated before any unit is written.
The bounded Core Bridge 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 Run 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 Run 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 Pattern, calls, tools, consent,
retries and token bounds. It supplies no post-selection fallback. The Altar 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 Archive 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 Run 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 Archive operations.
Revisions 3 and 4 continue to require their exact capability_key and their own Archive or Scout
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 Run intent and Graph 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.
This section accepts no command, executable, environment, provider credential, model alias, alternate list, or fallback switch. An adapter's trusted host still owns effect-time admission. Failure, policy refusal, or an uncertain start never redirects this exact casting to a different runtime. Provider/Gate configuration and compatible-road fallback need 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 Run 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 Composition revision = "3" and one explicit scout
configuration with rss-public-feed@1 for the source-built scavenger.observe_market@2 Pattern.
Omission disables new Scavenger admission while retaining its exact registered Pattern 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 Bridge remains independent.
The first native profile permits one active Scout binding in a fresh profile database. It cannot coexist with Bridge 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 Run 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 Bridge. 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 Bridge 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 Dispatcher shares the application's exact registry and lease ledger but has no Run event sink. A supplied Run UUID is caller attribution only: it neither establishes a Run relationship nor permits events or writes to that Run. The existing Graph dispatcher is unchanged.
Runes: location, provenance, semantics
A Rune is one validated top-level TOML instance in the Codex 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 Soulstone and Phoenix Runes and shares only the minimum OCI image invariant; it supplies
neither a Rune 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.
An Anchor is an owned directory territory. A Fragment is its safe local path segment. An Instance is one leaf TOML document. Provenance follows an instance at runtime but is not a TOML field. Validated instances are frozen: resolvers may derive effective state but may not alter Codex intent.
Filesystem ancestry names type, not semantic defaults. Named leaf profile instances supply
family-specific defaults; a capability-bearing Rune 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 Rune 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 Domain and retain the
Registrant's registrant_id; an implementation profile separately names its concrete Provider. A
Rune 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 Rune 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
Rune 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, Portals 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 Rune 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 Rune generation is validated before durable reconciliation.
Duplicate slugs fail deterministically, and an incoming Rune 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/Rune 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.
The assembly pipeline is: load and validate Settings; assemble selected schemas; discover and validate Rune instances; enforce identity, domain policy, and ports; then project only exact Scribe-owned units. Downstream registries consume that generation and must not reopen the Rune filesystem. Rune read, syntax and schema-validation failures identify the source file; schema failures retain their field diagnostics and original validation cause.
A sanctioned live Codex 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 Altar. Core promotion needs live HitL; 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
Codex 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 Codex 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, Codex 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 Ward rejects adaptive Phylactery state that is more permissive than Codex. Absent explicit authorization, effects require HitL 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.
Vessel configuration is the source of truth. A future Tomb envelope is derived, secret-free, and cannot alter queues, network, mounts, privacy, autonomy, approval, or authority. Tomb receives no Codex mount. Security (09) owns credentials and isolation; the Tomb delivery boundary remains Designed.
Future selectors
Application and Gateway profiles
Any further application selector requires its own accepted Spellweaver 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 Phylactery, 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 Composition/Pattern revisions and registered service roles into the
ApplicationDeploymentManifest@1, then
revalidates global ports, routes, secrets, mounts, migrations, dependencies, and resource policy
before Bind.
Changing profile or authority location is a typed Evolution effect, not Settings reload. It must quiesce admission, settle or preserve external-effect identities, fence the old epochs, revoke old routes and credential owners, transactionally restore an admitted partition when authority moves, and activate the new generation last. 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 Scroll, Spell
implementation, AgentSpec/Posture, and Context projection revisions plus bounded policy, with the
Agent references resolved only through an exact placement; the portable Scroll 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.