#transcript #persistence #state #memory

fmemory

Memory library for the fiddlesticks agent harness framework

5 releases (2 stable)

Uses new Rust 2024

3.0.0 Mar 3, 2026
1.0.0 Feb 9, 2026
0.9.91 Feb 9, 2026
0.9.9 Feb 9, 2026
0.1.0 Feb 7, 2026

#2474 in Database interfaces


Used in 3 crates (2 directly)

MIT license

355KB
8K SLoC

Context Layer API

fmemory provides durable state and transcript persistence for Fiddlesticks.

It is the persistence layer used by fharness for initializer/coding-run artifacts and by fchat (through an adapter) for conversation history.

Responsibilities

  • Persist session bootstrap artifacts (manifest, feature list, progress, run checkpoints)
  • Persist transcript messages
  • Expose a MemoryBackend contract for harness logic
  • Adapt memory transcript storage to fchat::ConversationStore

fmemory does not:

  • Execute model calls (fprovider)
  • Orchestrate turns (fchat)
  • Execute tools (ftooling)
  • Decide multi-run harness strategy (fharness)

Add dependency

[dependencies]
fmemory = { path = "../fmemory" }

Core types

  • MemoryBackend: async persistence trait
  • SqliteMemoryBackend: default durable backend implementation
  • PostgresMemoryBackend: durable backend using PostgreSQL
  • FilesystemMemoryBackend: JSON-file durable backend implementation
  • InMemoryMemoryBackend: ephemeral test-oriented backend implementation
  • MemoryBackendConfig: backend selection configuration
  • MemoryConversationStore: adapter implementing fchat::ConversationStore
  • SessionManifest: harness session metadata (+ schema/harness versions)
  • FeatureRecord: feature checklist item
  • ProgressEntry: per-run progress log entry
  • RunCheckpoint: run lifecycle status record
  • BootstrapState: manifest + feature/progress/checkpoint aggregate

Session initialization guards

MemoryBackend includes explicit initializer-safe methods:

  • is_initialized(session_id)
  • initialize_session_if_missing(...)

initialize_session_if_missing(...) is idempotent:

  • returns true when it creates state for the first time
  • returns false when state already exists (no overwrite)

Basic backend usage

use fcommon::SessionId;
use fmemory::prelude::*;

async fn seed_backend(backend: &dyn MemoryBackend) -> Result<(), MemoryError> {
    let session = SessionId::from("session-1");

    let created = backend
        .initialize_session_if_missing(
            &session,
            SessionManifest::new(session.clone(), "feature/init", "Initialize harness"),
            vec![FeatureRecord {
                id: "feature-1".to_string(),
                category: "functional".to_string(),
                description: "Initializer artifacts exist".to_string(),
                steps: vec!["write init state".to_string()],
                passes: false,
            }],
            Some(ProgressEntry::new("run-1", "Initializer scaffold created")),
            Some(RunCheckpoint::started("run-1")),
        )
        .await?;

    let _ = created;
    Ok(())
}

Backend selection

fmemory supports configurable backend construction:

use fmemory::{MemoryBackendConfig, create_default_memory_backend, create_memory_backend};

let sqlite_default = create_default_memory_backend()?;
let in_memory = create_memory_backend(MemoryBackendConfig::InMemory)?;
let sqlite_custom = create_memory_backend(MemoryBackendConfig::Sqlite {
    path: "./state/fmemory.sqlite3".into(),
})?;
let postgres = create_memory_backend(MemoryBackendConfig::Postgres {
    host: "127.0.0.1".into(),
    port: 5432,
    database: "fmemory".into(),
    username: "postgres".into(),
    password: "postgres".into(),
})?;
let filesystem = create_memory_backend(MemoryBackendConfig::Filesystem {
    root: "./state/fmemory".into(),
})?;

let _ = (sqlite_default, in_memory, sqlite_custom, postgres, filesystem);
# Ok::<(), fmemory::MemoryError>(())

Default backend path is ~/.fiddlesticks/fmemory.sqlite3 (or %USERPROFILE%/.fiddlesticks/fmemory.sqlite3 on Windows). Override it with FMEMORY_SQLITE_PATH.

fchat integration adapter

MemoryConversationStore lets fchat use fmemory without direct store duplication:

use std::sync::Arc;

use fmemory::prelude::*;

let backend: Arc<dyn MemoryBackend> = Arc::new(InMemoryMemoryBackend::new());
let store = MemoryConversationStore::new(backend);
let _ = store;

Versioning fields

SessionManifest includes:

  • schema_version (default: 1)
  • harness_version (default: "v0")

These support forward migration for future harness behaviors.

Error model

MemoryErrorKind variants:

  • Storage
  • NotFound
  • InvalidRequest
  • Other

Dependencies

~34MB
~639K SLoC