Summary
ConfigRenderer family (#1204, #1135, #1143 — telegram surface). LIFEOS/TOOLS/MemoryReviewer.ts embeds REVIEWER_SYSTEM_PROMPT and builds its user prompt with literal {{DA_NAME}} / {{PRINCIPAL_NAME}} template variables. Nothing ever renders them (no ConfigRenderer exists in v6), so the memory curator's inference prompt goes out verbatim as:
You are {{DA_NAME}}'s Memory Reviewer — a background process that reads recent
conversation between {{PRINCIPAL_NAME}} and {{DA_NAME}} ...
Confirmed in the persisted run artifacts: MEMORY/OBSERVABILITY/reviewer-runs/<runId>/prompt.system.md and prompt.user.md (conversation turns are labeled {{PRINCIPAL_NAME}}: ... / {{DA_NAME}}: ...).
The values exist in settings.json (daidentity.name, principal.name) but are never injected. Impact: the curator of the hot-layer memory — which is loaded into every turn — operates without knowing either name, degrading extraction quality (e.g., it can't reliably attribute facts to the right actor).
Separate cosmetic nit in the same file: the JSON schema examples hardcode the upstream author's names as Actor enum wire tokens ("daniel" | "kai").
Environment
Ubuntu 24.04, LifeOS v6.0.0.
Fix suggestion (verified locally)
Render at prompt-build time from settings, with neutral fallbacks:
function loadIdentityNames(): { da: string; principal: string } {
try {
const raw = JSON.parse(readFileSync(pathJoin(CLAUDE_ROOT, "settings.json"), "utf8"));
return {
da: raw?.daidentity?.name?.trim() || "the DA",
principal: raw?.principal?.name?.trim() || "the principal",
};
} catch { return { da: "the DA", principal: "the principal" }; }
}
function renderIdentity(template: string): string {
const n = loadIdentityNames();
return template.replaceAll("{{DA_NAME}}", n.da).replaceAll("{{PRINCIPAL_NAME}}", n.principal);
}
Wire tokens "daniel"/"kai" left untouched (they are Actor enum values that MemoryTypes.resolveStoragePath maps to the two memory files, not display names — the rendered prompt explains the token↔name mapping).
Worth a wider audit: any other runtime prompt carrying these placeholders shares the same gap (grep -rn '{{DA_NAME}}' --include='*.ts' across TOOLS/PULSE/hooks). Happy to send a PR.
Summary
ConfigRenderer family (#1204, #1135, #1143 — telegram surface).
LIFEOS/TOOLS/MemoryReviewer.tsembedsREVIEWER_SYSTEM_PROMPTand builds its user prompt with literal{{DA_NAME}}/{{PRINCIPAL_NAME}}template variables. Nothing ever renders them (no ConfigRenderer exists in v6), so the memory curator's inference prompt goes out verbatim as:Confirmed in the persisted run artifacts:
MEMORY/OBSERVABILITY/reviewer-runs/<runId>/prompt.system.mdandprompt.user.md(conversation turns are labeled{{PRINCIPAL_NAME}}: .../{{DA_NAME}}: ...).The values exist in
settings.json(daidentity.name,principal.name) but are never injected. Impact: the curator of the hot-layer memory — which is loaded into every turn — operates without knowing either name, degrading extraction quality (e.g., it can't reliably attribute facts to the right actor).Separate cosmetic nit in the same file: the JSON schema examples hardcode the upstream author's names as Actor enum wire tokens (
"daniel" | "kai").Environment
Ubuntu 24.04, LifeOS v6.0.0.
Fix suggestion (verified locally)
Render at prompt-build time from settings, with neutral fallbacks:
Wire tokens
"daniel"/"kai"left untouched (they areActorenum values thatMemoryTypes.resolveStoragePathmaps to the two memory files, not display names — the rendered prompt explains the token↔name mapping).Worth a wider audit: any other runtime prompt carrying these placeholders shares the same gap (
grep -rn '{{DA_NAME}}' --include='*.ts'across TOOLS/PULSE/hooks). Happy to send a PR.