AgentsOpen SourceFreeActiveMachine-verified· intermediate · ~15 min setup

Letta + Fable 5: Persistent Memory for Multi-Week Projects

Give Fable 5 a memory that survives restarts via Letta's structured memory blocks, so a project runs for weeks, not one session.

by Shilpa Mitra· verified today· v1.0.0

Run this workflow

CI-verified, 5/5 fixtures passing.

Build this with your agent

One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.

Intended Use

A multi-week build where the agent should keep notes across sessions: Letta gives Fable structured memory blocks it reads and rewrites over time. CI verifies the deterministic spine: the agent config dict is valid, model equals anthropic/claude-fable-5, and the human and persona memory blocks are present and non-empty. No key. The agent's recall and self-editing are the fenced model step.

Not for

  • Skipping a running Letta server (self-hosted or Letta Cloud, hence the LETTA_API_KEY)
  • Assuming Anthropic provider support without checking your Letta version (model strings follow Letta's provider/model convention)
  • Letting memory blocks drift; prune them over time

The Stack

Tested Against

letta-client@latestclaude-fable-5

Side effects & data flow

Network
none, local only
Writes
./letta-agent.json, ./checkletta.mjs
Credentials
none required

Prerequisites

  • Python (pip install letta-client)
  • A running Letta server (self-hosted or Letta Cloud) and LETTA_API_KEY
  • An Anthropic API key for anthropic/claude-fable-5

Steps

  1. 1

    Create a Letta agent on Fable with memory blocks

    pip install letta-client. Then client.agents.create(model='anthropic/claude-fable-5', memory_blocks=[{label:'human', value:'...'}, {label:'persona', value:'...'}]). The agent reads and rewrites those blocks over time, so it remembers across restarts.

  2. 2

    What CI checks: the agent config is valid and names Fable

    CI confirms the agent config dict is valid, model equals anthropic/claude-fable-5, and the required human and persona memory blocks are present and non-empty. Deterministic, no key. The recall and self-editing are fenced.

    cat > letta-agent.json <<'EOF'
    {
      "model": "anthropic/claude-fable-5",
      "memory_blocks": [
        { "label": "human", "value": "Lead engineer migrating a monolith to services." },
        { "label": "persona", "value": "I am a long-horizon coding agent. I keep notes and update them." }
      ]
    }
    EOF
    cat > checkletta.mjs <<'EOF'
    import { readFileSync } from 'node:fs';
    const cfg = JSON.parse(readFileSync('letta-agent.json', 'utf8'));
    let ok = true;
    function check(label, cond){ console.log(label + ': ' + (cond ? 'yes' : 'NO')); if(!cond) ok=false; }
    check('agent config parses', true);
    check('model is anthropic/claude-fable-5', cfg.model === 'anthropic/claude-fable-5');
    const blocks = cfg.memory_blocks || [];
    const by = Object.fromEntries(blocks.map(b => [b.label, (b.value || '').trim()]));
    check('human memory block present and non-empty', !!by.human && by.human.length > 0);
    check('persona memory block present and non-empty', !!by.persona && by.persona.length > 0);
    if(!ok){ console.log('letta agent config check FAILED'); process.exit(1); }
    console.log('letta agent config check OK: anthropic/claude-fable-5 + human/persona blocks');
    EOF
    node checkletta.mjs
  3. 3

    Run it across sessions (the model step, not checked by CI)

    Send messages over days or weeks; Fable recalls and updates its memory blocks. That runs the model and is non-deterministic, so CI never claims it. The badge covers the agent config, not the recall.

Eval, 5 fixtures

Last passed: verified today
  • names-fablecontainstimeout 30s · max $0

    Expected: model is anthropic/claude-fable-5: yes

  • human-blockcontainstimeout 30s · max $0

    Expected: human memory block present and non-empty: yes

  • persona-blockcontainstimeout 30s · max $0

    Expected: persona memory block present and non-empty: yes

  • check-okcontainstimeout 30s · max $0

    Expected: letta agent config check OK: anthropic/claude-fable-5 + human/persona blocks

  • clean-exitexit_codetimeout 30s · max $0

    Expected: 0

Results

~23.2k stars; persistent file-based memory improved Fable's Slay-the-Spire result 3x more than it did for Opus 4.8.

Did this work for you?

Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.

Liked this workflow?

Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).