Storage configuration¶
storage is required. It tells Colossus where the canonical event journal lives and
how to protect it. Storage configuration is separate from projections, semantic
indexes, and exports: those are derived data that Colossus can rebuild from the
journal.
Use this mental model when configuring storage:
| Component | Purpose |
|---|---|
| Journal adapter | Retains the canonical append-only event history in process memory, redb, or PostgreSQL |
| Protection mode | Stores payloads as plaintext canonical JSON or authenticated ciphertext |
| Journal key | Encrypts event payloads in protected mode |
| Signing key | Signs checkpoints in protected mode |
| Secure anchor | Keeps the last trusted journal sequence and hash outside the journal so rollback or truncation can be detected |
storage.location |
Selects the confinement base for a relative storage path |
storage.path |
Selects the local redb file or the local instance identity for ephemeral and PostgreSQL |
redb and PostgreSQL support keys.kind: none and the fully protected platform and
environment modes. Ephemeral storage requires none: a persistent secure anchor
cannot safely describe a fresh process-local journal. PostgreSQL TLS protects the
database connection; it does not change payload protection at rest. Normal worker IPC
uses an independent owner-only <storage.path>.worker-auth secret and never derives
authentication from storage keys.
For deployment topology, worker ownership, projections, and the public application API, see Storage and worker.
Choose a starting point¶
| Scenario | Adapter | Key provider | Guidance |
|---|---|---|---|
| One-shot job with no restart or recovery requirement | ephemeral |
none |
Keeps canonical state, projections, the default memory index, and automatic MCP OAuth state in process memory |
| Disposable container that must survive a process restart | redb |
none |
Place the file on an emptyDir or other Pod-lifetime volume |
| Desktop managed deployment | redb |
platform |
The OS credential store protects keys and the anchor |
| Headless single-host service | redb |
environment |
Inject both keys and preserve the file-backed anchor |
| One long-running worker | redb |
Either | Let the worker own the single redb writer lease |
| Shared or multi-process deployment | postgres |
Usually environment |
Put the journal in PostgreSQL and inject identical keys into every runtime |
| Same-host PostgreSQL processes under one OS identity | postgres |
platform can work |
Every process must resolve the same service and key accounts |
Start with redb unless the complete run is deliberately process-local or multiple
processes need direct access to the canonical journal. Changing adapter is not a
migration: Colossus does not import, merge, copy, or delete another adapter's journal.
Process-local ephemeral storage¶
Use ephemeral for a one-shot command or Kubernetes Job whose result is delivered to
an external system and whose Colossus history is intentionally discarded at process
exit:
This runs the production redb journal and projection implementation over redb's memory
backend. It creates no canonical database or writer-lock file. The default Tantivy
memory index and the MCP oauthCredentialStore: auto selection are also process-local.
storage.path remains a logical identity for adjacent explicitly persistent features;
ordinary one-shot commands do not use those files. Because the journal never leaves the
current process, colossus worker is refused under this adapter: serving, --status,
--shutdown, and public API hosting all require a worker another process can reach.
colossus worker --once, which recovers and drains inside the running process, remains
available.
Every invocation starts empty. Sessions, workflow progress, child jobs, approvals,
idempotency claims, effect evidence, audit history, projections, memories, and OAuth
tokens disappear when the process exits or crashes. A later Kubernetes retry is a new
run and cannot determine whether an earlier external effect completed. Use file-backed
redb or PostgreSQL whenever retry, resume, audit retention, or unknown-outcome recovery
matters. state doctor reports persistence: process and emits an explicit security
posture warning in this mode.
Explicit external audit exporters, mcp.oauthCredentialStore: platform, Chroma
projection metadata, and other separately configured adapters keep their documented
persistence behavior; ephemeral governs the canonical journal/projection store and
the automatic local defaults.
Keyless plaintext default¶
The sparse configuration created by colossus config init contains only the storage
placement that differs by scope:
Omitted adapter, startupVerification, and keys resolve to redb, incremental,
and none. Use config show to inspect that complete resolved shape, or pass
--storage-keys none|platform|environment to pin a protection choice in the authored
file. Payload
descriptors use plaintext-json-v1, key_id: none, an empty nonce, and hex-encoded
canonical JSON. Colossus still checks each payload hash and JSON shape when it is read,
maintains the record-hash chain, stream indexes, outbox, and projections, and performs a
complete replay for audit verify or startupVerification: full.
Incremental keyless startup performs bounded local head, hash, index, outbox, and projection-bound checks without replaying historical payloads. Signed checkpoints and secure anchors are disabled. This mode protects integrity against ordinary corruption, not confidentiality or rollback by an attacker who can consistently rewrite all local state.
Local redb with platform keys¶
This is the recommended protected local configuration:
storage:
location: home_workspace
path: state.redb
adapter: redb
startupVerification: incremental
keys:
kind: platform
service: dev.colossus.runtime
journal_key_id: journal-production
signing_key_id: checkpoint-production
When an entry is absent, Colossus generates a random 32-byte journal or signing key and stores it through the operating system credential service. The secure anchor is stored there too. Keyring failure is fatal; Colossus never silently writes these keys to disk.
Choose stable, deployment-specific service and key IDs. Reusing generic identifiers
across unrelated deployments makes their credential namespaces collide.
Top-level storage fields¶
storage.location¶
location selects the base for a relative storage.path:
| Value | Behavior |
|---|---|
workspace |
Resolve from the canonical workspace; this is the compatibility default when omitted |
home_workspace |
Resolve beneath the current workspace's cli home partition |
The global config init writes home_workspace; config init --local writes
workspace. Under home_workspace, path must be relative and confined. Absolute
paths, parent components, and any result outside the CLI partition are rejected. This
partition is distinct from Desktop Managed Local state. See
Colossus home and workspace resolution.
storage.path¶
With location: workspace, path may be workspace-relative or absolute. File-backed
adapters create the parent directory when needed. With location: home_workspace, it
must be a confined relative path and resolves from the selected workspace's CLI home
partition. Ephemeral storage validates this identity without creating its leaf or
parent directories.
Its exact meaning depends on the adapter:
| Adapter | Meaning of storage.path |
|---|---|
redb |
The canonical redb database file and the basis for its writer lease |
ephemeral |
A logical local instance identity; it is not a database path |
postgres |
A local instance identity used to derive worker IPC and adjacent local state paths; it is not the PostgreSQL journal location |
With ephemeral storage or PostgreSQL, changing storage.path changes local instance
identity without moving canonical data. Keep it stable for a deployed instance.
Do not treat copying a redb file, changing this path, or switching adapters as a storage migration. Provision the destination explicitly, verify its keys and secure anchor, and follow the operational recovery process.
storage.adapter¶
| Value | PostgreSQL block | Concurrency model |
|---|---|---|
Omitted or redb |
Must be absent | One local writer lease; other clients should use the worker |
ephemeral |
Must be absent | One fresh process-local store; no redb writer lease |
postgres |
Required | Canonical journal is shared through PostgreSQL |
The canonical spelling is postgres. An unknown adapter, a postgres block under
redb or ephemeral, or adapter: postgres without that block fails configuration
validation. Ephemeral storage additionally rejects platform and environment keys.
storage.startupVerification¶
| Value | Startup behavior |
|---|---|
Omitted or incremental |
Protected mode verifies the signed checkpoint tail; keyless mode performs bounded local integrity checks |
full |
Replay, decode, and verify every journal event before every writable start |
Incremental verification is the default. A legacy, absent, quarantined, or incompatible secure anchor causes one complete bootstrap audit and writes a version-two attestation. That first start can take tens of seconds for a large existing journal. Later clean starts inspect one checkpoint boundary plus any uncheckpointed tail instead of decrypting all history.
Set startupVerification: full when policy requires complete replay before every
writable start. The audit verify command always performs a complete audit regardless
of this setting. state doctor reports the configured mode, actual verification path,
verified sequence range, event count, and secure-anchor version.
Key providers and fixed protection mode¶
kind: none is the default. kind: platform and kind: environment both enable the
complete protected tier: authenticated payload encryption, signed checkpoints, and
secure anchors. Encryption and signing cannot be enabled independently.
Each redb file and PostgreSQL schema stores a durable protection marker. An ephemeral store initializes a plaintext marker for its process lifetime. A nonempty persistent store created before this marker existed is classified as encrypted. A configured mismatch fails startup before event writes; Colossus never creates mixed payload algorithms and does not migrate protection in place. Use a fresh path or schema to harden or simplify a deployment.
The journal encryption key and checkpoint signing key are independent 32-byte secrets. Do not give them the same value. The identifiers in YAML are identities, not secret material and not rotation instructions.
Platform credential store¶
Use kind: platform when every process can access the intended OS Keychain, Windows
Credential Manager, or Secret Service entries:
keys:
kind: platform
service: dev.colossus.runtime
journal_key_id: journal-production
signing_key_id: checkpoint-production
| Field | Meaning |
|---|---|
service |
Namespace in the operating system credential store |
journal_key_id |
Stable identity of the active event-encryption key |
signing_key_id |
Stable identity of the checkpoint-signing key |
Colossus uses distinct journal, signing, and anchor accounts under the configured service. It can retrieve a historical journal key when that key's account still exists.
For a shared PostgreSQL deployment, do not let separate hosts independently create entries with the same IDs: each host would generate different bytes. Provision the same protected secret material everywhere or use environment keys supplied by a central secret manager.
Environment-backed keys¶
Use kind: environment for headless, air-gapped, container, or externally managed
secret injection:
storage:
location: workspace
path: .colossus/state.redb
adapter: redb
startupVerification: incremental
keys:
kind: environment
journal_variable: COLOSSUS_JOURNAL_KEY
journal_key_id: journal-production
signing_variable: COLOSSUS_SIGNING_KEY
anchor_path: .colossus/secure-anchor.json
| Field | Rule |
|---|---|
journal_variable |
Name of the environment variable containing the journal key |
journal_key_id |
Stable identity recorded with encrypted journal events |
signing_variable |
Name of the environment variable containing the signing key |
anchor_path |
With location: workspace, a workspace-relative or absolute integrity path; with home_workspace, a confined relative path resolved beneath the CLI partition |
Each variable must contain exactly 32 bytes encoded as hexadecimal or base64. YAML stores only the variable names. There is no plaintext, generated-file, or keyring fallback.
These variables are read by Colossus itself. They do not need to appear in
sandbox.environment unless an authorized child process also needs them—which storage
keys normally should not.
The environment provider exposes only the configured journal key ID. If existing events reference a different ID, Colossus cannot decrypt them through this provider. Changing an ID or replacing the bytes under an existing ID is not a safe key rotation.
Secure anchors¶
The secure anchor records the last trusted journal sequence and hash outside the
canonical journal. state doctor compares it with the journal to detect missing,
rolled-back, or altered journal state.
| Key provider | Anchor location |
|---|---|
none |
Disabled; checkpoint returns no checkpoint |
none with ephemeral |
Disabled; all journal state ends with the process |
platform |
Protected credential-store account derived from service and journal_key_id |
environment |
JSON file at anchor_path, updated with an atomic rename |
Treat the anchor as integrity-critical state. Keep the file-backed anchor separate from the redb database, preserve it through host replacement, and back it up consistently with the journal and key identities. Incremental startup replaces a legacy or absent anchor only after a successful complete bootstrap audit. A malformed or mismatched version-two anchor fails closed and quarantines incremental verification until a complete verification succeeds.
The anchor is not a substitute for the journal encryption or signing key, and a copy of the journal alone is not a complete verified recovery set.
PostgreSQL configuration¶
PostgreSQL is the shared-journal adapter. This complete storage block uses environment keys and the built-in WebPKI roots:
storage:
path: .colossus/instance.redb
adapter: postgres
startupVerification: incremental
postgres:
connectionVariable: COLOSSUS_DATABASE_URL
schema: colossus_production
tls:
kind: webpki_roots
statementTimeoutMs: 30000
keys:
kind: environment
journal_variable: COLOSSUS_JOURNAL_KEY
journal_key_id: journal-production
signing_variable: COLOSSUS_SIGNING_KEY
anchor_path: .colossus/secure-anchor.json
The value of COLOSSUS_DATABASE_URL may be a libpq-style URL or key/value connection
string. Put only the environment variable name in YAML. Colossus does not include the
resolved connection value in its safe configuration summaries or adapter diagnostics.
With this example PostgreSQL journal payloads are encrypted with
COLOSSUS_JOURNAL_KEY. A PostgreSQL configuration may instead use keys.kind: none;
every runtime opening one schema must select the same protection mode.
PostgreSQL fields¶
| Field | Constraint |
|---|---|
connectionVariable |
Nonempty POSIX-style environment name; its value contains the connection string |
schema |
Deployment-owned, 1–63 byte ASCII identifier beginning with a letter or underscore |
tls |
Optional; defaults to kind: webpki_roots |
statementTimeoutMs |
100..=300000; defaults to 30000 |
The schema may otherwise contain ASCII letters, digits, and underscores. Colossus creates it if needed and sets it as the connection search path. The configured timeout is applied to both PostgreSQL statements and lock acquisition.
The connection environment variable is consumed in-process and does not need a
sandbox.environment grant. Supply it to the Colossus service through the host,
container, or secret-manager configuration.
PostgreSQL TLS modes¶
kind |
Trust behavior | Intended use |
|---|---|---|
webpki_roots |
Built-in WebPKI roots plus network.caBundlePath |
Public CAs or a shared enterprise CA bundle |
custom_ca |
Trust only the adapter-specific PEM bundle | A PostgreSQL-specific private CA |
disabled |
No TLS; rejected unless every target is loopback or a Unix socket | Isolated local development and CI only |
An exclusive PostgreSQL CA uses this exact shape:
storage:
path: .colossus/instance.redb
adapter: postgres
startupVerification: incremental
postgres:
connectionVariable: COLOSSUS_DATABASE_URL
schema: colossus_production
tls:
kind: custom_ca
caPemPath: /etc/colossus/postgres-ca.pem
statementTimeoutMs: 30000
keys:
kind: environment
journal_variable: COLOSSUS_JOURNAL_KEY
journal_key_id: journal-production
signing_variable: COLOSSUS_SIGNING_KEY
anchor_path: .colossus/secure-anchor.json
custom_ca excludes public roots and network.caBundlePath; the PEM file must contain
at least one certificate. With webpki_roots, the shared network bundle augments public
roots. See Network trust configuration for precedence across
Colossus-owned clients.
Key and adapter combinations¶
The supported adapter/protection combinations are:
| Adapter | No keys | Platform keys | Environment keys |
|---|---|---|---|
| ephemeral | One-shot process-local jobs | Invalid | Invalid |
| redb | Simple jobs and protected local volumes | Protected interactive single-host use | Services with injected secrets |
| PostgreSQL | Simple shared jobs where database controls are sufficient | Same-host processes resolving the same entries | Multi-host deployments with a central secret manager |
For PostgreSQL on multiple hosts, each host also has its own local storage.path and,
with environment keys, its own anchor_path. Manage those local identities and anchors
as durable deployment state even though the journal is shared.
Common configuration mistakes¶
| Symptom | Check |
|---|---|
| An ephemeral retry cannot find its prior run | This is expected; every process starts with an empty journal |
| Ephemeral configuration rejects protected keys | Use keys.kind: none, or select redb/PostgreSQL when anchors and protected persistence are required |
| redb startup reports a writer lease conflict | Another process owns the same storage.path; use its worker or stop the duplicate writer |
| PostgreSQL configuration is rejected before connecting | postgres requires a postgres block, while redb and ephemeral forbid one |
| PostgreSQL is healthy but journal decryption fails | Every process must use the same journal key bytes and stable key ID |
| An old journal becomes unreadable after a config edit | Changing key IDs or secret bytes does not rotate or migrate encrypted events |
| Startup reports a payload-protection mismatch | The nonempty path or schema was initialized in another mode; select it or use fresh storage |
storage.path changes but PostgreSQL data does not move |
Under PostgreSQL the path is local instance identity, not the database location |
| A copied redb file does not behave like a migration | Adapter and path changes never import keys, anchors, or events |
| The connection string appears directly in YAML | connectionVariable accepts the environment variable name, not a literal credential |
| PostgreSQL rejects a schema | Use a 1–63 byte ASCII identifier beginning with a letter or underscore |
| A private database CA is still rejected | Use caPemPath under kind: custom_ca and confirm the PEM contains certificates |
network.caBundlePath has no effect on PostgreSQL |
custom_ca is exclusive; use webpki_roots to inherit the shared bundle |
Remote PostgreSQL rejects kind: disabled |
Disabled TLS is restricted to loopback and Unix-socket targets |
| Journal verification reports an anchor mismatch | Restore and investigate the trusted journal, keys, and anchor as one recovery set |
Validate the result¶
First confirm that YAML fields, adapter pairing, paths, and bounds parse without printing resolved secrets:
Then open the configured adapter and verify the journal, checkpoints, projections, and secure anchor:
For a worker-owned redb deployment, also confirm the worker endpoint:
config show does not prove that environment variables, platform credential entries,
CA files, or PostgreSQL are available. state doctor performs the storage-backed
verification. Run it before placing a new target into service and after an intentional
recovery or migration.
Return to the configuration overview.