A3S Docs
A3S Code

Memory

Pluggable long-term memory for agents — store, search, and recall knowledge across sessions

Memory

A3S Code uses a two-layer memory architecture. The storage layer (a3s-memory) owns the MemoryStore trait and its default implementations. The agent layer (a3s-code) owns the three-tier session memory (AgentMemory) and context injection (MemoryContextProvider).

a3s-memory                          a3s-code
──────────────────────────────      ──────────────────────────────
MemoryStore (trait)                 AgentMemory
InMemoryStore                         ├── working    (Vec, max 10)
FileMemoryStore                       ├── short_term (VecDeque, max 100)
MemoryItem                            └── long_term  (→ MemoryStore)
MemoryType
RelevanceConfig                     MemoryConfig
                                    MemoryContextProvider

This separation means you can swap the storage backend without touching any agent code.

Quick Start

use a3s_code_core::{Agent, SessionOptions};

let agent = Agent::new("agent.hcl").await?;

// File-backed long-term memory (persists across restarts)
let session = agent.session(".", Some(
    SessionOptions::new()
        .with_file_memory("./memory")
))?;

let result = session.send("Remember: this project deploys to AWS us-east-1").await?;
const agent = await Agent.create('agent.hcl');
const session = agent.session('.', {
  fileMemory: './memory',
});

const result = await session.send('Remember: this project deploys to AWS us-east-1');
agent = Agent("agent.hcl")
session = agent.session(".", SessionOptions(
    file_memory="./memory",
))

result = session.send("Remember: this project deploys to AWS us-east-1")

Memory Types

Prop

Type

Failures are stored as Episodic with importance 0.9 — higher than successes so the agent avoids repeating them.

Three-Tier Session Memory

Working memory   — active context, auto-trimmed by relevance when over capacity (max 10)
Short-term       — current session, FIFO trim when over capacity (max 100)
Long-term        — persisted via MemoryStore, survives session restarts

remember() writes to both long-term and short-term simultaneously.

let memory = session.memory().unwrap();

// Store a fact
memory.remember(
    MemoryItem::new("Project uses PostgreSQL 15")
        .with_importance(0.8)
        .with_tag("database")
        .with_type(MemoryType::Semantic)
).await?;

// Convenience methods
memory.remember_success("Deployed via `just release`").await?;
memory.remember_failure("Direct `cargo publish` fails without fmt check").await?;

MemoryItem

Every memory is a MemoryItem. The builder API makes construction ergonomic:

use a3s_memory::{MemoryItem, MemoryType};

let item = MemoryItem::new("Prefer write_all over write for file I/O")
    .with_importance(0.8)          // 0.0–1.0, clamped
    .with_tag("rust")
    .with_tag("io")
    .with_type(MemoryType::Semantic)
    .with_metadata("source", "code-review");

Prop

Type

Relevance Scoring

When the agent needs context, memories are ranked by a score that combines importance and recency:

score = importance × importance_weight + exp(−age_days / decay_days) × recency_weight

Default config: importance_weight = 0.7, recency_weight = 0.3, decay_days = 30.

Configure via HCL:

memory {
  relevance {
    decay_days        = 30.0
    importance_weight = 0.7
    recency_weight    = 0.3
  }
  max_short_term = 100
  max_working    = 10
}

Or in code:

use a3s_memory::RelevanceConfig;
use a3s_code_core::memory::MemoryConfig;

SessionOptions::new()
    .with_memory_config(MemoryConfig {
        relevance: RelevanceConfig {
            decay_days: 7.0,        // faster decay for short-lived sessions
            importance_weight: 0.9,
            recency_weight: 0.1,
        },
        max_short_term: 100,
        max_working: 10,
    })

Storage Backends

FileMemoryStore

The default persistent backend. One JSON file per item, plus a compact index for fast search:

memory/
  index.json          ← lightweight index (id, tags, importance, timestamp)
  items/
    {uuid}.json       ← full item content, written atomically

Key properties:

  • Atomic writes via .tmp → rename — no corruption on crash
  • Index loaded into memory on init for fast search() and search_by_tags()
  • Path traversal prevention on memory IDs
  • rebuild_index() recovers from index corruption by scanning item files

InMemoryStore

Ephemeral, zero-config. Useful for testing and short-lived sessions:

use a3s_memory::InMemoryStore;

SessionOptions::new()
    .with_memory(Arc::new(InMemoryStore::new()))

Custom Backend

Implement MemoryStore to use any storage system — SQLite, Redis, a vector DB:

use a3s_memory::{MemoryItem, MemoryStore};

struct MyVectorStore { /* ... */ }

#[async_trait::async_trait]
impl MemoryStore for MyVectorStore {
    async fn store(&self, item: MemoryItem) -> anyhow::Result<()> {
        // embed item.content and upsert into vector DB
        todo!()
    }

    async fn search(&self, query: &str, limit: usize) -> anyhow::Result<Vec<MemoryItem>> {
        // embed query, ANN search, return top-k
        todo!()
    }

    async fn retrieve(&self, id: &str) -> anyhow::Result<Option<MemoryItem>> { todo!() }
    async fn search_by_tags(&self, tags: &[String], limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
    async fn get_recent(&self, limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
    async fn get_important(&self, threshold: f32, limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
    async fn delete(&self, id: &str) -> anyhow::Result<()> { todo!() }
    async fn clear(&self) -> anyhow::Result<()> { todo!() }
    async fn count(&self) -> anyhow::Result<usize> { todo!() }
}

SessionOptions::new().with_memory(Arc::new(MyVectorStore::new()))

FileMemoryStore uses substring matching for search(). A vector store replaces this with semantic similarity — no other changes needed.

Context Injection

MemoryContextProvider is registered automatically when memory is active. On each turn:

  1. Retrieves up to 5 relevant memories by substring match against the current prompt
  2. Injects them into the system prompt as structured context blocks
  3. After turn completion, stores the interaction as a Procedural memory
System Prompt
├── Base instructions
├── [memory] User prefers TypeScript           ← MemoryContextProvider
├── [memory] Deploy via `just release`         ← MemoryContextProvider
├── [resource] Related code snippets           ← FileSystemContextProvider
└── Tool definitions

Events

Prop

Type

API Reference

SessionOptions

Prop

Type

MemoryStore trait

Prop

Type

a3s-memory is a standalone crate. Add it directly if you need the storage layer without the full agent framework: cargo add a3s-memory

On this page