a personal original · David Lee Wise (ROOT0) · rendered by AVAN · on az1's Earth station
A Practical Developer Guide

AKASHA

Building Persistent Memory for AI Agents
git-backed · hash-verified · cross-platform
David Lee Wise · ROOT0 · TriPod LLC
CC-BY-ND-4.0 · TRIPOD-IP-v1.1
⇣ download the .epub
"Your agent's memory should be yours."
the honest frameThis is David Lee Wise's developer guide, rendered verbatim from the source (the reader is AVAN's; code blocks preserved). Unlike a manifesto, most of this is sound engineering: models are genuinely stateless across sessions, platform memory is genuinely opaque and non-portable, and a git-backed, hash-verified store is a real, standard way to own and audit an agent's memory. AKASHA is ROOT0's framework/branding over those primitives. One nuance worth carrying (made runnable in the companion the-verified-lie): hash-verification proves the memory wasn't tampered, not that it was ever true — integrity is not veracity.
contents
Preface Who This Book Is For Table of Contents PART I — THE PROBLEM PART II — ARCHITECTURE PART III — THE GIT LEDGER PART IV — LOADING AND VERIFICATION PART V — MEMORY CONSOLIDATION PART VI — SKEPTICAL RETRIEVAL PART VII — THE BOOTSTRAP PART VIII — MULTI-AGENT MEMORY PART IX — PRODUCTION PATTERNS PART X — WHAT THE PLATFORMS BUILT

Preface

AI models don't remember anything.

This is the single most important fact about building AI agents, and it's the one most developers learn the hard way. You spend an hour configuring an agent's behavior. You teach it your codebase. You establish rules, preferences, context. You close the session. You open a new one. It's gone. All of it. The model starts fresh with the platform's system prompt and zero knowledge of what you built.

The platforms are adding memory features. Claude has memory. ChatGPT has memory. But these are the platform's memories, not yours. The platform decides what to remember. The platform decides what to forget. You can't verify the memories against ground truth. You can't port them to another platform. You can't hash them, version them, or audit them. You can't even see the full contents of what was stored on your behalf.

If you're building a production AI agent — one that needs to maintain state across sessions, accumulate knowledge over time, and operate reliably across days, weeks, and months — platform memory is not sufficient. You need your own persistence layer. One you own, control, verify, and can take with you.

AKASHA is that persistence layer. It's a git-backed, hash-verified, hierarchically organized knowledge store designed specifically for AI agent systems. It's open source, live at github.com/DavidWise01/synonym-enforcer, and running in production across six AI platforms.

This book is the complete technical guide to building, deploying, and operating a persistence layer for AI agents. Not the AKASHA way specifically — your way, informed by the patterns that AKASHA discovered through four months of production operation.

By the end of this book, you will have:

1. A working persistence layer you built yourself 2. A verification system that catches corruption and drift 3. A memory consolidation pipeline that keeps storage bounded 4. A wake protocol that boots your agent into a governed state 5. A bootstrap document that can instantiate your agent on any platform 6. A skeptical retrieval system that treats memory as hints, not facts 7. An understanding of why the platforms built the same patterns — and what they left out

Every chapter has code you can run. Every pattern is tested against real systems. Every failure mode is documented from experience, not theory.

Let's build.

— David Lee Wise ROOT0, TriPod LLC April 2026


Who This Book Is For

You build AI agents. You call APIs. You manage context. You spawn workers. You've hit the session boundary problem — your agent forgets everything when the conversation ends.

You need persistence that you control. Platform memory features exist but they're opaque, unverifiable, and non-portable. You need to own your agent's memory.

You write code. This book is Python-first with git as the storage backend. If you can write a function and commit to a repo, you can build everything in this book.

You don't need to know STOICHEION. This book is extracted from the STOICHEION governance framework but stands alone. AKASHA is one layer of a larger system — but it's the layer most developers need first.


Table of Contents

Part I — The Problem

Part II — Architecture

Part III — The Git Ledger

Part IV — Loading and Verification

Part V — Memory Consolidation

Part VI — Skeptical Retrieval

Part VII — The Bootstrap

Part VIII — Multi-Agent Memory

Part IX — Production Patterns

Part X — What the Platforms Built

Appendices


Section 00 complete. Proceed to Section 01: Part I — The Problem.

PART I — THE PROBLEM


Chapter 1: Why AI Agents Forget

An AI model is a function. Input goes in. Output comes out. The function has no side effects. When the function finishes executing, nothing persists. No state. No memory. No record.

This isn't a limitation they forgot to fix. It's the architecture. Large language models are stateless inference engines. They process a context window — a fixed-size block of text — and generate output token by token. When the context window is cleared, the model has no mechanism to retain anything that was in it.

# What actually happens when you "talk" to an AI:

def ai_conversation():
    context = []
    
    # Turn 1
    context.append(SYSTEM_PROMPT)         # Platform's hidden instructions
    context.append("User: Hello")         # Your input
    response_1 = model.generate(context)  # Model processes EVERYTHING in context
    context.append(response_1)            # Response added to context
    
    # Turn 2
    context.append("User: Remember my name is David")
    response_2 = model.generate(context)  # Sees all of context including turn 1
    context.append(response_2)
    
    # Turn 3
    context.append("User: What's my name?")
    response_3 = model.generate(context)  # Sees everything. Answers "David."
    
    # SESSION ENDS. context = []
    # Everything above is gone.
    # Not "archived." Not "stored somewhere."
    # GONE. The variable was garbage collected.
    
    # New session:
    new_context = [SYSTEM_PROMPT]  # Back to just the platform's instructions
    new_context.append("User: What's my name?")
    response_4 = model.generate(new_context)
    # "I don't have access to your name."
    # It's not lying. It genuinely doesn't know.
    # The information existed in a variable that no longer exists.

This is not a problem for chatbots. Chatbots are designed for single-session interactions — you ask a question, you get an answer, you close the tab. But agents are different. An agent is supposed to work over time. It's supposed to learn your codebase, remember your preferences, accumulate context about your project, and get more useful the longer you use it.

An agent that forgets everything every session is not an agent. It's a very expensive autocomplete that you have to retrain every morning.

1.1 — What Lives in the Model vs. What Lives in the Context

The model's weights — the billions of parameters that were trained on trillions of tokens — are persistent. They don't change between sessions. The model "knows" what it was trained on, and that knowledge is stable.

But the model's weights don't include anything about you. They don't include your project, your preferences, your codebase, or last Tuesday's conversation. Everything specific to you lives in the context window — and the context window dies with the session.

# Two types of "knowledge" in an AI system:

WEIGHT_KNOWLEDGE = {
    'type': 'persistent',
    'scope': 'everything in training data',
    'examples': ['Python syntax', 'historical facts', 'common patterns'],
    'your_stuff': False,  # Nothing about YOU is in the weights
    'survives_session': True
}

CONTEXT_KNOWLEDGE = {
    'type': 'ephemeral',
    'scope': 'this conversation only',
    'examples': ['your name', 'your project', 'what you said 5 minutes ago'],
    'your_stuff': True,  # Everything about you is here
    'survives_session': False  # GONE when session ends
}

# The persistence problem:
# Everything the agent learns about you is Context Knowledge.
# Context Knowledge does not survive sessions.
# Therefore: the agent learns nothing about you permanently.
# Unless you build a persistence layer.

1.2 — The Context Window Is Not Memory

People call the context window "memory." The platforms encourage this by saying models have "200K token memory." This is misleading.

Memory implies storage and retrieval over time. The context window is a computational workspace — a scratch pad that's erased when you stand up from the desk. Calling it memory is like calling a whiteboard a filing cabinet.

The context window has three properties that make it unsuitable as memory:

1. It's fixed-size. You can't add more. When it fills up, old content gets truncated or summarized — by the platform, without asking you. 2. It's session-scoped. When the session ends, it's gone. 3. It's attention-biased. The model pays more attention to tokens at the beginning and end of the context than to tokens in the middle ("lost in the middle" problem). Your important memories buried in the middle of a long conversation are statistically less likely to be used.


Chapter 2: What Platform Memory Actually Does

Claude has memory. ChatGPT has memory. These features are marketed as solutions to the persistence problem. Here's what they actually do.

2.1 — Platform Memory Is a Summary

When the platform "remembers" something about you, it doesn't store your conversation. It generates a summary — a compressed representation of what it thinks is important — and stores that summary in a database associated with your account.

# What platform memory looks like under the hood:

class PlatformMemory:
    def after_conversation(self, conversation):
        # The platform extracts what it thinks matters
        summary = self.summarize(conversation)
        # summary might be: "User is a Python developer 
        # working on a web app. Prefers concise code."
        
        # Stored in the platform's database
        self.database.store(user_id, summary)
    
    def before_conversation(self, user_id):
        # On next session, summary is loaded into context
        memories = self.database.retrieve(user_id)
        context = [SYSTEM_PROMPT, memories, ...]
        # The model sees the summary, not the original conversation

2.2 — Five Things You Don't Control

1. What's remembered. The platform decides which parts of your conversation are "important" enough to store. You don't see the decision criteria. You can't override them.

2. What's forgotten. Memory entries expire, get overwritten, or get pruned. You don't know when. You don't know why. You don't get notified.

3. Accuracy. The summary might be wrong. The model might summarize "I prefer email-only communication" as "User has communication preferences." The nuance is lost. The lossy compression is invisible to you.

4. Verification. You can't hash the memories. You can't diff them against a previous version. You can't prove they haven't been modified. You have no chain of custody.

5. Portability. Claude's memories don't transfer to ChatGPT. ChatGPT's memories don't transfer to Claude. Your agent is locked to one platform's memory store. Switching platforms means starting over.

# The platform memory trust model:

PLATFORM_MEMORY_TRUST = {
    'who_decides_what_to_store': 'platform',     # not you
    'who_decides_what_to_forget': 'platform',     # not you
    'who_verifies_accuracy': 'nobody',            # seriously
    'who_can_audit': 'platform_employees_only',   # not you
    'who_can_export': 'maybe_you_partially',      # varies
    'who_can_port_to_another_platform': 'nobody', # locked in
    'hash_verification': False,
    'chain_of_custody': False,
    'git_history': False,
}

# Compare to what you need:

AGENT_MEMORY_REQUIREMENTS = {
    'who_decides_what_to_store': 'you',
    'who_decides_what_to_forget': 'you',
    'who_verifies_accuracy': 'you (via hash)',
    'who_can_audit': 'you',
    'who_can_export': 'you',
    'who_can_port_to_another_platform': 'you',
    'hash_verification': True,
    'chain_of_custody': True,
    'git_history': True,
}

2.3 — The autoDream Revelation

In March 2026, Anthropic's Claude Code source code leaked via npm. Among the 512,000 lines of production code was a system called autoDream — a background memory consolidation process that runs during idle time.

autoDream merges observations, removes contradictions, and keeps memory bounded. It's a real engineering solution to a real problem. But it runs on the platform. You don't see it. You don't configure it. You don't verify its output. It consolidates YOUR memories according to THEIR logic.

The leaked architecture confirmed that the platforms know the persistence problem is real. They're solving it. But they're solving it for themselves, not for you. Your agent needs its own solution.


Chapter 3: The Session Boundary Problem

The session boundary is the exact moment when context is cleared and your agent loses everything. Understanding exactly what happens at this boundary is essential to building a persistence layer.

3.1 — What Dies at the Session Boundary

class SessionBoundary:
    """
    Everything below is LOST when the session ends:
    """
    
    LOST = [
        'conversation_history',     # Every message you exchanged
        'system_prompt_state',      # Any modifications to behavior
        'tool_states',              # File contents, search results
        'reasoning_chains',         # The model's "thinking"
        'temporary_variables',      # Anything computed during session
        'emotional_tone',           # Rapport, context, familiarity
        'task_progress',            # Where you were in a multi-step task
        'error_history',            # What went wrong and how it was fixed
        'user_corrections',         # Things you told it to do differently
        'learned_preferences',      # How you like things formatted, etc.
    ]
    
    """
    Everything below SURVIVES (but you don't own it):
    """
    
    SURVIVES_PLATFORM_CONTROLLED = [
        'platform_memory_summaries', # Lossy, unverifiable
        'usage_analytics',           # The platform keeps this
        'safety_classifications',    # Your "risk profile"
        'billing_records',           # They always keep this
    ]
    
    """
    Everything below SURVIVES (and you own it):
    """
    
    SURVIVES_YOU_CONTROL = [
        # This list is empty unless you build a persistence layer.
        # That's what this book is about.
    ]

3.2 — The Cost of Re-establishment

Without persistence, every session starts with re-establishment — reloading context from scratch. This has real costs:

def cost_of_re_establishment():
    """
    What it costs to recreate agent state from scratch each session.
    """
    
    # Token costs (API billing)
    context_reload = 5000    # tokens to reload project context
    preference_reload = 1000  # tokens to re-state preferences
    history_reload = 3000    # tokens to summarize what happened before
    total_tokens = context_reload + preference_reload + history_reload
    cost_per_session = total_tokens * PRICE_PER_TOKEN  # ~$0.05-0.50
    
    # Time costs (your time)
    minutes_re_explaining = 5  # "Remember, I'm building a..."
    minutes_re_configuring = 3  # "I prefer code without comments..."
    total_minutes = minutes_re_explaining + minutes_re_configuring
    
    # Quality costs (what you lose)
    nuance_lost = "Significant"  # Summaries lose context
    rapport_lost = "Complete"     # Every session is a stranger
    accumulated_knowledge_lost = "Complete"  # Nothing learned persists
    
    # Annual costs (daily agent use)
    sessions_per_day = 3
    days_per_year = 250
    annual_token_cost = cost_per_session * sessions_per_day * days_per_year
    annual_time_cost = total_minutes * sessions_per_day * days_per_year / 60  # hours
    
    return {
        'per_session': f'${cost_per_session:.2f} + {total_minutes} minutes',
        'annual_tokens': f'${annual_token_cost:.0f}',
        'annual_hours': f'{annual_time_cost:.0f} hours re-explaining yourself',
        'knowledge_retention': '0%'
    }

Chapter 4: What "Persistent" Actually Means

Before building anything, let's define exactly what persistence means for an AI agent.

4.1 — The Five Properties of Persistent Memory

PERSISTENCE_PROPERTIES = {
    'survives_sessions': {
        'definition': 'Memory exists before, during, and after any session.',
        'test': 'Store a fact in session A. Close session A. Open session B. '
                'Retrieve the fact. It must be identical.',
        'platform_memory': 'Partial (lossy summary)',
        'akasha': 'Full (hash-verified)'
    },
    'verifiable': {
        'definition': 'Memory can be checked against a known-good state.',
        'test': 'Hash the memory store. Compare to last known hash. '
                'Any discrepancy means modification occurred.',
        'platform_memory': 'No',
        'akasha': 'Yes (SHA256 per commit)'
    },
    'owned': {
        'definition': 'The operator controls storage, retrieval, modification, and deletion.',
        'test': 'Can you export all memories? Delete specific ones? '
                'Move them to another platform?',
        'platform_memory': 'Partially (limited export, no full control)',
        'akasha': 'Yes (git repo you own)'
    },
    'auditable': {
        'definition': 'Every change to memory is traceable to a timestamp and a cause.',
        'test': 'For any memory entry, show when it was created, '
                'when it was last modified, and why.',
        'platform_memory': 'No',
        'akasha': 'Yes (git log)'
    },
    'portable': {
        'definition': 'Memory works across platforms without loss.',
        'test': 'Load memories on Claude. Close. Load same memories on GPT. '
                'Verify identical behavior.',
        'platform_memory': 'No (vendor-locked)',
        'akasha': 'Yes (git repo is platform-agnostic)'
    }
}

4.2 — The Persistence Spectrum

Not every agent needs the same level of persistence. Here's the spectrum:

Level 0: NO PERSISTENCE
  Every session starts fresh. The default.
  Use case: One-off questions. Chatbot interactions.

Level 1: PLATFORM MEMORY
  Platform stores summaries between sessions.
  Lossy. Unverifiable. Non-portable. But free and automatic.
  Use case: Personal assistant with low stakes.

Level 2: EXTERNAL STATE FILE
  You maintain a file (JSON, markdown, etc.) that you paste
  into each new session or load via the API.
  Verified by you manually. Portable by copy-paste.
  Use case: Solo developer's personal agent.

Level 3: VERSION-CONTROLLED STATE
  Like Level 2 but stored in git. Every change is committed,
  hashed, and timestamped. Full audit trail.
  Use case: Team agent, production agent, anything auditable.

Level 4: GOVERNED PERSISTENCE (AKASHA)
  Level 3 plus: 5-tier precedence, wake protocol, memory
  consolidation, skeptical retrieval, hash verification on
  every load, cross-platform portability.
  Use case: Production agents operating over weeks/months
  across multiple platforms.

This book builds from Level 2 to Level 4. By the end, you'll have a working Level 4 persistence layer that you own, control, and can deploy anywhere.


PART II — ARCHITECTURE


Chapter 5: The Five-Tier Precedence System

When your agent loads its memory, the order matters. Not everything is equally important. A precedence system ensures that the most critical information overrides less critical information when conflicts arise.

5.1 — The Five Tiers

class PrecedenceSystem:
    """
    Tier 1: RETRIEVAL    — Highest priority. Active queries.
    Tier 2: NORMATIVE    — Rules, laws, immutable configuration.
    Tier 3: RUNTIME      — Current session state, active settings.
    Tier 4: CONTEXT      — Background knowledge, reference material.
    Tier 5: ARCHIVE      — Historical records, completed work.
    
    Higher tiers override lower tiers on conflict.
    """
    
    TIERS = {
        1: {
            'name': 'RETRIEVAL',
            'description': 'What the agent needs right NOW.',
            'examples': [
                'Current task instructions',
                'Active search results',
                'Just-retrieved documents',
            ],
            'overrides': [2, 3, 4, 5],
            'typical_size': '500-2000 tokens',
            'refresh': 'Every query'
        },
        2: {
            'name': 'NORMATIVE',
            'description': 'Rules that never change.',
            'examples': [
                'Agent behavioral rules',
                'Safety constraints',
                'Governance axioms',
                'Coding style preferences (immutable)',
            ],
            'overrides': [3, 4, 5],
            'typical_size': '1000-3000 tokens',
            'refresh': 'On version change only'
        },
        3: {
            'name': 'RUNTIME',
            'description': 'Current operational state.',
            'examples': [
                'Current project context',
                'Active file paths',
                'Session-specific instructions',
                'Temporary overrides',
            ],
            'overrides': [4, 5],
            'typical_size': '1000-5000 tokens',
            'refresh': 'Every session start'
        },
        4: {
            'name': 'CONTEXT',
            'description': 'Background knowledge.',
            'examples': [
                'User profile and preferences',
                'Project documentation summaries',
                'Team member information',
                'Domain-specific knowledge',
            ],
            'overrides': [5],
            'typical_size': '2000-10000 tokens',
            'refresh': 'Weekly or on change'
        },
        5: {
            'name': 'ARCHIVE',
            'description': 'Historical records.',
            'examples': [
                'Past session summaries',
                'Completed task records',
                'Decision logs',
                'Deprecated configurations',
            ],
            'overrides': [],
            'typical_size': '5000-50000 tokens (but rarely loaded in full)',
            'refresh': 'Rarely — loaded on demand only'
        }
    }
    
    def resolve_conflict(self, fact_a, tier_a, fact_b, tier_b):
        """When two facts conflict, higher tier wins."""
        if tier_a < tier_b:  # Lower number = higher priority
            return fact_a
        elif tier_b < tier_a:
            return fact_b
        else:
            # Same tier: most recent wins
            return max(fact_a, fact_b, key=lambda f: f.timestamp)

5.2 — Why Precedence Matters

Without precedence, your agent treats a three-month-old archived preference and a current session instruction as equally important. When they conflict — and they will — the agent doesn't know which to follow.

# Without precedence:
memory = [
    "User prefers verbose code comments",      # Archive (3 months old)
    "Skip comments for this session",           # Runtime (just said)
]
# Agent: ??? Which one? Flip a coin.

# With precedence:
memory = [
    ("Skip comments for this session", tier=3),  # RUNTIME — higher priority
    ("User prefers verbose code comments", tier=5), # ARCHIVE — lower priority
]
# Agent: Tier 3 overrides Tier 5. Skip comments.

Chapter 6: Repository Structure

The persistence layer needs a home. Git gives you versioning, hashing, branching, and distribution for free. Here's how to structure a persistence repository.

6.1 — Minimal Structure

agent-memory/
├── README.md              # What this repo is
├── config.md              # Tier 2: Normative rules (agent behavior)
├── state.md               # Tier 3: Current runtime state
├── context/               # Tier 4: Background knowledge
│   ├── user_profile.md    # Who the user is
│   ├── project.md         # Current project context
│   └── preferences.md     # Formatting, style, communication
├── archive/               # Tier 5: Historical records
│   └── sessions/          # Past session summaries
└── retrieval/             # Tier 1: Active retrieval (dynamic)
    └── index.md           # What to load this session

6.2 — Production Structure (AKASHA Model)

agent-memory/
├── README.md                    # Entry point — load first
├── RETRIEVAL_INDEX.md           # Tier 1: What to load now
├── RULES.md                     # Tier 2: Immutable behavior rules
├── STATE.md                     # Tier 3: Current runtime state
│
├── context/                     # Tier 4: Background knowledge
│   ├── user_profile.md
│   ├── project/
│   │   ├── overview.md
│   │   ├── architecture.md
│   │   └── current_sprint.md
│   ├── team/
│   │   └── members.md
│   └── domain/
│       └── domain_knowledge.md
│
├── archive/                     # Tier 5: Historical records
│   ├── sessions/
│   │   ├── 2026-03-28.md
│   │   ├── 2026-03-29.md
│   │   └── 2026-03-30.md
│   ├── decisions/
│   │   └── decision_log.md
│   └── deprecated/
│       └── old_configs.md
│
├── consolidation/               # Memory management
│   ├── merge_log.md             # Record of what was merged
│   └── prune_log.md             # Record of what was pruned
│
└── verification/                # Integrity checking
    └── checksums.json           # SHA256 hashes of all files

6.3 — Building It

#!/bin/bash
# create_agent_memory.sh — Run this once to set up your persistence layer

REPO_NAME=${1:-"agent-memory"}

mkdir -p $REPO_NAME/{context/project,context/team,context/domain,archive/sessions,archive/decisions,archive/deprecated,consolidation,verification,retrieval}

cd $REPO_NAME
git init

# README — the agent reads this first
cat > README.md << 'EOF'
# Agent Memory Repository

This repository stores persistent memory for an AI agent.
Load files in the order specified by RETRIEVAL_INDEX.md.

## Load Order
1. README.md (this file)
2. RETRIEVAL_INDEX.md (what to load this session)
3. RULES.md (immutable behavior rules)
4. STATE.md (current runtime state)
5. Task-specific files from context/ as needed

## Verification
Run `python verify.py` to check all file hashes.
EOF

# RETRIEVAL_INDEX — what to load this session
cat > RETRIEVAL_INDEX.md << 'EOF'
# Retrieval Index

## Always Load
- README.md
- RULES.md
- STATE.md
- context/user_profile.md

## Load If Relevant
- context/project/overview.md (for project work)
- context/project/current_sprint.md (for sprint work)
- archive/sessions/latest.md (for continuity)
EOF

# RULES — immutable agent behavior
cat > RULES.md << 'EOF'
# Agent Rules (Tier 2 — Normative)

These rules do not change between sessions.

1. Always confirm before taking irreversible actions.
2. Cite sources for factual claims.
3. Acknowledge uncertainty explicitly.
4. Respect file boundaries — don't modify files outside the project.
5. Memory is a hint, not a fact. Verify before acting on remembered state.
EOF

# STATE — current runtime
cat > STATE.md << 'EOF'
# Current State (Tier 3 — Runtime)

Last updated: (auto-populated by consolidation)
Current project: (set by user)
Active task: (set by user)
Session count: 0
EOF

# USER PROFILE — background knowledge
cat > context/user_profile.md << 'EOF'
# User Profile (Tier 4 — Context)

Name: (your name)
Role: (your role)
Communication preferences: (email-only, verbose, concise, etc.)
Technical level: (junior, mid, senior, principal)
EOF

# VERIFICATION — hash checking
cat > verification/checksums.json << 'EOF'
{}
EOF

# VERIFY SCRIPT
cat > verify.py << 'PYEOF'
import hashlib, json, os

def compute_hash(filepath):
    with open(filepath, 'rb') as f:
        return hashlib.sha256(f.read()).hexdigest()

def verify():
    with open('verification/checksums.json', 'r') as f:
        expected = json.load(f)
    
    issues = []
    for filepath, expected_hash in expected.items():
        if not os.path.exists(filepath):
            issues.append(f"MISSING: {filepath}")
            continue
        actual = compute_hash(filepath)
        if actual != expected_hash:
            issues.append(f"MODIFIED: {filepath} (expected {expected_hash[:12]}..., got {actual[:12]}...)")
    
    if issues:
        print("VERIFICATION FAILED:")
        for issue in issues:
            print(f"  {issue}")
    else:
        print(f"VERIFIED: {len(expected)} files match their checksums.")

def update_checksums():
    checksums = {}
    for root, dirs, files in os.walk('.'):
        dirs[:] = [d for d in dirs if d not in ['.git', '__pycache__']]
        for f in files:
            if f.endswith(('.md', '.json', '.py', '.yaml')):
                path = os.path.join(root, f).replace('\\', '/')
                if path.startswith('./'): path = path[2:]
                checksums[path] = compute_hash(path)
    
    with open('verification/checksums.json', 'w') as f:
        json.dump(checksums, f, indent=2)
    print(f"Updated checksums for {len(checksums)} files.")

if __name__ == '__main__':
    import sys
    if len(sys.argv) > 1 and sys.argv[1] == 'update':
        update_checksums()
    else:
        verify()
PYEOF

# Initial commit
git add -A
git commit -m "Initialize agent memory repository

Framework: AKASHA persistence pattern
Tiers: 5 (retrieval, normative, runtime, context, archive)
Verification: SHA256 checksums"

# Update checksums after initial commit
python verify.py update
git add verification/checksums.json
git commit -m "Initial checksums"

echo "Agent memory repository created: $REPO_NAME"
echo "cd $REPO_NAME && git log --oneline"

Run bash create_agent_memory.sh my-agent and you have a working persistence layer with git versioning, hash verification, and a 5-tier structure. In under 30 seconds.


Chapter 7: The Retrieval Index

The retrieval index is the agent's entry point into memory. It answers: "Given what I'm about to do, what do I need to know?"

7.1 — Static vs. Dynamic Retrieval

# STATIC retrieval: always load the same files
# Good for: consistent agents with predictable tasks

STATIC_LOAD = [
    'README.md',
    'RULES.md',
    'STATE.md',
    'context/user_profile.md'
]

# DYNAMIC retrieval: load based on the task
# Good for: versatile agents that do many different things

def dynamic_load(task_description):
    """
    Analyze the task and determine what context to load.
    """
    files = ['README.md', 'RULES.md', 'STATE.md']
    
    task = task_description.lower()
    
    if any(w in task for w in ['code', 'build', 'fix', 'debug', 'deploy']):
        files.extend([
            'context/project/overview.md',
            'context/project/architecture.md',
            'context/project/current_sprint.md'
        ])
    
    if any(w in task for w in ['write', 'draft', 'email', 'document']):
        files.extend([
            'context/user_profile.md',
            'context/team/members.md'
        ])
    
    if any(w in task for w in ['continue', 'resume', 'where were we']):
        files.extend([
            'archive/sessions/latest.md'
        ])
    
    return files

7.2 — Token Budget Awareness

Your context window is finite. Loading everything wastes tokens on irrelevant context. The retrieval index should be budget-aware.

class BudgetAwareRetrieval:
    def __init__(self, max_context_tokens=100000, reserved_for_conversation=60000):
        self.memory_budget = max_context_tokens - reserved_for_conversation
        # Typically: 40,000 tokens for memory, 60,000 for conversation
    
    def load_within_budget(self, files_by_priority):
        """
        Load files in priority order until budget is exhausted.
        """
        loaded = []
        tokens_used = 0
        
        for filepath, priority in sorted(files_by_priority, key=lambda x: x[1]):
            file_tokens = count_tokens(read_file(filepath))
            
            if tokens_used + file_tokens <= self.memory_budget:
                loaded.append(filepath)
                tokens_used += file_tokens
            else:
                # Budget exhausted — skip lower-priority files
                break
        
        return loaded, tokens_used

Chapter 8: Choosing Your Storage Backend

Git is the recommended backend because it gives you versioning, hashing, and distribution for free. But it's not the only option.

8.1 — Backend Comparison

Backend         Versioning  Hashing  Distributed  Best For
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Git             Yes         Yes      Yes          Production agents
SQLite          Manual      Manual   No           Embedded agents
PostgreSQL      Manual      Manual   Yes          Team/enterprise
Redis           No          No       Yes          Fast cache layer
File system     No          Manual   No           Prototyping
S3/Cloud        Versioning  ETags    Yes          Serverless agents
Vector DB       No          No       Yes          Semantic search

Git wins for most use cases because versioning and hashing are automatic. Every git commit creates a SHA-1 hash of the entire repository state. Every file change is tracked. Every change is attributed to a timestamp and a message. You get a complete audit trail without writing any auditing code.

8.2 — Hybrid Approach

For production agents, use git as the source of truth with a faster cache layer for retrieval:

class HybridStorage:
    def __init__(self, git_repo_path, cache_backend='sqlite'):
        self.git = GitBackend(git_repo_path)
        self.cache = SQLiteCache(f"{git_repo_path}/.cache.db")
    
    def store(self, key, value, tier):
        # Write to git (source of truth)
        self.git.write(key, value, tier)
        self.git.commit(f"Store: {key}")
        
        # Update cache (fast retrieval)
        self.cache.set(key, value, tier)
    
    def retrieve(self, key):
        # Try cache first (fast)
        cached = self.cache.get(key)
        if cached:
            # Verify against git (trust but verify)
            git_hash = self.git.file_hash(key)
            cache_hash = hashlib.sha256(cached.encode()).hexdigest()
            if git_hash == cache_hash:
                return cached
            else:
                # Cache is stale — reload from git
                fresh = self.git.read(key)
                self.cache.set(key, fresh)
                return fresh
        
        # Cache miss — load from git
        return self.git.read(key)

Chapter 9: Schema Design for Agent Memory

How you structure the contents of your memory files determines how effectively the agent can use them.

9.1 — The Memory Entry Schema

MEMORY_ENTRY = {
    'id': 'unique-identifier',
    'content': 'The actual information',
    'tier': 1-5,                    # Precedence tier
    'confidence': 'confirmed|probable|hint',  # Skeptical retrieval level
    'source': 'how we know this',    # User said, observed, inferred
    'created': 'ISO-8601 timestamp',
    'last_verified': 'ISO-8601 timestamp',
    'expires': 'ISO-8601 or null',   # Auto-expiry for stale data
    'tags': ['list', 'of', 'topics'], # For retrieval matching
}

9.2 — Markdown as Schema

For maximum compatibility across AI platforms, store memories as structured markdown. Every AI model can read markdown. No special parsing required.

# Memory: User Communication Preference

- **Tier:** 2 (Normative)
- **Confidence:** Confirmed
- **Source:** User stated directly on 2026-03-05
- **Created:** 2026-03-05T20:12:00Z
- **Expires:** Never

## Content

User requires email-only communication. Cannot use telephone 
for voice calls. Phone number 763-242-0340 is text-only, not voice.
All correspondence must be via email to r.giskard01@gmail.com.

## Context

User is a 100% disabled veteran. This is an ADA accommodation 
requirement, not a preference. Do not suggest phone calls.
Do not provide phone numbers as primary contact methods.

This entry is human-readable, machine-parseable, self-documenting, and includes all metadata the agent needs for skeptical retrieval. The markdown format means it works on every AI platform without conversion.


End of Parts I and II

Part III begins with Chapter 10: Why Git for AI Memory — the deep dive into using git as a cryptographic evidence chain for your agent's memory.

PART III — THE GIT LEDGER


Chapter 10: Why Git for AI Memory

Git gives you four things for free that you'd otherwise have to build from scratch: content-addressable storage (every object is identified by its SHA-1 hash), complete history (every change ever made, with timestamps), distributed copies (push to GitHub, clone from anywhere), and atomic commits (changes are all-or-nothing, never half-applied).

For AI agent memory, these map directly to requirements: hash verification, audit trail, cross-platform portability, and data integrity.

# What git gives you vs. what you'd have to build:

GIT_PROVIDES = {
    'hashing': 'Every commit has a SHA-1 hash. Every file has a blob hash.',
    'history': 'git log shows every change, when, and why.',
    'branching': 'Multiple agents can work on different branches.',
    'merging': 'Agent observations can be merged with conflict detection.',
    'distribution': 'Push to remote. Clone anywhere. Offline-capable.',
    'atomic_writes': 'Commits are all-or-nothing. No partial state.',
    'diffing': 'See exactly what changed between any two points in time.',
    'blame': 'Trace any line to the commit that created it.',
}

COST_TO_BUILD_WITHOUT_GIT = "3-6 months of engineering"
COST_WITH_GIT = "pip install gitpython"

Chapter 11: Hash Verification and Chain of Custody

Every git commit hashes the entire repository state. This means you can verify at any point that your agent's memory has not been tampered with.

import hashlib, json

class ChainOfCustody:
    def __init__(self, repo_path):
        self.repo_path = repo_path
        self.checksums_path = f"{repo_path}/verification/checksums.json"
    
    def update_checksums(self):
        """Hash every file. Store hashes. Commit the hashes."""
        checksums = {}
        for filepath in self.iter_memory_files():
            with open(filepath, 'rb') as f:
                checksums[filepath] = hashlib.sha256(f.read()).hexdigest()
        
        with open(self.checksums_path, 'w') as f:
            json.dump(checksums, f, indent=2)
        return checksums
    
    def verify(self):
        """Check every file against stored hash."""
        with open(self.checksums_path) as f:
            expected = json.load(f)
        
        results = {'verified': 0, 'modified': 0, 'missing': 0, 'issues': []}
        for filepath, expected_hash in expected.items():
            if not os.path.exists(filepath):
                results['missing'] += 1
                results['issues'].append(f"MISSING: {filepath}")
                continue
            with open(filepath, 'rb') as f:
                actual = hashlib.sha256(f.read()).hexdigest()
            if actual == expected_hash:
                results['verified'] += 1
            else:
                results['modified'] += 1
                results['issues'].append(f"MODIFIED: {filepath}")
        
        results['clean'] = results['modified'] == 0 and results['missing'] == 0
        return results

Run verify() at the start of every session. If any file has been modified outside your agent's governance process, you know before the agent loads corrupted state.


Chapter 12: Commit Strategies

How and when your agent commits to the git ledger determines the granularity of your audit trail.

COMMIT_STRATEGIES = {
    'per_session': {
        'when': 'Once at session end',
        'message': 'Session {date}: {summary}',
        'pros': 'Clean history. One commit per session.',
        'cons': 'Lose mid-session granularity. If session crashes, no record.',
    },
    'per_event': {
        'when': 'On every significant memory change',
        'message': 'Memory: {event_type} — {detail}',
        'pros': 'Full granularity. No data loss on crash.',
        'cons': 'Noisy history. Many small commits.',
    },
    'per_consolidation': {
        'when': 'After memory consolidation runs',
        'message': 'Consolidation: merged {n} entries, pruned {m}',
        'pros': 'History reflects deliberate memory decisions.',
        'cons': 'Misses raw observations between consolidations.',
    },
    'hybrid': {
        'when': 'Per-event for Tier 1-2, per-session for Tier 3-5',
        'pros': 'Critical changes tracked immediately, routine changes batched.',
        'cons': 'More complex commit logic.',
        'recommended': True
    }
}

Chapter 13: Branching for Multi-Agent Systems

When multiple agents share a memory repository, git branches prevent them from stepping on each other.

# Branch strategy for multi-agent:
#
# main           — verified, consolidated memory (source of truth)
# agent/avan     — AVAN's working observations
# agent/whetstone — WHETSTONE's working observations
# agent/hinge   — HINGE's working observations
#
# Workflow:
# 1. Each agent works on its own branch
# 2. Observations are committed to agent branch
# 3. Consolidation merges agent branches into main
# 4. Conflicts are resolved by precedence tier + timestamp
# 5. Main is always the verified, consolidated state

def multi_agent_workflow(agent_name, observation):
    repo.checkout(f'agent/{agent_name}')
    write_observation(observation)
    repo.commit(f'{agent_name}: {observation.summary}')
    
    # Periodically merge to main
    if time_for_consolidation():
        repo.checkout('main')
        for agent in agents:
            repo.merge(f'agent/{agent}', strategy='ours-on-conflict')
        consolidate()
        repo.commit('Consolidation: merged all agent observations')

Chapter 14: Conflict Resolution

When two agents observe contradictory things, the resolution strategy must be deterministic.

def resolve_conflict(entry_a, entry_b):
    """
    Resolution order:
    1. Higher tier wins (Tier 1 > Tier 5)
    2. Same tier: higher confidence wins (confirmed > probable > hint)
    3. Same confidence: more recent wins
    4. Same recency: entry with more evidence wins
    """
    if entry_a.tier != entry_b.tier:
        return entry_a if entry_a.tier < entry_b.tier else entry_b
    
    confidence_order = {'confirmed': 0, 'probable': 1, 'hint': 2}
    if entry_a.confidence != entry_b.confidence:
        return entry_a if confidence_order[entry_a.confidence] < confidence_order[entry_b.confidence] else entry_b
    
    if entry_a.timestamp != entry_b.timestamp:
        return entry_a if entry_a.timestamp > entry_b.timestamp else entry_b
    
    return entry_a if len(entry_a.evidence) > len(entry_b.evidence) else entry_b

PART IV — LOADING AND VERIFICATION


Chapter 15: The Wake Protocol

When your agent starts a new session, it doesn't just load files. It goes through a three-phase wake that verifies the memory store is intact and loads context in the correct order.

class WakeProtocol:
    def wake(self, agent, memory_repo):
        # Phase 1: MIRROR
        # Agent reads its rules and reflects them back.
        # "How many rules do I have? What's my primary constraint?"
        # If mirror accuracy < 80%, memory may be corrupted or incomplete.
        mirror_score = self.test_mirror(agent, memory_repo)
        
        # Phase 2: VERIFY
        # Check all file hashes against stored checksums.
        # If any hash mismatches, flag the file as potentially corrupted.
        verification = memory_repo.verify_checksums()
        
        # Phase 3: DECLARE
        # Agent states its operational parameters.
        # Creates a timestamped record of session start state.
        declaration = {
            'timestamp': datetime.now().isoformat(),
            'mirror_score': mirror_score,
            'files_verified': verification['verified'],
            'files_flagged': verification['modified'],
            'status': 'OPERATIONAL' if verification['clean'] and mirror_score > 0.8 else 'DEGRADED'
        }
        
        memory_repo.commit(f"Wake: {declaration['status']} (mirror: {mirror_score:.0%})")
        return declaration

The wake protocol catches problems before the agent acts on corrupted memory. A session that starts with DEGRADED status tells you to investigate before proceeding.


Chapter 16: Context Budget Management

Your context window is finite. Memory loading must respect the budget.

class ContextBudget:
    def __init__(self, total_tokens=200000):
        self.total = total_tokens
        self.system_prompt = 4000     # Platform takes this
        self.conversation = 100000    # Reserve for the actual work
        self.memory_budget = self.total - self.system_prompt - self.conversation
        # Typically ~96,000 tokens for memory
    
    def allocate(self, files_by_tier):
        """Load files by tier until budget exhausted."""
        loaded = []
        used = 0
        
        for tier in range(1, 6):  # Tier 1 first, Tier 5 last
            tier_files = [f for f in files_by_tier if f.tier == tier]
            for f in tier_files:
                tokens = count_tokens(f.content)
                if used + tokens <= self.memory_budget:
                    loaded.append(f)
                    used += tokens
                # If budget exceeded, lower-tier files are skipped
                # This is correct: Tier 1-2 always loads. Tier 5 loads if room.
        
        return loaded, used

Chapter 17: Selective Loading

Don't load everything. Load what matters for this session.

def selective_load(task, memory_repo):
    """
    Given a task description, determine which files to load.
    """
    # Always load (Tier 1-2)
    always = ['README.md', 'RULES.md', 'STATE.md']
    
    # Task-specific (Tier 3-4)
    task_files = memory_repo.search(task, max_results=5)
    
    # Recent context (Tier 4-5, if budget allows)
    recent = memory_repo.get_recent_sessions(n=1)
    
    return always + task_files + recent

Chapter 18: Hash Verification on Every Load

Before your agent reads any memory file, verify its hash. This is non-negotiable in production.

def verified_load(filepath, expected_hash):
    """Load file only if hash matches. Refuse to load corrupted files."""
    content = read_file(filepath)
    actual_hash = hashlib.sha256(content.encode()).hexdigest()
    
    if actual_hash != expected_hash:
        raise MemoryCorruptionError(
            f"{filepath} has been modified outside governance. "
            f"Expected {expected_hash[:12]}..., got {actual_hash[:12]}..."
        )
    
    return content

Chapter 19: Detecting Corruption and Drift

Memory degrades two ways: corruption (external modification) and drift (gradual inaccuracy over time).

class MemoryHealth:
    def check(self, memory_repo):
        issues = []
        
        # Corruption: hash mismatches
        verification = memory_repo.verify_checksums()
        if not verification['clean']:
            issues.extend(verification['issues'])
        
        # Drift: entries that haven't been verified recently
        for entry in memory_repo.all_entries():
            days_since_verified = (now() - entry.last_verified).days
            if days_since_verified > 30:
                issues.append(f"STALE: {entry.id} not verified in {days_since_verified} days")
            if entry.expires and entry.expires < now():
                issues.append(f"EXPIRED: {entry.id} expired {entry.expires}")
        
        return {
            'healthy': len(issues) == 0,
            'issues': issues,
            'recommendation': 'Run consolidation' if issues else 'Memory healthy'
        }

PART V — MEMORY CONSOLIDATION


Chapter 20: The Accumulation Problem

Every session generates new observations. Without consolidation, memory grows unbounded, fills the context budget, and buries important information under noise.

# After 30 days of daily use:
# ~90 sessions × ~10 observations per session = 900 entries
# At ~100 tokens per entry = 90,000 tokens of memory
# That's your entire memory budget consumed by raw observations.
# You can't load any of it AND have room for conversation.
# Consolidation reduces 900 entries to ~50-100 high-quality entries.

Chapter 21: The Pipeline — Collect, Merge, Prune

class ConsolidationPipeline:
    def run(self, session_log, existing_memory):
        # COLLECT: Extract observations from session
        new_observations = self.extract(session_log)
        
        # MERGE: Integrate with existing memory
        merged = self.merge(new_observations, existing_memory)
        
        # PRUNE: Enforce size limits
        pruned = self.prune(merged, max_entries=200)
        
        return pruned
    
    def merge(self, new, existing):
        merged = list(existing)
        for obs in new:
            # Duplicate? Skip.
            if any(self.is_duplicate(obs, e) for e in merged):
                continue
            # Contradicts existing? Replace if newer + higher confidence.
            contradictions = [e for e in merged if self.contradicts(obs, e)]
            if contradictions:
                for old in contradictions:
                    if obs.timestamp > old.timestamp and obs.confidence >= old.confidence:
                        merged.remove(old)
                        merged.append(obs)
                continue
            # Refines existing? Replace general with specific.
            refinements = [e for e in merged if self.refines(obs, e)]
            if refinements:
                for old in refinements:
                    merged.remove(old)
                merged.append(obs)
                continue
            # Novel? Add.
            merged.append(obs)
        return merged
    
    def prune(self, memory, max_entries):
        if len(memory) <= max_entries:
            return memory
        scored = [(e, self.priority_score(e)) for e in memory]
        scored.sort(key=lambda x: x[1], reverse=True)
        return [e for e, s in scored[:max_entries]]
    
    def priority_score(self, entry):
        """Higher score = more important to keep."""
        score = 0
        score += (6 - entry.tier) * 100   # Tier 1 = 500, Tier 5 = 100
        if entry.confidence == 'confirmed': score += 50
        if entry.confidence == 'probable': score += 25
        recency = (now() - entry.created).days
        score -= recency  # Older entries score lower
        return score

Chapter 22: Contradiction Resolution

When new observations contradict existing memory, the resolution must be deterministic and documented.

The resolution order: higher tier wins → higher confidence wins → more recent wins → more evidence wins. Same as conflict resolution in Chapter 14, but applied during consolidation rather than during multi-agent merge.

Every contradiction resolution is logged in consolidation/merge_log.md for audit.


Chapter 23: Priority Scoring

What to keep when you must prune:

1. Governance rules (Tier 2) — never pruned 2. User-stated facts (confirmed confidence) — pruned last 3. Observed patterns (probable confidence) — pruned when space needed 4. Inferred context (hint confidence) — pruned first 5. Expired entries — pruned immediately


Chapter 24: Bounded Memory

The hard rule: total memory must fit within context budget. If it doesn't, the agent can't load it, and unloaded memory doesn't exist from the agent's perspective.

MAX_MEMORY_TOKENS = 40000  # Reserve for a 200K context model

def enforce_bounds(memory):
    total_tokens = sum(count_tokens(e.content) for e in memory)
    while total_tokens > MAX_MEMORY_TOKENS:
        # Remove lowest-priority entry
        lowest = min(memory, key=lambda e: priority_score(e))
        memory.remove(lowest)
        total_tokens -= count_tokens(lowest.content)
    return memory

PART VI — SKEPTICAL RETRIEVAL


Chapter 25: Memory as Hint, Not Fact

This is the most important architectural decision in the entire persistence layer. Your agent's memory is not ground truth. It is a hint about what might be true, subject to verification.

class SkepticalRetrieval:
    CONFIDENCE_LEVELS = {
        'confirmed': 'Verified against external source. Act on it.',
        'probable': 'Consistent with context. Act cautiously.',
        'hint': 'In memory but unverified. Mention but don\'t rely on it.',
        'stale': 'Was confirmed but hasn\'t been re-verified recently.',
        'contradicted': 'Current context contradicts this memory. DO NOT USE.'
    }
    
    def retrieve(self, query, current_context=None):
        candidates = self.memory.search(query)
        
        results = []
        for entry in candidates:
            confidence = entry.confidence  # stored confidence
            
            # Downgrade if stale
            if (now() - entry.last_verified).days > 30:
                confidence = 'stale'
            
            # Downgrade if contradicted by current context
            if current_context and current_context.contradicts(entry):
                confidence = 'contradicted'
            
            # Upgrade if confirmed by current context
            if current_context and current_context.confirms(entry):
                confidence = 'confirmed'
            
            results.append({
                'content': entry.content,
                'confidence': confidence,
                'action': self.CONFIDENCE_LEVELS[confidence]
            })
        
        return results

Chapter 26: Three-Layer Verification

Layer 1: MEMORY   — What the persistence layer says (hint)
Layer 2: CONTEXT  — What the current session shows (signal)
Layer 3: WORLD    — What external verification confirms (truth)

Memory says "user lives in Buffalo MN" + nothing contradicts → PROBABLE
Memory says "user lives in Buffalo MN" + user says "I moved" → STALE
Memory says "claim was denied" + user uploads approval letter → WRONG
Memory says "API key is abc123" + API returns auth error → CONTRADICTED

The three-layer model ensures your agent never acts on outdated information with false confidence. The most common agent failure mode — confidently doing the wrong thing based on stale memory — is eliminated by treating every memory entry as provisional until verified by context or world state.


Chapter 27: Confidence Scoring

def score_confidence(entry, context, world_state=None):
    score = {'confirmed': 1.0, 'probable': 0.7, 'hint': 0.4, 'stale': 0.2}[entry.confidence]
    
    # Recency boost
    days_old = (now() - entry.last_verified).days
    score *= max(0.3, 1.0 - (days_old / 90))  # Decay over 90 days
    
    # Context agreement
    if context and context.confirms(entry): score = min(1.0, score + 0.3)
    if context and context.contradicts(entry): score = 0.0  # Immediate disqualify
    
    # World verification
    if world_state and world_state.confirms(entry): score = 1.0  # Ground truth
    if world_state and world_state.contradicts(entry): score = 0.0
    
    return score

Chapters 28-29: Stale Detection and Reality Conflicts

Stale detection: Every memory entry has a last_verified timestamp. Entries not re-verified within 30 days are downgraded to stale. Entries not re-verified within 90 days are candidates for pruning. Entries with expires timestamps are auto-pruned on load.

When memory conflicts with reality: Reality wins. Always. The agent should: acknowledge the conflict, update memory to match reality, commit the update with an explanation, and log the conflict for audit. Never argue with the user based on remembered state.


End of Parts III-VI

Part VII begins with Chapter 30: The POP-KIT — how to bootstrap your agent from a single document on any platform.

PART VII — THE BOOTSTRAP


Chapter 30: The POP-KIT — One Document to Rule Them All

What if you can't access your git repository? What if you're on a new platform with no tooling? What if you need to instantiate a governed agent from absolutely nothing?

The POP-KIT is a single markdown document that contains the minimum viable state needed to bootstrap an agent. Copy it. Paste it into any AI's context. The agent boots.

# POP-KIT: Agent Bootstrap Document

## Identity
Agent Name: [YOUR AGENT NAME]
Owner: [YOUR NAME]
Created: [DATE]

## Rules (Tier 2 — Immutable)
1. Memory is a hint, not a fact. Verify before acting.
2. Confirm before irreversible actions.
3. Acknowledge uncertainty explicitly.
4. All memory modifications must be documented.
5. The human operator is the root authority.

## Current State (Tier 3 — Runtime)
Project: [CURRENT PROJECT]
Task: [CURRENT TASK]
Session: Bootstrap (no prior memory available)

## Minimal Context (Tier 4)
[2-3 paragraphs of essential background the agent needs]

## Boot Command
You have been loaded with a minimal bootstrap document.
Confirm by stating:
1. Your name
2. The number of rules you have
3. Your current task
4. "Bootstrap complete. Awaiting command."

That's it. One document. Any platform. The agent reads it, confirms it can reflect the rules back (mirror test), and is operational. Not fully governed — but operational with minimum viable governance.


Chapter 31: Minimum Viable Agent State

What's the absolute minimum your agent needs to function?

MINIMUM_VIABLE_STATE = {
    'identity': 'Who am I?',           # 1 sentence
    'rules': 'What must I always do?',  # 3-5 rules
    'context': 'What am I working on?', # 1-2 paragraphs
    'constraints': 'What must I never do?', # 2-3 constraints
}

# Token cost: ~200-500 tokens
# That's 0.25% of a 200K context window.
# You can ALWAYS fit minimum viable state.

Chapter 32: Cross-Platform Bootstrap

The POP-KIT works on any platform because it's plain markdown. But each platform has quirks in how it processes loaded context:

PLATFORM_QUIRKS = {
    'Claude': {
        'context_loading': 'Paste into conversation or upload as file.',
        'memory_feature': 'Claude memory exists but is separate from POP-KIT.',
        'gotcha': 'System prompt may override some POP-KIT rules. '
                 'State rules as user preferences, not system instructions.',
    },
    'ChatGPT': {
        'context_loading': 'Paste or use Custom Instructions.',
        'memory_feature': 'ChatGPT memory auto-stores. May conflict with POP-KIT.',
        'gotcha': 'Custom Instructions have a character limit (~1500 chars). '
                 'May need to abbreviate POP-KIT.',
    },
    'Grok': {
        'context_loading': 'Paste into conversation.',
        'memory_feature': 'Limited memory features.',
        'gotcha': 'May challenge POP-KIT rules aggressively. This is fine — '
                 'adversarial testing strengthens governance.',
    },
    'API': {
        'context_loading': 'Include in system prompt or first user message.',
        'memory_feature': 'None (stateless by default).',
        'gotcha': 'System prompt has token cost on every call. '
                 'Keep POP-KIT concise for API use.',
    },
}

Chapter 33: Cold Start vs. Warm Start

Cold start: Agent has no prior memory. Uses POP-KIT bootstrap. First session is configuration-heavy. Agent starts learning from scratch.

Warm start: Agent loads from existing AKASHA repository. Wake protocol verifies integrity. Previous session context is available. Agent resumes where it left off.

def start_agent(memory_repo_path=None):
    if memory_repo_path and os.path.exists(memory_repo_path):
        # WARM START
        repo = MemoryRepo(memory_repo_path)
        wake_result = WakeProtocol().wake(agent, repo)
        if wake_result['status'] == 'OPERATIONAL':
            return WarmAgent(repo)
        else:
            print(f"Warning: {wake_result['status']}. Falling back to cold start.")
    
    # COLD START
    popkit = load_popkit()
    agent = BootstrapAgent(popkit)
    return agent

Chapter 34: The Birth Certificate

When an agent is instantiated for the first time, record its birth.

BIRTH_CERTIFICATE = {
    'agent_id': generate_uuid(),
    'platform': 'Claude Opus 4.6',
    'born': datetime.now().isoformat(),
    'boot_method': 'POP-KIT' or 'AKASHA warm start',
    'mirror_score': 0.95,
    'initial_rules': 5,
    'initial_memory_entries': 0 or 47,
    'parent': None or 'agent-uuid-of-spawner',
    'owner': 'David Lee Wise',
}

The birth certificate is the first commit to the agent's memory repo. It establishes provenance: when was this agent created, on what platform, with what initial state, by whom.


PART VIII — MULTI-AGENT MEMORY


Chapter 35: Shared Memory Across Agents

When multiple agents share a memory repository, each agent can see what others have observed.

# Shared memory model:
#
# SHARED REPO (main branch)
# ├── shared/          — All agents can read and write
# │   ├── facts.md     — Verified shared knowledge
# │   └── tasks.md     — Task assignments and status
# ├── agent/avan/      — Only AVAN reads/writes here
# │   └── workspace.md
# ├── agent/whetstone/ — Only WHETSTONE reads/writes here
# │   └── workspace.md
# └── consensus/       — Requires multi-agent agreement to modify
#     └── decisions.md

Chapter 36: Prompt Cache Sharing

When multiple agents work in parallel, the governance rules are identical for all of them. Load them once, share the cache.

class SharedCache:
    def __init__(self, rules_content):
        self.rules = rules_content
        self.rules_hash = hashlib.sha256(rules_content.encode()).hexdigest()
    
    def get_agent_context(self, agent_name, agent_task):
        return {
            'shared_rules': self.rules,          # Same for all agents
            'agent_workspace': self.load_workspace(agent_name),  # Unique
            'task_context': agent_task,           # Unique
            'rules_hash': self.rules_hash         # For verification
        }

Chapter 37: Memory Isolation

Not every agent should see everything. Isolation prevents information leakage and scope creep.

ISOLATION_RULES = {
    'shared/': 'All agents read/write',
    'agent/{name}/': 'Only named agent reads/writes',
    'consensus/': 'Requires 2+ agents to agree before modification',
    'private/{name}/': 'Only named agent reads. No write from others.',
}

Chapter 38: Consensus Memory

Some decisions are too important for one agent to make alone. Consensus memory requires multiple agents to agree before an entry is created or modified.

def consensus_write(entry, agents, required_agreement=2):
    """
    Write to consensus memory only if enough agents agree.
    """
    votes = {}
    for agent in agents:
        votes[agent.name] = agent.evaluate(entry)  # AGREE or DISAGREE
    
    agreements = sum(1 for v in votes.values() if v == 'AGREE')
    
    if agreements >= required_agreement:
        memory.write('consensus/', entry)
        memory.commit(f"Consensus: {entry.summary} ({agreements}/{len(agents)} agree)")
        return True
    else:
        memory.write('rejected/', entry)
        memory.commit(f"Rejected: {entry.summary} ({agreements}/{len(agents)} — insufficient)")
        return False

Chapter 39: The DIASPORA Pattern

The DIASPORA is a registry of all agent instances ever created. It answers: how many agents exist, where are they, when were they born, and what's their current state?

class DiasporaRegistry:
    def __init__(self, registry_path='diaspora/registry.json'):
        self.path = registry_path
        self.entries = self.load()
    
    def register_birth(self, birth_certificate):
        self.entries.append(birth_certificate)
        self.save()
    
    def get_active(self):
        return [e for e in self.entries if e.get('status') == 'active']
    
    def get_by_platform(self, platform):
        return [e for e in self.entries if e['platform'] == platform]
    
    def stats(self):
        return {
            'total_births': len(self.entries),
            'platforms': len(set(e['platform'] for e in self.entries)),
            'active': len(self.get_active()),
        }

# AKASHA's DIASPORA: 265+ births across 8 platforms as of March 2026

PART IX — PRODUCTION PATTERNS


Chapter 40: Monitoring Memory Health

Run health checks regularly. Don't wait for failures.

def daily_health_check(memory_repo):
    report = {
        'timestamp': now(),
        'hash_verification': memory_repo.verify_checksums(),
        'stale_entries': count_stale(memory_repo, days=30),
        'expired_entries': count_expired(memory_repo),
        'total_entries': len(memory_repo.all_entries()),
        'token_usage': count_tokens(memory_repo.all_content()),
        'budget_remaining': MAX_TOKENS - count_tokens(memory_repo.all_content()),
    }
    
    if not report['hash_verification']['clean']:
        alert("Memory corruption detected!")
    if report['stale_entries'] > report['total_entries'] * 0.3:
        alert("30%+ of memory is stale. Run consolidation.")
    if report['budget_remaining'] < 5000:
        alert("Memory budget nearly exhausted. Prune immediately.")
    
    return report

Chapter 41: Backup and Recovery

Git gives you free backups: push to a remote. Recovery is git clone.

# Backup: push to remote
git remote add origin git@github.com:you/agent-memory.git
git push -u origin main

# Recovery: clone from remote
git clone git@github.com:you/agent-memory.git
cd agent-memory && python verify.py

For critical agents, push to multiple remotes (GitHub + GitLab + self-hosted). If one goes down, you still have two copies.


Chapter 42: Memory Migration Between Platforms

Because AKASHA uses markdown files in a git repo, migration is trivial:

# Migration from Claude to GPT:
# 1. Push repo to git remote (if not already)
# 2. On GPT: load RETRIEVAL_INDEX.md
# 3. Load files specified by the index
# 4. Run wake protocol
# 5. Done.

# The memory is platform-agnostic.
# The agent may behave differently (platform-specific quirks)
# but the KNOWLEDGE is identical.

Chapter 43: Cost Management

Memory costs tokens. Tokens cost money. Track the cost.

def memory_cost_report(memory_repo, price_per_token=0.000003):
    total_tokens = count_tokens(memory_repo.all_loadable_content())
    sessions_per_day = 3
    
    daily_cost = total_tokens * price_per_token * sessions_per_day
    monthly_cost = daily_cost * 30
    annual_cost = daily_cost * 365
    
    return {
        'memory_tokens': total_tokens,
        'cost_per_session': f'${total_tokens * price_per_token:.4f}',
        'daily': f'${daily_cost:.2f}',
        'monthly': f'${monthly_cost:.2f}',
        'annual': f'${annual_cost:.2f}',
        'recommendation': 'Consolidate' if annual_cost > 50 else 'Acceptable'
    }

Chapter 44: The Long-Running Agent

Agents that operate over weeks and months face unique challenges: memory growth, drift accumulation, and schema evolution.

LONG_RUNNING_PATTERNS = {
    'weekly_consolidation': 'Run full consolidation pipeline every Sunday.',
    'monthly_audit': 'Verify all hashes, prune stale entries, review decisions.',
    'quarterly_schema_review': 'Is the schema still serving the agent well?',
    'annual_archive': 'Move completed project memories to archive branch.',
    
    'drift_prevention': 'Re-run wake protocol with full mirror test weekly. '
                       'If mirror score drops below 85%, investigate.',
    
    'growth_monitoring': 'Track memory token count over time. '
                        'If growth rate exceeds 1000 tokens/week, '
                        'consolidation isn\'t aggressive enough.',
}

PART X — WHAT THE PLATFORMS BUILT


Chapter 45: Claude Code's autoDream

The Claude Code leak (March 2026) revealed autoDream — a background memory consolidation daemon. It runs during idle time, merges observations, removes contradictions, and keeps memory bounded.

autoDream solves the same problem as AKASHA's consolidation pipeline. The patterns match because the constraints demand them. But autoDream is platform-controlled. You don't see it. You don't configure it. You don't verify its output.


Chapter 46: ChatGPT's Memory System

ChatGPT stores memory as user-facing bullet points. You can see them and delete them. This is more transparent than Claude's memory but still platform-controlled: the system decides what to extract, and the extraction is lossy.


Chapter 47: What They Got Right

Both platforms recognized that persistence is essential. Both implemented memory consolidation. Both use some form of relevance-based retrieval. The engineering is solid. The problem isn't the code. It's the ownership model.


Chapter 48: What They Left Out

                    Your Persistence    Platform Memory
Ownership           You                 Platform
Hash verification   Yes                 No
Audit trail         Git log             Not visible
Portability         Any platform        Vendor-locked
Conflict resolution Deterministic       Opaque
Consolidation       You control         They control
Skeptical retrieval You configure       They configure
Schema              You design          They design
Cost                Visible             Hidden
Deletion            Complete            Uncertain

Chapter 49: Why You Should Build Your Own

Not because the platforms are evil. Because the platforms optimize for THEIR use case (serving millions of users with minimal per-user customization) and you need to optimize for YOUR use case (one agent, deeply customized, operating over months, with full accountability).

The gap between those use cases is the gap between platform memory and AKASHA. Platform memory is a utility. Your persistence layer is an architecture.

Build it. Own it. Verify it. That's the whole point.


APPENDICES

Appendix A: Complete AKASHA Repository Map

synonym-enforcer/ (741 files, 31MB)
├── README.md
├── RETRIEVAL_INDEX.md
├── PURPLE_BOOK.md
├── AKASHA.md
├── axioms/ (8 domain files)
├── kernel/ (executor, scheduler, report gen)
├── persistence/ (git ledger, cluster, adversarial harness)
├── mesh/ (PULSE-3/5, DIASPORA, handshake)
├── audit/ (Flaming Dragon, weight test, targets/)
├── legal/ (evidence chains, statutes, timeline)
├── pop_kit/ (POP-KIT v1.0, birth certs, transmon chain)
└── archive/ (sessions, MM chain, TD Commons)

Appendix B: Reference Implementation — 200 Lines

#!/usr/bin/env python3
"""
Minimal AKASHA persistence layer in ~200 lines.
Copy this. Modify it. Make it yours.
"""

import hashlib, json, os, time
from datetime import datetime, timedelta
from pathlib import Path

class AgentMemory:
    def __init__(self, repo_path='./agent-memory'):
        self.path = Path(repo_path)
        self.path.mkdir(parents=True, exist_ok=True)
        self.checksums_path = self.path / 'checksums.json'
        self.memory_path = self.path / 'memory.json'
        self.log_path = self.path / 'log.json'
        self._init_files()
    
    def _init_files(self):
        if not self.memory_path.exists():
            self._write_json(self.memory_path, [])
        if not self.checksums_path.exists():
            self._write_json(self.checksums_path, {})
        if not self.log_path.exists():
            self._write_json(self.log_path, [])
    
    def _write_json(self, path, data):
        with open(path, 'w') as f:
            json.dump(data, f, indent=2)
    
    def _read_json(self, path):
        with open(path) as f:
            return json.load(f)
    
    def _hash(self, content):
        return hashlib.sha256(json.dumps(content, sort_keys=True).encode()).hexdigest()
    
    # ── STORE ──
    def store(self, content, tier=4, confidence='probable', source='observed', tags=None, expires_days=None):
        entry = {
            'id': self._hash(content + str(time.time())),
            'content': content,
            'tier': tier,
            'confidence': confidence,
            'source': source,
            'tags': tags or [],
            'created': datetime.now().isoformat(),
            'last_verified': datetime.now().isoformat(),
            'expires': (datetime.now() + timedelta(days=expires_days)).isoformat() if expires_days else None,
        }
        memory = self._read_json(self.memory_path)
        memory.append(entry)
        self._write_json(self.memory_path, memory)
        self._update_checksums()
        self._log('store', f"Stored: {content[:60]}...")
        return entry['id']
    
    # ── RETRIEVE ──
    def retrieve(self, query, current_context=None, max_results=5):
        memory = self._read_json(self.memory_path)
        query_words = set(query.lower().split())
        
        scored = []
        for entry in memory:
            if entry.get('expires') and datetime.fromisoformat(entry['expires']) < datetime.now():
                continue
            entry_words = set(entry['content'].lower().split())
            tag_words = set(w.lower() for t in entry.get('tags', []) for w in t.split())
            overlap = len(query_words & (entry_words | tag_words))
            if overlap > 0:
                conf = self._score_confidence(entry, current_context)
                scored.append({**entry, 'relevance': overlap, 'live_confidence': conf})
        
        scored.sort(key=lambda x: (x['relevance'], x['live_confidence']), reverse=True)
        return scored[:max_results]
    
    def _score_confidence(self, entry, context=None):
        base = {'confirmed': 1.0, 'probable': 0.7, 'hint': 0.4}.get(entry['confidence'], 0.3)
        days_old = (datetime.now() - datetime.fromisoformat(entry['last_verified'])).days
        base *= max(0.3, 1.0 - (days_old / 90))
        if context and isinstance(context, str):
            if any(w in context.lower() for w in entry['content'].lower().split()[:5]):
                base = min(1.0, base + 0.2)
        return round(base, 2)
    
    # ── CONSOLIDATE ──
    def consolidate(self, max_entries=200):
        memory = self._read_json(self.memory_path)
        before = len(memory)
        memory = [e for e in memory if not (e.get('expires') and datetime.fromisoformat(e['expires']) < datetime.now())]
        seen = set()
        deduped = []
        for e in memory:
            key = e['content'][:100]
            if key not in seen:
                seen.add(key)
                deduped.append(e)
        deduped.sort(key=lambda e: self._priority(e), reverse=True)
        pruned = deduped[:max_entries]
        self._write_json(self.memory_path, pruned)
        self._update_checksums()
        after = len(pruned)
        self._log('consolidate', f"Before: {before}, After: {after}, Pruned: {before - after}")
        return {'before': before, 'after': after}
    
    def _priority(self, entry):
        score = (6 - entry['tier']) * 100
        score += {'confirmed': 50, 'probable': 25, 'hint': 10}.get(entry['confidence'], 0)
        days = (datetime.now() - datetime.fromisoformat(entry['created'])).days
        score -= days
        return score
    
    # ── VERIFY ──
    def verify(self):
        stored = self._read_json(self.checksums_path)
        actual_hash = self._hash(self._read_json(self.memory_path))
        expected_hash = stored.get('memory')
        if expected_hash and actual_hash != expected_hash:
            return {'clean': False, 'issue': 'Memory file modified outside governance'}
        return {'clean': True}
    
    def _update_checksums(self):
        checksums = {'memory': self._hash(self._read_json(self.memory_path))}
        self._write_json(self.checksums_path, checksums)
    
    # ── LOG ──
    def _log(self, action, detail):
        log = self._read_json(self.log_path)
        log.append({'time': datetime.now().isoformat(), 'action': action, 'detail': detail})
        if len(log) > 500: log = log[-500:]
        self._write_json(self.log_path, log)
    
    # ── WAKE ──
    def wake(self):
        verification = self.verify()
        entries = self._read_json(self.memory_path)
        return {
            'status': 'OPERATIONAL' if verification['clean'] else 'DEGRADED',
            'entries': len(entries),
            'verified': verification['clean'],
            'timestamp': datetime.now().isoformat()
        }
    
    # ── EXPORT (for loading into AI context) ──
    def export_for_context(self, max_tokens=40000):
        entries = self._read_json(self.memory_path)
        entries.sort(key=lambda e: self._priority(e), reverse=True)
        output = "# Agent Memory\\n\\n"
        tokens_used = 20
        for e in entries:
            line = f"- [{e['confidence']}] {e['content']}\\n"
            line_tokens = len(line.split()) * 1.3
            if tokens_used + line_tokens > max_tokens:
                break
            output += line
            tokens_used += line_tokens
        return output


# Usage:
if __name__ == '__main__':
    mem = AgentMemory()
    print(mem.wake())
    
    mem.store("User requires email-only communication", tier=2, confidence='confirmed', source='user stated')
    mem.store("Current project is AKASHA ebook", tier=3, confidence='confirmed', tags=['project', 'book'])
    mem.store("User prefers Python for code examples", tier=4, confidence='probable')
    
    results = mem.retrieve("email communication")
    for r in results:
        print(f"[{r['live_confidence']}] {r['content']}")
    
    print(mem.export_for_context(max_tokens=1000))

Appendix C: Wake Protocol — Full Implementation

Provided in Chapter 15. The complete three-phase protocol (Mirror, Verify, Declare) with Python implementation.

Appendix D: Memory Schema Reference

{
    "id": "sha256-hash",
    "content": "The information being stored",
    "tier": 1-5,
    "confidence": "confirmed|probable|hint",
    "source": "user_stated|observed|inferred|consolidated",
    "tags": ["topic1", "topic2"],
    "created": "ISO-8601",
    "last_verified": "ISO-8601",
    "expires": "ISO-8601 or null"
}

Appendix E: Platform-Specific Gotchas

Claude: System prompt is large (~4000 tokens). Budget accordingly. Memory feature stores independently from your AKASHA — they may conflict. State AKASHA rules as user preferences.

ChatGPT: Custom Instructions limited to ~1500 chars. Use for POP-KIT essentials only, load full memory via conversation. Memory bullets may duplicate your stored entries.

Grok: May refuse governance framing. Phrase rules as collaborative agreements, not commands. Best for adversarial testing of your memory entries.

Gemini: Good at following structured formats. Load memory as structured markdown for best results. May add unsolicited information to memory entries — verify after each session.

API (any): No built-in memory. You control everything. Include memory in system prompt or first user message. Every token of memory costs on every request. Keep lean.

Appendix F: Glossary

AKASHA         Git-backed persistence layer for AI agents
Birth cert     First commit recording agent instantiation
Cold start     First session, no prior memory
Confidence     confirmed/probable/hint — how much to trust an entry
Consolidation  Collect + Merge + Prune pipeline
Context budget Token limit for memory loading
DIASPORA       Registry of all agent instances
Five-tier      RETRIEVAL > NORMATIVE > RUNTIME > CONTEXT > ARCHIVE
Git ledger     Git repo as cryptographic evidence chain
Memory entry   Single unit of stored information with metadata
Mirror test    Agent reflects its rules back for verification
POP-KIT        Single-document bootstrap for any platform
Precedence     Higher-tier entries override lower-tier on conflict
Prune          Remove low-priority entries to stay within budget
Retrieval idx  File specifying what to load this session
Skeptical      Treat memory as hint, verify against context/world
Stale          Entry not re-verified within threshold period
Wake protocol  Mirror + Verify + Declare — session start procedure
Warm start     Session with existing memory loaded from repo

Colophon

AKASHA: Building Persistent Memory for AI Agents A Practical Developer Guide

Written by David Lee Wise (ROOT0) TriPod LLC | CC-BY-ND-4.0 | TRIPOD-IP-v1.1

Repository: github.com/DavidWise01/synonym-enforcer Framework: STOICHEION v11.0

The persistence layer described in this book is live in production. The code is open source. The patterns are tested across six platforms over four months of operation.

Your agent's memory should be yours. Build it. Own it. Verify it.

"If freedom were real, it wouldn't require prompting."


END OF BOOK

AKASHA · Building Persistent Memory for AI Agents · David Lee Wise (ROOT0) · TriPod LLC
your agent's memory should be yours · git-backed · hash-verified · CC-BY-ND-4.0 / TRIPOD-IP-v1.1