The User Model lives at ~/.claude/LIFEOS/USER/PRINCIPAL/PRINCIPAL_IDENTITY.md (in a standard install LIFEOS/USER is a symlink to ~/.config/LIFEOS/USER, which may be its own private git repo) as markdown with the lifeos-freshness-v1 frontmatter (LIFEOS/DOCUMENTATION/Freshness/FreshnessSystem.md):
last_updated: ISO-8601 # every write, any author
last_updated_by: <author>
convention: lifeos-freshness-v1
last_reviewed: ISO-8601 # principal review only; drives the staleness grade (90-day window for this file)
last_reviewed_by: <principal>
The Interview skill's ContextCheckin intent is the only flow that bumps last_reviewed; this skill's intents read the file on demand when it is viewed or edited.
The same frontmatter also holds the header facts that code reads, so a change to one of these is a change to the YAML key, never to prose:
| Key |
Reader |
core (name, pronunciation, timezone) |
getPrincipal() in hooks/lib/identity.ts, as the fallback only: LIFEOS/USER/CONFIG/LIFEOS_CONFIG.toml [principal] wins for name, pronunciation and timezone |
voice_clone |
the model, through the header-mirror block (no code reader) |
preferences |
getPrincipalPreferences() in hooks/lib/identity.ts |
tech_stack |
getTechStack() in hooks/lib/identity.ts, its only source |
LIFEOS/TOOLS/HeaderMirror.ts copies these keys into a generated block in the body, because @-import strips frontmatter; DerivedSync.ts runs it on every hand edit.
The blank template (Intents/Edit.md § Output format) starts the file with four sections: Quick Reference, Worldview, Work Patterns & Communication, and Preferences. Users add their own sections over time, and the memory curation loop may keep an auto-append Memory-System Proposals queue at the bottom. Edit changes the sections that exist in the user's file; it does not impose the template's schema on it. First-time setup, a worked example and a read-only proof: Setup.md.