Summary
Three independent parser bugs in PAI/TOOLS/GenerateTelosSummary.ts cause the auto-generated PRINCIPAL_TELOS.md (loaded into the DA's context at every session start via CLAUDE.md @-import) to silently miss most of the user's TELOS data.
The DA boots without seeing the user's missions, active goals, narratives, challenges, or formative experiences — even when those source files are fully populated.
Bug 1 — parseItems() only matches bullet form; standard PAI source files use header form
File: PAI/TOOLS/GenerateTelosSummary.ts, function parseItems (lines 47-59)
Symptom: Generated PRINCIPAL_TELOS.md has empty ## Missions, ## Active Goals (2026), ## Active Narratives, ## Personal Challenges, and ## Core Models sections — even when MISSION.md, GOALS.md, NARRATIVES.md, CHALLENGES.md, and MODELS.md are fully populated.
Root cause: parseItems matches only this single regex:
const match = line.match(/^-\s+\*?\*?(\w+)\*?\*?:\s*(.+)/);
That matches bullet form: - **M0**: Family Presence. But the canonical PAI source files (after a real /interview run, after /migrate, or after the user fills them in by hand) use header form:
### M0: Family Presence
Be fully present for family — attend every kids' event...
parseItems returns zero items for these files, so all five callers (parseMissions, parseGoals, parseNarratives, parseChallenges, parseModels) yield empty arrays. Note: parseProblems and parseStrategies already handle the header form correctly via their own regex — parseItems is the inconsistent one.
Proposed fix: Extend parseItems to try header form when bullet form misses:
function parseItems(content: string): ParsedItem[] {
const items: ParsedItem[] = [];
for (const line of content.split('\n')) {
// Bullet: "- **M0**: text"
const bullet = line.match(/^-\s+\*?\*?(\w+)\*?\*?:\s*(.+)/);
if (bullet) {
items.push({ id: bullet[1], text: bullet[2].trim() });
continue;
}
// Header: "## M0: text" / "### G0: text" / "#### MO0: text"
const header = line.match(/^#{2,4}\s+([A-Z]+\d+):\s*(.+?)(?:\s*\(.*\))?\s*$/);
if (header) {
items.push({ id: header[1], text: header[2].trim() });
}
}
return items;
}
Bug 2 — Hardcoded {{PRINCIPAL_FULL_NAME}} placeholder in generated output
File: PAI/TOOLS/GenerateTelosSummary.ts, line 220
Symptom: Generated PRINCIPAL_TELOS.md starts with the literal string:
# Principal TELOS — {{PRINCIPAL_FULL_NAME}}
The {{PRINCIPAL_FULL_NAME}} token is never substituted because there is no substitution mechanism in this generator (it's a write, not a render). Different problem from #1135 (which is about the installer not substituting in PAI_SYSTEM_PROMPT.md); this is a generator that hardcodes a placeholder it can't resolve.
Proposed fix: Read the principal name from settings.json daidentity (or PRINCIPAL_IDENTITY.md frontmatter) at generation time:
import { readFileSync } from 'fs';
const settings = JSON.parse(readFileSync(join(process.env.HOME!, '.claude/settings.json'), 'utf-8'));
const principalName = settings.principal?.fullName || settings.principal?.name || 'Principal';
// then:
'# Principal TELOS — ' + principalName,
Or accept it as an environment variable / config injection.
Bug 3 — parseTraumas() requires ID-prefixed items but the bootstrap TRAUMAS.md uses plain titles
File: PAI/TOOLS/GenerateTelosSummary.ts, function parseTraumas (lines 189-193)
Symptom: Generated ## Formative Experiences (Traumas) section is empty even when TRAUMAS.md is fully populated.
Root cause: parseTraumas calls parseItems (which expects TR0, TR1, etc. prefixed items), but the canonical/bootstrap TRAUMAS.md uses plain titled headers:
## Major Transformations
### Religious Worldview Shift
**Age:** ~28 (after 7-year marriage)
**What happened:** ...
### Divorce
...
No TR# prefix, so parseItems returns zero, and the section in the generated summary is empty.
Proposed fix: Fall back to extracting ### Title headers and assigning synthetic TR0..TRn IDs:
function parseTraumas(): string[] {
const content = readTelosFile('TRAUMAS.md');
if (!content) return [];
// Try ID-prefixed format first
const items = parseItems(content);
if (items.length > 0) {
return items.map(i => `- **${i.id}**: ${truncate(i.text, 90)}`);
}
// Fallback: ### Title headers, assign synthetic TR0..TRn
const headers = [...content.matchAll(/^###\s+(.+?)\s*$/gm)];
return headers.map((m, i) => `- **TR${i}**: ${truncate(m[1].trim(), 90)}`);
}
Reproduce
# Use the bootstrap-default TRAUMAS.md and populate MISSION.md / GOALS.md with `### M0: Title` form
bun ~/.claude/PAI/TOOLS/GenerateTelosSummary.ts
cat ~/.claude/PAI/USER/TELOS/PRINCIPAL_TELOS.md
# Expect: Missions, Goals, Narratives, Challenges, Formative Experiences sections all empty
# Expect: header reads "# Principal TELOS — {{PRINCIPAL_FULL_NAME}}"
After applying the three patches above:
# Principal TELOS — <user's actual name>
## Missions
- **M0**: Family Presence
- **M1**: Financial Independence
...
## Formative Experiences (Traumas)
- **TR0**: Religious Worldview Shift
- **TR1**: Divorce
...
Impact
PRINCIPAL_TELOS.md is @-imported into the DA's system context on every session start (per CLAUDE.md). When these bugs fire, the DA boots blind to the user's missions, goals, narratives, challenges, and formative experiences — the entire point of the TELOS system. Users may not realize until they ask the DA something like "what's my current mission?" and get an unsteered answer.
Environment
Related
Summary
Three independent parser bugs in
PAI/TOOLS/GenerateTelosSummary.tscause the auto-generatedPRINCIPAL_TELOS.md(loaded into the DA's context at every session start viaCLAUDE.md@-import) to silently miss most of the user's TELOS data.The DA boots without seeing the user's missions, active goals, narratives, challenges, or formative experiences — even when those source files are fully populated.
Bug 1 —
parseItems()only matches bullet form; standard PAI source files use header formFile:
PAI/TOOLS/GenerateTelosSummary.ts, functionparseItems(lines 47-59)Symptom: Generated
PRINCIPAL_TELOS.mdhas empty## Missions,## Active Goals (2026),## Active Narratives,## Personal Challenges, and## Core Modelssections — even whenMISSION.md,GOALS.md,NARRATIVES.md,CHALLENGES.md, andMODELS.mdare fully populated.Root cause:
parseItemsmatches only this single regex:That matches bullet form:
- **M0**: Family Presence. But the canonical PAI source files (after a real/interviewrun, after/migrate, or after the user fills them in by hand) use header form:### M0: Family Presence Be fully present for family — attend every kids' event...parseItemsreturns zero items for these files, so all five callers (parseMissions,parseGoals,parseNarratives,parseChallenges,parseModels) yield empty arrays. Note:parseProblemsandparseStrategiesalready handle the header form correctly via their own regex —parseItemsis the inconsistent one.Proposed fix: Extend
parseItemsto try header form when bullet form misses:Bug 2 — Hardcoded
{{PRINCIPAL_FULL_NAME}}placeholder in generated outputFile:
PAI/TOOLS/GenerateTelosSummary.ts, line 220Symptom: Generated
PRINCIPAL_TELOS.mdstarts with the literal string:The
{{PRINCIPAL_FULL_NAME}}token is never substituted because there is no substitution mechanism in this generator (it's a write, not a render). Different problem from #1135 (which is about the installer not substituting inPAI_SYSTEM_PROMPT.md); this is a generator that hardcodes a placeholder it can't resolve.Proposed fix: Read the principal name from
settings.json daidentity(orPRINCIPAL_IDENTITY.mdfrontmatter) at generation time:Or accept it as an environment variable / config injection.
Bug 3 —
parseTraumas()requires ID-prefixed items but the bootstrapTRAUMAS.mduses plain titlesFile:
PAI/TOOLS/GenerateTelosSummary.ts, functionparseTraumas(lines 189-193)Symptom: Generated
## Formative Experiences (Traumas)section is empty even whenTRAUMAS.mdis fully populated.Root cause:
parseTraumascallsparseItems(which expectsTR0,TR1, etc. prefixed items), but the canonical/bootstrapTRAUMAS.mduses plain titled headers:No
TR#prefix, soparseItemsreturns zero, and the section in the generated summary is empty.Proposed fix: Fall back to extracting
### Titleheaders and assigning syntheticTR0..TRnIDs:Reproduce
After applying the three patches above:
Impact
PRINCIPAL_TELOS.mdis@-imported into the DA's system context on every session start (perCLAUDE.md). When these bugs fire, the DA boots blind to the user's missions, goals, narratives, challenges, and formative experiences — the entire point of the TELOS system. Users may not realize until they ask the DA something like "what's my current mission?" and get an unsteered answer.Environment
Related
{{PLACEHOLDER}}literal that never gets resolved) but in a different file (PAI_SYSTEM_PROMPT.md) and from a different mechanism (installer skipping the file). Both fixes should land together as a "no literal{{}}tokens in shipped/generated PAI files" hygiene rule.