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_pathrecords 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.
- Idempotence — dry-run / run / re-run yield the same row count
- Chunk-row match — H2 section count equals curated count
- Traceability — unique
source_pathvalues match the file count - features-sync integrity — existing entries in the memcore wiki remain unchanged (no drift)
- Wiki reflection — feature document sections stay synced with curated state
- 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.yamlv2.0 — hybrid rules + deprecated sectionscripts/persona-ingest.py— idempotent ingest implementationdocs/operations/features/persona-loader.md— feature specdocs/operations/persona-loader-verification-2026-04-21.md— six-axis verification report
Series overview: Series index
๋๊ธ
๋๊ธ ์ฐ๊ธฐ