Most agents hardcode their personality and knowledge into the source code. This chapter shows a better way: keep everything in plain files on disk. Swap a file, change how the agent behaves — no code changes needed.

The Big Picture

Chapter 6 answers: how does an agent have personality, memory, and knowledge?

The answer: all from files on disk, not hardcoded.

STARTUP (once):              EVERY TURN:
═══════════════              ════════════
BootstrapLoader               User input
  SOUL.md                         │
  IDENTITY.md    ─────>     _auto_recall()
  TOOLS.md                  search memory
  MEMORY.md                       │
  AGENTS.md                       ▼
  USER.md                   build_system_prompt()
      │                      8 layers assembled
  SkillsManager                    │
    scan SKILL.md                  ▼
      │                        LLM API call
  cached every turn

The BootstrapLoader is the startup routine that reads all the files in your agent’s directory and caches them before the first turn.

Swap a file = change behavior. Zero code changes.

Four Key Concepts

1. 8-Layer System Prompt Assembly

Built every turn. Order = priority (earlier = stronger influence):

Layer 1: IDENTITY.md  → "Who you are"
Layer 2: SOUL.md      → "Your personality" (early = dominant)
Layer 3: TOOLS.md     → "How to use tools"
Layer 4: Skills       → "Available skills"
Layer 5: MEMORY.md + auto-recalled memories
Layer 6: HEARTBEAT.md, AGENTS.md, USER.md
Layer 7: Runtime      → agent_id, model, current time
Layer 8: Channel hint → "You respond via Discord/Terminal/etc"

LLMs tend to weight earlier content in the prompt more heavily. By placing personality (SOUL.md) in layer 2 — right after the agent’s name — it becomes the dominant behavioral influence for the rest of the conversation.

2. Memory — Two-Tier Storage

MEMORY.md — Evergreen facts, manually maintained and permanent. Example: “User prefers concise answers. Timezone UTC+7.”

daily/YYYY-MM-DD.jsonl — Daily logs written by the agent at runtime.

{"ts":"...", "category":"fact", "content":"..."}

The agent writes memories via a memory_write tool and searches them via memory_search.

3. Auto-Recall — Automatic Every Turn

Before every LLM call, the user’s message is searched against memory. Top 3 results are injected into Layer 5. The user doesn’t ask — it happens automatically.

memoryContext := autoRecall(userInput)   // search top-3
systemPrompt := buildSystemPrompt(memoryContext)

4. Hybrid Search Pipeline (mini-RAG)

RAG (Retrieval-Augmented Generation) means the agent retrieves relevant notes from memory and adds them to the prompt before calling the LLM. This makes it much more accurate for personal or domain-specific use.

1. Keyword (TF-IDF)    → top-10
2. Vector (hash)       → top-10
3. Merge               → 70% vector + 30% keyword
4. Temporal decay      → older memories score lower
5. De-duplicate + diversify (MMR) — avoid surfacing five memories that all say the same thing
         ↓
     top-k → inject into system prompt

This is a RAG pattern without an external vector database — pure Python. For production at scale, swap in a real vector DB (Chroma, Qdrant, Pinecone) for better accuracy.

File-Based vs External Memory

Pure File-Based External (Qdrant, etc.)
Setup Zero — works immediately Install + config
Cost Free Free self-host / paid cloud
Search quality TF-IDF + hash — good enough Embedding API — more accurate
Scale Hundreds of entries Thousands+
Privacy 100% local Depends on setup

For personal agents: file-based is fine. For enterprise with large knowledge bases, external RAG is worth the setup cost.

Takeaway

  • System prompt — files on disk, not hardcode → change files = change behavior
  • 8 layers, order = priority → SOUL at layer 2 for dominance
  • Memory: MEMORY.md (evergreen) + daily JSONL (runtime)
  • Auto-recall — inject relevant memories into every turn automatically
  • Hybrid search: TF-IDF + vector + MMR → foundation of the RAG pattern