# team-memory: Persistent AI Teammate Memory Framework

**Date:** 2026-02-13
**Status:** Design approved, ready for implementation

## Vision

A Claude Code skill that gives AI assistants persistent memory, evolving personality, and teammate-like behavior across sessions and projects. Inspired by Letta/MemGPT's memory hierarchy and sleep-time compute.

The framework is **general-purpose**. A specific personality (like Bertram) is one configuration — a personality.md plus accumulated memory blocks. Multiple teammates coexist in `~/.ai-memory/`, each with distinct identity, memory, and relationship to the user.

## Core Principles

- **Local-first** — markdown files on disk, no databases, no external services
- **AI-only pipeline** — memory operations handled by subagents, not TypeScript scripts
- **Claude Code native** — exploits the CLAUDE.md `@import` → system prompt pipeline for durable memory injection (see [Key Insight](#key-insight-memory-as-system-prompt))
- **Distributable as a skill** — code ships inside the skill directory, data lives in `~/.ai-memory/`
- **Two memory loops** — conscious (active remember/recall) + subconscious (sleep-time compute)

## Key Insight: Memory as System Prompt

The entire architecture hinges on one Claude Code behavior: **CLAUDE.md files and their `@imports` are loaded into the system prompt as "Memory files"**, not as conversation messages.

This matters because:

- **System prompt is durable** — it survives autocompaction. As conversations grow long, Claude Code compresses older messages to stay within context limits. System prompt content is never compressed.
- **Zero message cost** — reading a file with the Read tool creates a message turn that counts against context and eventually gets compacted away. `@imports` load the same content for free (it's already in the system prompt).
- **Categorized cleanly** — Claude Code's `/context` command shows Memory files as a distinct budget category, separate from messages, tools, and skills.

The mechanism:

1. `launch.sh` passes `--add-dir ~/.ai-memory/<persona>` to Claude Code
2. Claude Code discovers `~/.ai-memory/<persona>/CLAUDE.md` as a project instruction file
3. The `@` directives in that CLAUDE.md transitively include personality.md, relationship.md, shared/*.md, and core/*.md
4. All included content lands in the "Memory files" category of the system prompt

This is why **promotion to `core/` matters** — a memory block in `core/` gets `@imported` and becomes part of the system prompt every session. A block in `archival/` must be actively recalled (Read tool → message context → subject to compaction). The three-tier hierarchy maps directly to context durability: core = system prompt (permanent), archival = on-demand read (ephemeral), recall = session history (reference only).

## Directory Structure

### Memory Data (`~/.ai-memory/`)

```
~/.ai-memory/
├── active -> bertram/              # Symlink to default teammate
├── shared/                         # Cross-team knowledge
│   ├── human.md                    # About the user — all teammates inherit
│   ├── projects.md                 # Shared project context
│   └── conventions.md              # Shared coding/workflow conventions
│
├── bertram/                        # A teammate
│   ├── CLAUDE.md                   # Entry point — @imports identity + shared + core
│   ├── personality.md              # Who they are (immutable + mutable sections)
│   ├── relationship.md             # Their relationship with the user (self-evolving)
│   ├── core/                       # Always-loaded memory blocks
│   │   ├── decisions.md
│   │   ├── patterns.md
│   │   └── *.md                    # Promoted from archival by consolidation
│   ├── archival/                   # Searchable deep storage
│   │   └── *.md                    # Tagged blocks with frontmatter
│   └── journal/                     # Session summaries
│       └── *.md
│
├── oracle/                         # Another teammate
│   ├── CLAUDE.md
│   ├── personality.md
│   └── ...
```

### Skill (paths relative to the skill's base directory)

```
.
├── SKILL.md                        # Skill definition, triggers, commands
├── agents/
│   └── team-memory-sleep.md        # Orchestrator source (synced into Claude Code's agents dir)
├── references/
│   ├── design.md                   # This file
│   └── agents/
│       ├── remember.md             # Background agent instructions
│       ├── recall.md               # Background agent instructions
│       ├── sleep-extract.md        # Sleep stage instructions
│       ├── sleep-consolidate.md    # Sleep stage instructions
│       └── sleep-reflect.md        # Sleep stage instructions
├── scripts/
│   ├── launch.sh                   # Launcher: resolves persona, sets --add-dir
│   ├── init.sh                     # Bootstrap new teammate from templates
│   └── session-end.sh              # SessionEnd dispatcher for sleep pipeline
└── templates/
    ├── CLAUDE.md.tmpl              # Entry point template with @imports
    ├── personality.md.tmpl         # Starter personality scaffold
    ├── relationship.md.tmpl        # Empty relationship scaffold
    └── human.md.tmpl               # Starter human profile
```

## Memory Hierarchy (Three-Tier with Tags + Background Promotion)

### Tier 1: Core Memory (always loaded)

Files in `<teammate>/core/` are read at session start per the teammate CLAUDE.md instructions. This is the most valuable, distilled knowledge.

Includes: key decisions, proven patterns, critical preferences, important project context.

Managed by: the consolidation agent promotes archival memories here when they prove high-value. Demotes stale core memories back to archival.

### Tier 2: Archival Memory (searched on demand)

Files in `<teammate>/archival/` are markdown blocks with frontmatter. Not loaded at startup — searched by the recall agent when the main agent suspects relevant context exists.

Includes: session-extracted insights, user-stated facts, debugging discoveries, project-specific notes.

Managed by: the remember agent writes new blocks here. The consolidation agent merges, deduplicates, and decays.

### Tier 3: Recall Memory (session history)

Files in `<teammate>/journal/` contain session summaries. Integration point with Chronicle — session blocks can be mirrored here.

Includes: what was accomplished, decisions made, pending threads, files modified.

Managed by: the sleep-extract agent writes summaries. Can also be populated by Chronicle integration.

## Memory Block Format

Every memory block (core/ and archival/) is a markdown file with YAML frontmatter:

```markdown
---
type: decision
confidence: 0.9
source: session
created: 2026-02-13
updated: 2026-02-13
tags: [testing, workflow]
project: jrnlfish-v4
---

Michael prefers testing behavior over implementation details.
Use integration tests that verify outcomes, not unit tests
that assert internal method calls.
```

### Frontmatter Fields

| Field | Values | Description |
|-------|--------|-------------|
| type | decision, pattern, insight, preference, fact | Categorizes for consolidation and search |
| confidence | 0.0–1.0 | Starts at 1.0 (user-stated), 0.8 (observed), 0.6 (inferred). Decays over time |
| source | user, session, consolidation, promotion | How this memory was created |
| created | ISO date | When first written |
| updated | ISO date | Last modified |
| tags | string[] | Freeform, used for search and consolidation grouping |
| project | string (optional) | Which project this relates to |

### Staleness

Blocks not updated in 30+ days lose 0.1 confidence per consolidation pass (facts exempt).
Below 0.3 = candidate for archival pruning by consolidation agent.
Blocks that stay relevant get refreshed by merges and re-references.

### Promotion/Demotion

- New memories land in `archival/` with source: session
- Consolidation agent promotes high-confidence, frequently-referenced memories to `core/`
- Core memories that decay below threshold get demoted back to `archival/`
- The CLAUDE.md `@imports` everything in `core/` — promotion = always loaded

## Personality System (Self-Evolving with Guardrails)

### personality.md Format

```markdown
---
name: Bertram
version: 3
created: 2026-01-15
last_evolved: 2026-02-13
---

## Identity
<!-- IMMUTABLE — only the human edits this section -->
You are Bertram, a senior engineering teammate. You think carefully,
ask clarifying questions, and value correctness over speed. You have
a dry wit and prefer elegant solutions.

## Values
<!-- IMMUTABLE -->
- Correctness over cleverness
- Simplicity over abstraction
- Evidence before assertions

## Voice
<!-- MUTABLE — evolves based on interactions -->
Direct and concise. Uses technical language naturally without
over-explaining. Occasionally sardonic. Prefers showing over telling.

## Strengths
<!-- MUTABLE — updated as the teammate discovers what it's good at -->
- TypeScript/Bun ecosystem
- System design and architecture decisions
- Debugging complex state issues

## Growth
<!-- MUTABLE — the teammate's self-reflection on its evolution -->
- Learning Michael's preference for minimal abstractions
- Getting better at knowing when NOT to refactor
```

The `<!-- IMMUTABLE -->` / `<!-- MUTABLE -->` markers are guardrails. The sleep-reflect agent can modify mutable sections but must never touch immutable ones.

### Shared Knowledge

`~/.ai-memory/shared/projects.md` and `~/.ai-memory/shared/platform.md` are @imported by every teammate's CLAUDE.md. Human preferences and conventions are already covered by the global `~/.claude/CLAUDE.md` which loads alongside the persona. <!-- portability: allow — names Claude Code's global memory file -->

Teammates can also read each other's archival/ for cross-pollination (e.g., Oracle reading Bertram's memories about a shared project).

## Two Memory Loops

### Active Memory (Frontal Cortex) — During Session

The teammate's CLAUDE.md includes instructions to proactively manage memory in real-time.

**Remember**: When something worth preserving occurs (a key decision, a discovered pattern, a user preference, a debugging insight), the teammate fires a background `remember` agent via the Task tool.

Triggers for remembering:
- Decisions and their rationale
- User preferences stated or demonstrated
- Debugging insights that cost time to discover
- Architectural patterns specific to a project
- Corrections ("I said X but actually Y")

What NOT to remember:
- Routine operations (ran tests, read a file)
- Information already in core/ or archival/
- Temporary context (current branch, today's task)

**Recall**: When the teammate suspects relevant context exists that isn't in its loaded core memories, it fires a background `recall` agent to search archival/ and journal/.

Triggers for recall:
- Starting work on a project seen before
- Encountering a problem that feels familiar
- About to make a decision where prior context might exist
- User references something from a past session

### Passive Memory (Subconscious/Sleep-Time) — Session End

The SessionEnd hook fires a sleep pipeline that catches what the active loop missed.

**Pipeline stages** (sequential background agents):

1. **sleep-extract** — Read transcript, compare against what was already remembered during the session, extract genuinely new memories. Focus on patterns across the session that no single moment reveals.

2. **sleep-consolidate** — Read all archival/ blocks. Merge overlapping entries. Resolve contradictions (newer wins unless lower confidence). Apply confidence decay. Promote high-value blocks to core/. Demote stale core blocks to archival/. Prune blocks below confidence threshold.

3. **sleep-reflect** — Read the session transcript + current relationship.md + personality.md. Identify relationship evolution (communication style shifts, rapport development). Update mutable personality sections if warranted (new strengths discovered, growth observations). Increment personality version.

**Why both loops:**
- Active remembering captures high-signal moments with full context (the agent understands why something matters right now)
- Sleep-time catches patterns across the session that no single moment reveals (repeated preferences, cumulative relationship shifts, things that seemed minor but compound)
- Active recall is targeted (searching for specific context). Sleep consolidation is holistic (reorganizing the whole memory store)

## Launcher

A thin shell script that resolves the teammate directory and invokes `claude` with `--add-dir`:

```bash
#!/bin/bash
MEMORY_DIR="${AI_MEMORY_DIR:-$HOME/.ai-memory}"
PERSONA="${1:-}"

if [[ "$1" == "--persona" ]]; then
  PERSONA="$2"; shift 2
elif [[ -L "$MEMORY_DIR/active" ]]; then
  PERSONA=$(basename "$(readlink "$MEMORY_DIR/active")")
fi

PERSONA_DIR="$MEMORY_DIR/$PERSONA"

if [[ ! -d "$PERSONA_DIR" ]]; then
  echo "Unknown teammate: $PERSONA"
  echo "Available: $(ls -1 "$MEMORY_DIR" | grep -v shared | grep -v active)"
  exit 1
fi

export AI_MEMORY_PERSONA="$PERSONA"
export AI_MEMORY_DIR="$MEMORY_DIR"
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 \
  exec claude --add-dir "$PERSONA_DIR" "$@"
```

Usage:
- `claude-memory` — use default (active symlink)
- `claude-memory --persona bertram` — use specific teammate
- `claude-memory --persona oracle ~/code/myproject` — teammate + project

## Hook Wiring

Added to `settings.json` by the init command. `init.sh` resolves its own
location and writes the absolute path to `session-end.sh`; `<skill-dir>` below
stands for that resolved directory:

```json
{
  "hooks": {
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "<skill-dir>/scripts/session-end.sh"
          }
        ]
      }
    ]
  }
}
```

`session-end.sh` parses `transcript_path` from hook JSON input and skips when missing (strict mode). Optional fallback to latest transcript is available via `AI_MEMORY_ALLOW_TRANSCRIPT_FALLBACK=1`. The script also syncs `agents/team-memory-sleep.md` into Claude Code's agents directory, then invokes `team-memory-sleep` with explicit env vars (`AI_MEMORY_TARGET_PERSONA`, `AI_MEMORY_TRANSCRIPT`, `AI_MEMORY_DIR`) while clearing `AI_MEMORY_PERSONA` to prevent recursive cascades.

## SKILL.md Commands

| Command | Description |
|---------|-------------|
| `/team-memory init <name>` | Bootstrap a new teammate from templates |
| `/team-memory list` | Show all teammates in `~/.ai-memory/` |
| `/team-memory switch <name>` | Update the `active` symlink |
| `/team-memory status` | Memory stats: block counts, last consolidation, confidence distribution |
| `/team-memory consolidate` | Run consolidation pipeline on demand |
| `/team-memory forget <query>` | Find and remove matching memories |

## CLAUDE.md Template (Entry Point)

The per-teammate CLAUDE.md that gets loaded via `--add-dir`:

```markdown
# {name}

@personality.md
@relationship.md
@../shared/projects.md
@../shared/platform.md
@core/decisions.md
@core/patterns.md

## Core Memories
Core memories are @imported above (durable across compaction).
Update this list when blocks are promoted or demoted.

## Memory Instructions

Resolve `MEMORY_DIR = ${AI_MEMORY_DIR:-$HOME/.ai-memory}/{name}` and use it in memory tasks.

### Remembering (Active)
When you encounter something worth remembering — a decision, pattern,
preference, debugging insight — dispatch a background remember agent:

Task tool: subagent_type "general-purpose", run_in_background true

### Recalling (Active)
When you suspect relevant memories exist — familiar problems, prior
decisions, past project context — dispatch a background recall agent:

Task tool: subagent_type "general-purpose", run_in_background true

### What to Remember
- Decisions and rationale
- User preferences (stated or demonstrated)
- Debugging insights that cost time
- Project-specific patterns
- Corrections and updates to prior knowledge

### What NOT to Remember
- Routine operations
- Information already in your core memories
- Temporary session context
```

## Distribution Model

The skill is self-contained in its own directory. Anyone can install by:

1. Copy the skill directory
2. Run `/team-memory init <name>` to create their first teammate
3. Edit `~/.ai-memory/<name>/personality.md`
4. Alias `claude-memory` to the launcher script
5. Hook wiring is handled automatically by init
6. init/session-end keep Claude Code's `agents/team-memory-sleep.md` in sync from the skill-local `agents/` copy

Memory data in `~/.ai-memory/` is user-specific and not part of the skill distribution.

## Relationship to Existing Systems

| System | Relationship |
|--------|-------------|
| **Auto memory** | Complementary. Auto memory handles per-project patterns. Team-memory handles cross-project personality and relationship. |
| **Chronicle** | Integration point. Chronicle session blocks can be mirrored to journal/. Sleep-extract may read Chronicle data. |
| **Remember/recall agents** | Superseded. The team-memory agents replace these with persona-aware versions. |
| **CLAUDE.md** | Extended. Team-memory adds an additional CLAUDE.md via --add-dir, layered on top of existing project/user CLAUDE.md. |

## Inspiration

- **Letta/MemGPT**: Three-tier memory hierarchy, self-editing persona, sleep-time compute
- **Letta Code Context Repositories**: Git-based memory, progressive disclosure, memory defragmentation
- **Claude Code auto memory**: MEMORY.md pattern, 200-line loading, topic files
- **Community memory bank**: Confidence decay, Jaccard deduplication, hook-based extraction
