Configuration-as-code for the Exocortex — parse, validate, serialize, diff, and migrate
.cortex.tomlfiles
Every Exocortex deployment needs configuration — agent definitions, memory settings, network parameters, and more. cortex-toml is the library that makes .cortex.toml files first-class configuration artifacts: typed, validated, versionable, and diffable.
Think of it as the Cargo.toml parser for the Exocortex ecosystem. Just as serde + toml give Rust projects typed configuration, cortex-toml gives Exocortex deployments:
- Parsing: TOML string → typed
CortexConfigstruct (via serde) - Validation: Check types, ranges, required fields, and cross-field constraints
- Serialization:
CortexConfig→ pretty-printed TOML - Diffing: Compare two configs and generate a human-readable migration plan
- Round-tripping: Parse → serialize → parse produces identical results
Configuration-as-code is a DevOps best practice that brings software engineering rigor to infrastructure:
- Version control: Track configuration changes in git, review them in PRs, roll back when needed
- Validation: Catch misconfigurations (bad ports, impossible temperatures, missing fields) before deployment
- Diffing: See exactly what changed between two config versions — essential for change management
- Migration planning: Generate actionable migration steps when upgrading configurations
- Type safety: The
CortexConfigstruct is your schema — no silent field name typos or wrong types
Real-world applications:
- CI/CD pipelines: Validate
.cortex.tomlin CI before deploying - Config drift detection: Diff running config against committed config to detect unauthorized changes
- Multi-environment management: Compare dev/staging/prod configs to ensure consistency
- Agent onboarding: New agents get validated configuration from day one
┌──────────────────────────────────────────────────────────────┐
│ Cortex TOML Pipeline │
│ │
│ .cortex.toml │
│ ┌───────────────────────┐ │
│ │ name = "my-exocortex" │ │
│ │ version = "0.1.0" │ TomlParser │
│ │ │ ──▶ parse(input) ──▶ CortexConfig │
│ │ [agents.main] │ │
│ │ type = "chat" │ ┌────────────────────────┐ │
│ │ model = "gpt-4" │ │ CortexConfig │ │
│ │ │ │ ├─ name: String │ │
│ │ [memory] │ │ ├─ version: String │ │
│ │ backend = "sqlite" │ │ ├─ agents: HashMap │ │
│ │ max_entries = 5000 │ │ ├─ memory: MemoryCfg │ │
│ │ │ │ └─ network: NetworkCfg│ │
│ │ [network] │ └────────┬───────────────┘ │
│ │ bind = "0.0.0.0" │ │ │
│ │ port = 3000 │ ▼ │
│ │ tls = true │ ConfigValidator │
│ └───────────────────────┘ ┌────────────────────┐ │
│ │ name non-empty? │ │
│ │ temperature 0–2? │ │
│ │ port > 0? │ │
│ │ decay 0–1? │ │
│ └────────┬───────────┘ │
│ │ │
│ TomlSerializer ▼ │
│ serialize(config)──▶ TOML ConfigDiff │
│ diff(old, new)──▶ plan │
│ ┌────────────────────┐ │
│ │ - port: 8080 → 3000│ │
│ │ - agents.x: added │ │
│ └────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
use cortex_toml::{TomlParser,ConfigValidator,TomlSerializer,CortexConfig};// Parse a .cortex.toml filelet toml = r#"name = "my-exocortex"version = "0.1.0"[agents.main]type = "chat"model = "gpt-4"temperature = 0.7[memory]backend = "sqlite"max_entries = 5000decay_factor = 0.9[network]bind = "0.0.0.0"port = 3000tls = true"#;let config = TomlParser::parse(toml).expect("Valid TOML");println!("Project: {} v{}", config.name, config.version);println!("Agents: {:?}", config.agents.keys().collect::<Vec<_>>());// Validate the configurationlet errors = ConfigValidator::validate(&config);if errors.is_empty(){println!("✓ Configuration is valid");}else{for err in&errors {println!("✗ {}: {}", err.field, err.message);}}// Serialize back to TOMLlet output = TomlSerializer::serialize(&config).unwrap();println!("{}", output);// Round-trip: parse → serialize → parse should be identicallet reparsed = TomlParser::parse(&output).unwrap();assert_eq!(config, reparsed);use cortex_toml::{ConfigDiff,CortexConfig};let old_config = TomlParser::parse(r#"name = "my-exocortex"version = "0.1.0""#).unwrap();let new_config = TomlParser::parse(r#"name = "my-exocortex"version = "0.2.0"[agents.helper]type = "tool"model = "gpt-3.5""#).unwrap();let diff = ConfigDiff::diff(&old_config,&new_config);if diff.is_empty(){println!("No changes");}else{println!("Migration plan:");println!("{}", diff.migration_plan());// Output:// - version: 0.1.0 → 0.2.0// - agents.helper: absent → added}use cortex_toml::{TomlParser,ConfigValidator};let bad_config = TomlParser::parse(r#"name = " "[agents.main]type = ""temperature = 5.0"#).unwrap();let errors = ConfigValidator::validate(&bad_config);assert!(!errors.is_empty());// errors[0]: name is required (whitespace only)// errors[1]: agents.main.type is required (empty)// errors[2]: agents.main.temperature must be 0.0-2.0, got 5.0| Method | Returns | Description |
|---|---|---|
TomlParser::parse(input) | Result<CortexConfig, String> | Parse TOML string to config |
| Method | Returns | Description |
|---|---|---|
TomlSerializer::serialize(config) | Result<String, String> | Serialize config to pretty TOML |
| Method | Returns | Description |
|---|---|---|
ConfigValidator::validate(config) | Vec<ValidationError> | All validation errors |
ConfigValidator::is_valid(config) | bool | Quick validity check |
| Method | Returns | Description |
|---|---|---|
ConfigDiff::diff(old, new) | ConfigDiff | Compute differences between configs |
diff.len() | usize | Number of changed fields |
diff.is_empty() | bool | No changes detected |
diff.migration_plan() | String | Human-readable change summary |
| Field | Type | Default | Description |
|---|---|---|---|
name | String | required | Project name |
version | String | "" | Semantic version |
agents | HashMap<String, AgentConfig> | empty | Agent definitions |
memory | MemoryConfig | see defaults | Memory subsystem |
network | NetworkConfig | see defaults | Network settings |
| Field | Type | Default | Description |
|---|---|---|---|
agent_type | String | required | Agent type (chat, tool, etc.) |
model | String | "" | Model identifier |
temperature | f64 | 0.7 | Sampling temperature (0.0–2.0) |
| Field | Type | Default | Description |
|---|---|---|---|
backend | String | "file" | Storage backend |
max_entries | u64 | 10000 | Maximum memory entries |
decay_factor | f64 | 0.95 | Memory decay rate (0.0–1.0) |
| Field | Type | Default | Description |
|---|---|---|---|
bind | String | "127.0.0.1" | Bind address |
port | u16 | 8080 | Port number |
tls | bool | false | Enable TLS |
Diffing two configurations is equivalent to computing the symmetric difference of two labeled graphs. Each config is a tree (TOML is a tree-structured format), and the diff identifies:
- Changed leaves: Scalar values that differ
- Added subtrees: New agents or sections present only in the new config
- Removed subtrees: Sections present only in the old config
The diff algorithm runs in O(n) time where n is the total number of fields in both configs.
Each validation rule is a constraint on a field:
name: non-empty ∧ trim(name) ≠ ""
temperature: 0.0 ≤ value ≤ 2.0
max_entries: value > 0
decay_factor: 0.0 ≤ value ≤ 1.0
port: 0 < value ≤ 65535
The validator applies all constraints independently and returns the full set of violations (not just the first one), enabling batch error reporting.
The decay_factor in memory configuration controls exponential decay:
retention(n) = decay_factorⁿ
half_life = −ln(2) / ln(decay_factor)
| decay_factor | Half-life (writes) |
|---|---|
| 0.99 | 69 |
| 0.95 | 13.5 |
| 0.90 | 6.6 |
| 0.85 | 4.3 |
cargo add cortex-tomlOr add to your Cargo.toml:
[dependencies]
cortex-toml = "0.1.0"memory-plimpsest— Layered memory with ghost tracesconstellation-map— Fleet visualization as star chartsknowledge-compass— Provenance navigation for knowledge graphsemotional-colorist— Valence-based color mapping for agent states
MIT © SuperInstance
Part of the Exocortex project — persistent cognitive substrate for multi-agent systems.