Agent Self-Improvement Harness (1/12) — Separating Static Identity from Runtime SOUL

The Problem — Two Files with the Same Name, 47% Drift

AI agent "persona" data splits into two layers. A static identity layer that rarely changes (values, worldview, capability definitions) and a dynamic state layer updated every session (learning notes, observations, user insights). When both layers share the same file, editorial authorities compete and drift accumulates.

In one actual agent, the SOUL identity file existed in both the repo (persona/) and the runtime (hermes-data/) directories:

  • Initial template (repo, 16 KB) versus actual runtime file (24 KB, updated with mir self-edits)
  • A 47% difference between the two files
  • USER.md was worse — the repo version held a static profile, while the runtime version had accumulated §-separated insights and evolved into a completely different file

The root cause was storing two editing authorities in one path. When a manager edits manually and the agent self-edits on the same path, one side will always lag or get overwritten.

The Design — Split Paths by Editing Authority (Option C Hybrid)

The fix is to separate the two layers explicitly and give each layer exactly one authoritative path.

Static identity — repo as single source

Path Role Author
persona/ONTOLOGY.md 4-layer identity framework Manager
persona/VALUES.md Value priorities, judgment rules Manager
persona/BEING.md Temperament, worldview, non-negotiable principles Manager
persona/CAPABILITIES.md Skills / meta-skills / knowledge domains Manager
persona/LIFE_PROJECT_PLAN.md Project direction Manager

Dynamic slots — runtime as single source

Path Role Author
hermes-data/SOUL.md Runtime-injected SOUL Manager + mir self-edit
hermes-data/memories/USER.md Accumulated user insights Agent (memory tool)
hermes-data/memories/MEMORY.md Session memory Agent (memory tool)

Historical files (persona/SOUL.md, persona/USER.md) are deprecated. The persona/loader.sh script that handled copying is deprecated too, retaining only the --uninstall path.

The Implementation — Idempotent One-Way Ingest

The path from static identity to memcore (a SQLite-based curated memory) collapses into one script.

persona/*.md (repo single source)
       │
       ▼  scripts/persona-ingest.py  (manually invoked by manager)
       │
       ▼
memcore curated
  source_path = "persona/<file>.md"

Operating principles:

  • Direction: repo → memcore one-way. No back-flow.
  • Idempotence: DELETE+INSERT pattern. On re-run, prior N rows → inserted N rows, unchanged.
  • Traceability: source_path records the unique path. Reverse-traceable.
  • Chunk-row match: H2 section count in the file equals curated row count. File structure maps 1:1 to storage structure.

No automatic hook is attached. Persona changes happen a handful of times per year at most — there is no reason to ingest on every boot, and the editing cadence must be decided by the manager.

Verification — Six-Axis Checklist

File separation alone is not structural governance. Separation only matters if these six axes all pass.

  1. Idempotence — dry-run / run / re-run yield the same row count
  2. Chunk-row match — H2 section count equals curated count
  3. Traceability — unique source_path values match the file count
  4. features-sync integrity — existing entries in the memcore wiki remain unchanged (no drift)
  5. Wiki reflection — feature document sections stay synced with curated state
  6. Rollback path — uninstall script restores the historical-file setup

Without all six, "separating two files" is indistinguishable from "changing nothing structural."

The Effect — The Drift Path Itself Disappears

After separation, the paths that could produce drift are gone. Static identity flows one way from repo to memcore, and the runtime SOUL is edited directly under hermes-data/. The two paths never cross, so the question "which copy is current?" no longer exists.

Side effect: observation points also become clear. If the runtime SOUL exceeds its token budget (~8.3 K tokens against a 3 K recommendation — 2.7× over), you monitor hermes-data/ alone. The repo side's change history lives in git log. When responsibility splits, monitoring targets split with it.

Application — A Generalizable Pattern

This separation pattern generalizes to "any config file where manager edits and agent self-edits intermix."

  • System prompts + learning notes → templates/ (repo) + runtime/notes.md (runtime)
  • Tool schemas + tool usage stats → tools/schemas/ (repo) + runtime/usage-log.db (runtime)
  • Agent role definitions + role execution records → roles/ (repo) + runtime/role-history.md (runtime)

The shared rule is one sentence: never put two editing authorities on one file. When editors differ, put the files in different places, and make the flow one-directional — and drift itself stops occurring.

Conclusion

File separation looks trivial, but for structures where editing authorities were already mixed, it is a decisive shift. The cost of detecting and resolving drift disappears, and a problem on one side no longer propagates to the other. The "single source" principle is not mere documentation hygiene — it is a structural isolation mechanism. Separation only functions as real governance when paired with idempotent one-way ingest and six-axis verification.

References

  • persona/module.yaml v2.0 — hybrid rules + deprecated section
  • scripts/persona-ingest.py — idempotent ingest implementation
  • docs/operations/features/persona-loader.md — feature spec
  • docs/operations/persona-loader-verification-2026-04-21.md — six-axis verification report

Series overview: Series index

๋Œ“๊ธ€

์ด ๋ธ”๋กœ๊ทธ์˜ ์ธ๊ธฐ ๊ฒŒ์‹œ๋ฌผ

Agent Memory Engine (2/10) — Building an AI Agent Memory System with SQLite Alone

"ML Foundations (9/9) — PyTorch vs TensorFlow, and the Road to Local LLMs"

"RAG Core Study (14/26) — Evaluation Sets with RAGAS & DeepEval"

"ML Foundations (8/9) — Deep Learning Architectures: CNN, RNN, Attention"

"ML Foundations (7/9) — Deep Learning Training: Optimizers, Regularization, Initialization"

OpenClaw to Hermes Migration (2/13) — What to Preserve, Partially Port, or Discard

AI Agents I Built (5/7) — Building an Automated Blogger API Publishing System