Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,551 changes: 1,496 additions & 55 deletions Cargo.lock

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions HACKATHON.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Fluctlight Swarm Memory

Parallel coding agents are fast, but they do not share a durable account of what was tried, what failed, or which result was actually verified. They can receive the same context, repeat the same dead end, and turn a worker's confident claim into team knowledge without evidence.

Fluctlight Swarm Memory is a Codex plugin backed by FluctlightDB. It gives a parallel Codex run:

- shared verified truth and mandatory failure warnings;
- disjoint episodic memories so workers explore different strategies;
- worker and worktree identity binding;
- citations restricted to memories actually exposed to that worker;
- evidence-gated outcomes—workers report attempts, but only an admin/verifier can accept them;
- targeted learning: success or reproduced failure updates only the memories that were cited;
- WAL and v4 checkpoint recovery across coordinator restarts.

## One-command demo

Prerequisites: Rust/Cargo and Python 3.9+.

[Watch the 61-second captioned demo](docs/demo/fluctlight-swarm-memory-demo.mp4) or run the same verified flow yourself:

```bash
python3 scripts/demo_codex_swarm.py
```

The demo launches an authenticated local coordinator, assigns two non-overlapping memory bundles, proves that a worker cannot cite another worker's memory, proves that a worker cannot verify its own result, accepts trusted evidence, finishes the run, restarts the coordinator, and confirms the completed state survived.

Expected final line:

```text
PASS: durable, diverse, evidence-gated swarm memory survived restart
```

## How it connects to Codex

The plugin is in [`plugins/fluctlight-swarm`](plugins/fluctlight-swarm). It packages:

- an MCP server with five swarm lifecycle tools;
- `SubagentStart` and `SubagentStop` hooks;
- a Skill that requires the root agent to declare the full roster before spawning workers.

Codex calls `fluctlight_swarm_begin` once. Each `SubagentStart` hook claims one unique slot and injects only that slot's bounded memory bundle. Each `SubagentStop` hook records a pending attempt tied to its Git tree. Trusted repository tests provide the evidence; a worker cannot self-certify.

The current prototype intentionally keeps final evidence approval with the root/verifier. This is a safety boundary, not an autonomous-success claim.

## What Codex contributed

Codex was used as the engineering environment, not merely as a text generator. Parallel analysis agents audited FluctlightDB's Rust persistence model and the open-source Codex hook/plugin surfaces. Codex then designed the transaction model, wrote the Rust coordinator and tests, built the MCP plugin, found an MCP 2.0 compatibility issue during a live smoke test, added a regression test, and reran the complete verification suite.

## Verification

- complete `cargo test -p fluctlightdb` suite, including the 10,000-memory load smoke test;
- HTTP lifecycle and role-enforcement integration tests;
- WAL replay and v4 checkpoint round trips;
- Python client and MCP 2.0 tool-registration tests;
- Codex plugin and Skill validators;
- the end-to-end demo above, including restart recovery.

Design and source audit: [`docs/superpowers/specs/2026-08-15-codex-native-swarm-memory-design.md`](docs/superpowers/specs/2026-08-15-codex-native-swarm-memory-design.md) · [`docs/CODEX_SWARM_SOURCE_AUDIT.md`](docs/CODEX_SWARM_SOURCE_AUDIT.md)
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@

[![PyPI](https://img.shields.io/pypi/v/fluctlightdb)](https://pypi.org/project/fluctlightdb/) · [GitHub](https://github.com/voxmastery/FluctlightDB) · [Paper DOI](https://doi.org/10.5281/zenodo.20949890)

> **Codex Community Hackathon:** [Fluctlight Swarm Memory — problem, architecture, and one-command demo](HACKATHON.md)

### Fluctlight Swarm Memory — built with Codex

This hackathon prototype solves a failure mode in parallel coding agents: workers can receive duplicate context, repeat known failures, and promote unverified claims into shared knowledge. The Codex plugin gives every worker shared verified truth and warnings, but assigns different episodic strategies; it binds attempts to workers/worktrees and learns only from evidence accepted by a trusted verifier. State survives restarts through FluctlightDB WAL and v4 checkpoints.

Codex parallel agents were used to audit both codebases, design the transaction model, implement the Rust coordinator and MCP hooks, discover and fix an MCP 2.0 compatibility issue, and run the verification suite. Reproduce the shipped artifact with:

[![Watch the 61-second Fluctlight Swarm Memory demo](docs/demo/fluctlight-swarm-memory-preview.png)](docs/demo/fluctlight-swarm-memory-demo.mp4)

**[Watch the 61-second demo video](docs/demo/fluctlight-swarm-memory-demo.mp4)** · [Read the demo narration](docs/demo/demo-voiceover-script.md)

```bash
python3 scripts/demo_codex_swarm.py
```

## Install

```bash
Expand Down
41 changes: 41 additions & 0 deletions crates/fluctlightdb/src/brain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pub struct FluctlightBrain {
pub semantic: SemanticField,
#[serde(default)]
pub recent_separations: Vec<SeparationResult>,
#[serde(default)]
pub swarm: crate::swarm::SwarmState,
#[serde(skip)]
checkpoint_policy: CheckpointPolicy,
/// Runtime counter for autonomic Somnus durability seals (not semantic sleep).
Expand Down Expand Up @@ -164,6 +166,7 @@ impl FluctlightBrain {
governance: crate::governance::GovernanceState::default(),
semantic: SemanticField::default(),
recent_separations: Vec::new(),
swarm: crate::swarm::SwarmState::default(),
checkpoint_policy: CheckpointPolicy::default(),
ticks_since_systems_seal: 0,
wal_records_since_seal: 0,
Expand Down Expand Up @@ -308,6 +311,42 @@ impl FluctlightBrain {
Ok(())
}

pub fn apply_swarm_transaction(
&mut self,
transaction: crate::swarm::SwarmTransaction,
) -> Result<crate::swarm::SwarmApplyResult> {
if let Some(path) = self.store_path.as_deref() {
if !crate::storage::should_use_v4(path) {
return Err(Error::Store(
"swarm coordination requires v4 segmented storage".into(),
));
}
}
let mut next = self.swarm.clone();
let run = next.apply_transaction(transaction.clone())?;
if next == self.swarm {
return Ok(run);
}
if wal::wal_enabled() {
self.wal_append(WalEntry::SwarmTransaction { transaction })?;
}
self.swarm = next;
self.maybe_checkpoint()?;
Ok(run)
}

pub(crate) fn apply_swarm_transaction_internal(
&mut self,
transaction: crate::swarm::SwarmTransaction,
checkpoint: bool,
) -> Result<crate::swarm::SwarmApplyResult> {
let run = self.swarm.apply_transaction(transaction)?;
if checkpoint {
self.maybe_checkpoint()?;
}
Ok(run)
}

pub fn stage(&self) -> DevStage {
self.development.stage
}
Expand Down Expand Up @@ -1591,6 +1630,7 @@ impl FluctlightBrain {
governance: crate::governance::GovernanceState::default(),
semantic,
recent_separations,
swarm: crate::swarm::SwarmState::default(),
checkpoint_policy: CheckpointPolicy::default(),
ticks_since_systems_seal: 0,
wal_records_since_seal: 0,
Expand Down Expand Up @@ -1643,6 +1683,7 @@ impl Clone for FluctlightBrain {
governance: self.governance.clone(),
semantic: self.semantic.clone(),
recent_separations: self.recent_separations.clone(),
swarm: self.swarm.clone(),
checkpoint_policy: self.checkpoint_policy.clone(),
ticks_since_systems_seal: self.ticks_since_systems_seal,
wal_records_since_seal: self.wal_records_since_seal,
Expand Down
2 changes: 2 additions & 0 deletions crates/fluctlightdb/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub enum Error {
DistributedMutationDisabled { operation: &'static str },
#[error("serialization error: {0}")]
Serde(String),
#[error(transparent)]
Swarm(#[from] crate::swarm::SwarmError),
#[error("sqlite error: {0}")]
Sqlite(#[from] rusqlite::Error),
}
Expand Down
8 changes: 8 additions & 0 deletions crates/fluctlightdb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ pub mod stage_schedule;
pub mod storage;
pub mod store;
pub mod store_lock;
pub mod swarm;
pub mod tau;
pub mod tau_runtime;
pub mod tenant;
Expand Down Expand Up @@ -159,6 +160,13 @@ pub use stage_schedule::StageConsolidationReport;
pub use storage::{default_brain_path, default_tenant_brain_dir, StorageFormat};
pub use store::{verify_path, BrainVerifyReport};
pub use store_lock::{SharedStoreLock, StoreLock};
pub use swarm::{
allocate_roster, BeginSwarm, CitationReceipt, CiteMemories, ClaimSlot, EngramFeedback,
EvidenceReceipt, EvidenceResult, FinishSwarm, MemoryBundle, MemoryCandidate, MemoryExposure,
PendingAttempt, RecordEvidence, ReportAttempt, SwarmApplyResult, SwarmError, SwarmRun,
SwarmState, SwarmStatus, SwarmSummary, SwarmTransaction, TruthRevision, VerifiedOutcome,
WorkerSlot, WorkerStatus,
};
pub use tau::{TauHit, TauLane, TauShard};
pub use types::{
ActivationResult, Episode, ExperienceReport, Provenance, ProvenanceKind, RecallResult,
Expand Down
44 changes: 44 additions & 0 deletions crates/fluctlightdb/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ impl Default for BrainManifest {
"semantic".into(),
"muon".into(),
"tau".into(),
"swarm".into(),
],
}
}
Expand Down Expand Up @@ -197,6 +198,7 @@ fn write_checkpoint_dir(brain: &FluctlightBrain, dir: &Path) -> Result<()> {
// Serialize/Deserialize; they just were never written.
segment::write_segment(dir, "muon", &brain.muon)?;
segment::write_segment(dir, "tau", &brain.tau)?;
segment::write_segment(dir, "swarm", &brain.swarm)?;

let identity = brain.wal_identity();
let manifest = BrainManifest {
Expand Down Expand Up @@ -290,6 +292,7 @@ fn load_checkpoint_dir(dir: &Path) -> Result<FluctlightBrain> {
// older brain directories readable and matches the previous (always-empty) behaviour.
brain.muon = segment::read_segment(dir, "muon").unwrap_or_default();
brain.tau = segment::read_segment(dir, "tau").unwrap_or_default();
brain.swarm = segment::read_segment(dir, "swarm").unwrap_or_default();
brain.agent = segment::read_segment(dir, "agent").unwrap_or_default();
brain.governance = segment::read_segment(dir, "governance").unwrap_or_default();
match (manifest.tenant_uuid, manifest.durability) {
Expand Down Expand Up @@ -355,9 +358,34 @@ pub fn migrate_v3_file_to_v4(v3_path: &Path, v4_dir: &Path) -> Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use crate::swarm::{BeginSwarm, SwarmTransaction, WorkerSlot, WorkerStatus};
use crate::types::Episode;
use tempfile::tempdir;

fn add_swarm(brain: &mut FluctlightBrain) -> uuid::Uuid {
let swarm_id = uuid::Uuid::new_v4();
brain
.apply_swarm_transaction(SwarmTransaction::Begin(BeginSwarm {
transaction_id: uuid::Uuid::new_v4(),
swarm_id,
project_id: "fluctlight".into(),
objective_digest: "sha256:objective".into(),
repository_identity: "repo".into(),
base_commit: "abc123".into(),
policy_version: "v1".into(),
roster: vec![WorkerSlot {
slot_id: "slot-a".into(),
role: "worker".into(),
agent_id: None,
worktree: None,
status: WorkerStatus::Declared,
}],
allocations: std::collections::HashMap::new(),
}))
.unwrap();
swarm_id
}

#[test]
fn v4_roundtrip() {
let dir = tempdir().unwrap();
Expand Down Expand Up @@ -490,6 +518,20 @@ mod tests {
);
}

#[test]
fn v4_roundtrip_preserves_swarm_state() {
let dir = tempdir().unwrap();
let v4 = dir.path().join("brain_v4");
let mut brain = FluctlightBrain::new();
let swarm_id = add_swarm(&mut brain);

save_v4_dir(&brain, &v4).unwrap();
let loaded = load_v4_dir(&v4).unwrap();

assert!(loaded.swarm.runs.contains_key(&swarm_id));
assert_eq!(loaded.swarm.applied_transactions.len(), 1);
}

/// A brain directory written before lane persistence has no muon/tau segment. Loading it
/// must still succeed (falling back to empty lanes) rather than erroring out.
#[test]
Expand All @@ -502,9 +544,11 @@ mod tests {
let checkpoint = resolve_checkpoint_dir(&v4).unwrap();
let _ = fs::remove_file(checkpoint.join("muon.seg"));
let _ = fs::remove_file(checkpoint.join("tau.seg"));
let _ = fs::remove_file(checkpoint.join("swarm.seg"));

let loaded = load_v4_dir(&v4).expect("older brain dirs must still load");
assert_eq!(loaded.muon_len(), 0);
assert!(loaded.swarm.runs.is_empty());
}

#[cfg(unix)]
Expand Down
15 changes: 11 additions & 4 deletions crates/fluctlightdb/src/replicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ pub fn sync_once(primary: &Path, replica_dir: &Path) -> Result<ReplicaStatus> {
let mut snapshot_copied = false;
let mut wal_bytes_copied = 0u64;

let manifest = primary.join("manifest.json");
let manifest_mtime = file_mtime_secs(&manifest).unwrap_or(0);
let publication = if primary.join("CURRENT").exists() {
primary.join("CURRENT")
} else {
primary.join("manifest.json")
};
let manifest_mtime = file_mtime_secs(&publication).unwrap_or(0);
let brain_dst = replica_dir.join("brain");

if storage::is_v4_path(primary) {
Expand Down Expand Up @@ -109,8 +113,11 @@ pub fn sync_once(primary: &Path, replica_dir: &Path) -> Result<ReplicaStatus> {
}

pub fn open_replica_brain(replica_dir: &Path) -> Result<FluctlightBrain> {
let brain_path = if replica_dir.join("brain").join("manifest.json").exists() {
replica_dir.join("brain")
let v4_brain = replica_dir.join("brain");
let brain_path = if v4_brain.join("CURRENT").exists()
|| v4_brain.join("manifest.json").exists()
{
v4_brain
} else {
replica_dir.join("brain.flct")
};
Expand Down
Loading
Loading