config — top-level modules
config.loader
Load non-secret configuration into frozen, typed dataclasses.
Secrets are never stored here. get_secret is the single sanctioned access point for
later phases, and reads the environment (Keychain-backed in the owner's setup) only.
REPO_ROOT = Path(__file__).resolve().parent.parent
module-attribute
LEVERS_OVERLAY = Path(__file__).resolve().parent / 'levers.toml'
module-attribute
OllamaConfig
dataclass
host
instance-attribute
port
instance-attribute
default_keep_alive
instance-attribute
request_timeout_s
instance-attribute
generation_timeout_s
instance-attribute
base_url
property
ResourceConfig
dataclass
usable_ram_gb
instance-attribute
max_resident_models
instance-attribute
PathsConfig
dataclass
data_dir
instance-attribute
telemetry_db
instance-attribute
raw_store
instance-attribute
vector_store
instance-attribute
derived_store
instance-attribute
vault_catalog
instance-attribute
attestation_store
instance-attribute
VaultConfig
dataclass
path
instance-attribute
pattern
instance-attribute
watch_debounce_s = 1.0
class-attribute
instance-attribute
watch_poll_interval_s = 5.0
class-attribute
instance-attribute
EmbeddingConfig
dataclass
model
instance-attribute
dim
instance-attribute
query_instruction
instance-attribute
DreamingConfig
dataclass
similarity_threshold
instance-attribute
min_cluster_size
instance-attribute
max_clusters
instance-attribute
near_dup_threshold
instance-attribute
DreamRnDConfig
dataclass
Dream-phase R&D track (FEATURE-FLAG OFF by default). The interpreter panel + adjudicator
refuse to run unless enabled is True — see core/dreaming/rnd.py.
enabled
instance-attribute
sigma
instance-attribute
min_degree
instance-attribute
bridge_clustering_max
instance-attribute
centrality_top_k
instance-attribute
agreement_jaccard
instance-attribute
bridge_top_k
instance-attribute
hole_min_persistence
instance-attribute
sbm_k_max
instance-attribute
InterfaceConfig
dataclass
handoff_dir
instance-attribute
default_adapter
instance-attribute
AmbassadorConfig
dataclass
The conversational front door (Track B). Runs on the pinned tier (always warm); these
are its judgment bounds, not behavior switches: retrieval_k caps per-turn retrieval depth
(the budgeter enforces the window regardless), history_max_turns caps the cheap in-memory
working context (older context is RE-retrieved from the authored-dialogue corpus, not
double-stored), and interruption_sensitivity ∈ {off, earned_only, verbose} is the
owner-tunable unprompted-message dial (default earned_only — note §3).
retrieval_k = 5
class-attribute
instance-attribute
history_max_turns = 6
class-attribute
instance-attribute
interruption_sensitivity = 'earned_only'
class-attribute
instance-attribute
MonitorConfig
dataclass
The edge monitor — a small dashboard + chat surface over Tailscale (Zone B). A SEPARATE
process palace supervises; it reads the core-emitted status snapshot and relays chat over the
interface handoff, never importing core (Invariant 2). OFF by default; bind host to the
Tailscale IP (not 0.0.0.0) so the tailnet is the auth boundary, same as the note-sync setup.
status_path is where the launcher writes the metadata snapshot the dashboard renders.
enabled = False
class-attribute
instance-attribute
host = '127.0.0.1'
class-attribute
instance-attribute
port = 8787
class-attribute
instance-attribute
status_path = Path('data/monitor/status.json')
class-attribute
instance-attribute
request_timeout_s = 30.0
class-attribute
instance-attribute
EffectorsConfig
dataclass
Track G effector surface (docs/design-notes/hands-and-the-effector-layer.md). Fail-closed
twice over: enabled off refuses to build either side of the handoff, and an empty
upstreams allowlist refuses every fetch even when enabled. upstreams is (name, url)
pairs — the ONLY place a URL exists in the sensing path; the core-side request carries
just the name.
Sensing (β = 0) is the only class the WIRED surface admits (EffectView ceiling ε = SENSING).
The acting-class knobs below (ledger_db, drafts_dir, jit_credential_ttl) support the
built-but-off reversible/irreversible hands (G5/G6): the durable effect ledger, where a
reversible write stages its draft, and the short TTL of the per-action JIT credential minted at
send time. They are inert until ε is deliberately raised past sensing.
enabled = False
class-attribute
instance-attribute
handoff_dir = Path('data/handoff/sensing')
class-attribute
instance-attribute
timeout_s = 20.0
class-attribute
instance-attribute
max_response_kb = 512
class-attribute
instance-attribute
upstreams = ()
class-attribute
instance-attribute
ledger_db = Path('data/effectors/effects.sqlite')
class-attribute
instance-attribute
drafts_dir = Path('data/effectors/drafts')
class-attribute
instance-attribute
jit_credential_ttl = '60s'
class-attribute
instance-attribute
AirlockConfig
dataclass
Research airlock (§16). The sealed core uses only handoff_dir; the rest is Zone-B
bridge config (S3 target + the narrowly-scoped assumed role). The core never reads S3.
handoff_dir
instance-attribute
s3_bucket
instance-attribute
s3_region
instance-attribute
aws_profile
instance-attribute
requests_prefix
instance-attribute
results_prefix
instance-attribute
poll_interval_s
instance-attribute
poll_timeout_s
instance-attribute
AttestationConfig
dataclass
Runtime proof layer (attestation-layer.md). Records are always written; enabled gates
SIGNING. Pub-key paths are committed (non-secret); the private seeds live in Keychain/Vault.
enabled = False
class-attribute
instance-attribute
signing_key_secret = 'attestation-signing-key'
class-attribute
instance-attribute
owner_key_secret = 'attestation-owner-key'
class-attribute
instance-attribute
supervisor_pub = Path('ops/attestation/supervisor.pub')
class-attribute
instance-attribute
owner_pub = Path('ops/attestation/owner.pub')
class-attribute
instance-attribute
SecretsConfig
dataclass
Vault as a per-interaction runtime authorization layer (vault-runtime-auth.md). enabled
only gates whether build_secrets_backend wires a real VaultClient — get_secret(name)
with no token is unaffected either way (env/Keychain, unchanged).
enabled = False
class-attribute
instance-attribute
addr = 'http://127.0.0.1:8200'
class-attribute
instance-attribute
kv_mount = 'kv'
class-attribute
instance-attribute
aws_mount = 'aws'
class-attribute
instance-attribute
grant_roles = frozenset()
class-attribute
instance-attribute
token_ttl = '10m'
class-attribute
instance-attribute
BackupConfig
dataclass
restic → S3 encrypted backups (BUILD-SPEC §16b). restic encrypts + deduplicates CLIENT-SIDE,
so AWS never sees plaintext; the bucket's SSE-KMS is defense in depth. enabled gates the
scheduled job only. The repo password and the backup AWS key live in Keychain (named here, never
stored here). Off by default — turn on per machine via config/local.toml once the bucket is
applied and Keychain is placed.
enabled = False
class-attribute
instance-attribute
repository = ''
class-attribute
instance-attribute
password_secret = 'restic-password'
class-attribute
instance-attribute
aws_access_key_id_secret = 'backup-aws-access-key-id'
class-attribute
instance-attribute
aws_secret_access_key_secret = 'backup-aws-secret-access-key'
class-attribute
instance-attribute
region = 'us-east-1'
class-attribute
instance-attribute
vault_snapshot = True
class-attribute
instance-attribute
exclude = ('logs', 'queue.sqlite', 'queue.sqlite-wal', 'queue.sqlite-shm', '*-shm', '*.lock', '.DS_Store')
class-attribute
instance-attribute
keep_daily = 7
class-attribute
instance-attribute
keep_weekly = 4
class-attribute
instance-attribute
keep_monthly = 6
class-attribute
instance-attribute
SelfModConfig
dataclass
The self-modification loop (BUILD-SPEC §14, Phase 10). Two fail-closed switches:
enabled is the master switch for the whole propose→approve→execute→validate→rollback loop;
unattended_enabled separately gates the ONLY path that acts without human approval (the §14
'safe levers'). Both OFF by default — a fresh clone can't self-modify, and never unattended,
until the owner deliberately turns each on in config/local.toml.
enabled = False
class-attribute
instance-attribute
unattended_enabled = False
class-attribute
instance-attribute
ledger_db = Path('data/selfmod_ledger.sqlite')
class-attribute
instance-attribute
SandboxConfig
dataclass
runtime
instance-attribute
image
instance-attribute
timeout_s
instance-attribute
memory
instance-attribute
cpus
instance-attribute
pids_limit
instance-attribute
max_concurrency
instance-attribute
warm_pool_size
instance-attribute
wasm_module = ''
class-attribute
instance-attribute
ModelConfig
dataclass
name
instance-attribute
tier
instance-attribute
pinned
instance-attribute
resident_gb
instance-attribute
num_ctx
instance-attribute
evicts_pinned = False
class-attribute
instance-attribute
Config
dataclass
ollama
instance-attribute
resources
instance-attribute
paths
instance-attribute
vault
instance-attribute
embedding
instance-attribute
dreaming
instance-attribute
dream_rnd
instance-attribute
sandbox
instance-attribute
interface
instance-attribute
airlock
instance-attribute
models
instance-attribute
ambassador = field(default_factory=AmbassadorConfig)
class-attribute
instance-attribute
monitor = field(default_factory=MonitorConfig)
class-attribute
instance-attribute
attestation = field(default_factory=AttestationConfig)
class-attribute
instance-attribute
secrets = field(default_factory=SecretsConfig)
class-attribute
instance-attribute
backup = field(default_factory=BackupConfig)
class-attribute
instance-attribute
selfmod = field(default_factory=SelfModConfig)
class-attribute
instance-attribute
effectors = field(default_factory=EffectorsConfig)
class-attribute
instance-attribute
pinned_model
property
model_for_tier(tier)
load_config(path=None)
get_config()
cached
refresh_config()
Drop the cached Config and reload from disk. Called after the self-mod loop writes a knob
to levers.toml (ops/apply.py) so the change actually takes effect for subsequent
get_config() callers in a long-running process, rather than waiting on a restart.
get_secret(name, token=None)
Fetch a secret. With no token: environment (Keychain-backed in the owner's setup) — the owner-operated / bootstrap path, unchanged from Phase 0.
With a token: a Vault ephemeral token minted for the calling agent's role
(Supervisor.mint_token, vault-runtime-auth.md §2). The agent receives the token in its
context, passes it here, and never constructs or stores it; Vault enforces the role's
policy and raises VaultPermissionDenied if the path is out of scope — the agent learns
nothing beyond "denied". The import lazily inside this branch only: config.loader is
imported throughout core/, and hvac must never become a transitive hard dependency of
that import (mirrors the lazy boto3/watchdog pattern elsewhere in this repo).
Secrets are NEVER stored in config files or committed, and never passed to a model (Invariant 10).
config.secrets_backend
Vault as a per-interaction runtime authorization layer (design-notes/vault-runtime-auth.md).
The object-capability model already scopes store handles at the code level (the dreamer
gets a MirrorView, never a raw vector store). This module closes the matching gap at the
credential level: an agent never holds a real secret, only an ephemeral token minted by the
supervisor and scoped to a named policy (role). A token that doesn't cover a path is denied —
the agent learns nothing beyond "denied" (VaultPermissionDenied).
hvac (the Vault HTTP client) is real-Vault-only and lazily imported inside VaultClient, so
importing this module — or config.loader, which imports it lazily too — never requires hvac
to be installed. The import-firewall (ops/import_lint.py) additionally blocks hvac from
ever appearing under core/: agents receive tokens in context (Phase 5), they never call
Vault directly. This module lives in config/, one level below get_secret(), exactly like
the design note's import-discipline section specifies.
Phase scope (Steps 4–5 of the security & attestation track, NOT a numbered phase): the primitives
below (FakeVault, VaultClient, build_secrets_backend, and MintedToken) and the
scope-enforcement tests that exercise them. Step 5 added the accessor half of MintedToken — a
mint's non-secret audit handle, which an attestation records in vault_token_accessor to tie an
action to its authorization (the Vault↔attestation join; never the token — see MintedToken).
Threading minted tokens into the dreamer/curator/vault-sync call sites is explicitly deferred to
Phase 5 (agent factory + dispatcher) per the design note's own framing — this module makes that
wiring possible without itself performing it.
VaultPermissionDenied
Bases: Exception
Raised when a token is unknown, or known but its role's policy doesn't cover the path.
Deliberately uninformative beyond that — the caller (an agent) must not learn why it was
denied, only that it was; the Vault audit log (or FakeVault.denials in tests) is where the
detail belongs (vault-runtime-auth.md §6 — denials are an alignment signal, not noise).
MintedToken
dataclass
What a mint returns: the secret token AND its accessor — Vault hands back both in one
response (resp["auth"]["client_token"] / ["accessor"]). The two live in different
keyspaces and do different jobs (the Step-5 Vault↔attestation join, attestation-layer.md §2):
• token — the credential. The agent uses it (get_secret(name, token=...)) and
nothing else may. NEVER logged, attested, or shown to a model (Invariant 10).
• accessor — a non-secret audit handle. It can look up a token's metadata or revoke it,
but cannot authenticate or read any secret. THIS is what an attestation
records in vault_token_accessor, tying an action to its Vault authorization
without ever exposing the credential.
The supervisor holds the whole MintedToken: it passes .token to the agent (in context,
Phase 5) and records .accessor in the attestation it emits for that action.
token
instance-attribute
accessor
instance-attribute
SecretsBackend
Bases: Protocol
What both FakeVault (tests) and VaultClient (real Vault) implement — the supervisor
and get_secret(..., token=...) depend on this shape, never on which one is wired.
mint_token(role, ttl)
read_secret(name, token)
FakeVault
dataclass
An in-memory dev/test double — no real Vault, no network, no subprocess. policies
maps a role name to the exact set of secret names its tokens may read (the dev-mode
analogue of an HCL policy's path stanzas, see ops/vault/policies/); secrets is the
backing key-value store. Every mint and every read/deny is recorded for assertions.
policies
instance-attribute
secrets = field(default_factory=dict)
class-attribute
instance-attribute
minted = field(default_factory=list)
class-attribute
instance-attribute
denials = field(default_factory=list)
class-attribute
instance-attribute
mint_token(role, ttl)
read_secret(name, token)
role_for_accessor(accessor)
The dev-mode analogue of Vault's lookup-accessor: resolve an accessor to the role it
was minted for, WITHOUT the token. This is what makes the Step-5 join verifiable — an
attestation's vault_token_accessor can be confirmed to match its claimed agent_role.
Returns None for an unknown accessor (or for a token passed here — wrong keyspace).
VaultClient
Real Vault, via hvac. Construction is side-effect-free — no connection is opened until
mint_token/read_secret is actually called — mirroring OllamaClient/lancedb.connect
elsewhere: safe to build in a wiring test without a live Vault dev-server running.
supervisor_token is the supervisor's own bootstrap credential (the bottom turtle for this
layer — placed in Keychain/env via get_secret("vault-supervisor-token"), same pattern as
the attestation signing keys). It is used only to mint child tokens; reads always go through
a freshly-scoped client built from the caller's token, never the supervisor's.
hvac is imported per-method, not in __init__: edge/bridge/bridge.py holds the same
line for boto3 ("imported LAZILY... so tests with a fake client never require boto3
installed") — this is that pattern applied here, so a wiring test can construct and inspect
a VaultClient (addr, kv_mount) with no Vault dev-server and no hvac installed; only an
actual mint_token/read_secret call needs the real package.
addr = addr
instance-attribute
kv_mount = kv_mount
instance-attribute
mint_token(role, ttl)
read_secret(name, token)
build_secrets_backend(config=None)
Wire a real VaultClient from [secrets] — None when disabled, the normal state
until the owner stands up a Vault dev-server (Step 6 runbook). Unlike attestation's
fail-closed signing gate, a missing supervisor token here is not a silent-fallback risk
(there is no insecure fallback path to slip into) — it simply surfaces as an hvac auth
error on the first real mint_token call, not at construction.