What happens
The shipped LifeOS/install/settings.system.json env block sets path variables as literal strings:
"env": {
"LIFEOS_DIR": "$HOME/.claude/LIFEOS",
"PROJECTS_DIR": "$HOME/Projects",
"LIFEOS_CONFIG_DIR": "$HOME/.claude/LIFEOS",
...
Claude Code injects settings.json env values verbatim — it never shell-expands them. Verified directly: after setup, a fresh authed session's printenv LIFEOS_CONFIG_DIR returns the literal string $HOME/.claude/LIFEOS.
On a clean Debian 13 install (Claude Code 2.1.198, bun 1.3.14), during /LifeOS setup:
ScaffoldUser wrote the 93-file USER tree into a junk directory literally named $HOME/ under the skill folder
LinkUser created a broken, self-referential symlink ~/.claude/LIFEOS/USER → $HOME/.claude/LIFEOS/USER
The setup agent caught it mid-run. From its own transcript:
"Root cause found: the env var LIFEOS_CONFIG_DIR=$HOME/.claude/LIFEOS is set to a literal, unexpanded string. The bun tools don't expand $HOME, so:
- ScaffoldUser wrote 93 files into a junk dir literally named
$HOME/ under the skill folder
- LinkUser created a broken symlink:
~/.claude/LIFEOS/USER → $HOME/.claude/LIFEOS/USER (also self-referential once expanded — it points back into configRoot, breaking the separation contract)"
It then repaired itself (moved USER into place, removed the junk tree) — genuinely impressive agentic recovery, but every fresh install is currently performing self-surgery. And the deeper issue: anything else that reads LIFEOS_CONFIG_DIR/LIFEOS_DIR from env at runtime (hooks, Pulse, TOOLS) receives the literal string and will mis-resolve unless it defensively expands.
Repro
Clean Linux box → bootstrap installer → /LifeOS setup → observe the $HOME/ junk dir under the skill folder + broken symlink. Or simply, post-setup: claude -p 'printenv LIFEOS_CONFIG_DIR'.
Scope note: a second same-day install on a machine with a full pre-existing config did NOT reproduce the junk-dir failure — USER landed correctly. The literal env value is constant (verified via printenv on both runs), but whether the TS tools mis-resolve appears environment-dependent. The clean-box repro is deterministic, so: fresh installs affected.
Prior art — this is a known class in this repo
The v6 payload reintroduces the same class in the new LIFEOS tree.
Suggested fix (either/both)
- Belt — tools resolve env paths defensively:
value.replace(/^\$HOME\b/, os.homedir()) in a shared resolvePath() used by ScaffoldUser / LinkUser / DetectEnv.
- Suspenders — InstallEngine substitutes the real home into the deployed
settings.system.json env block during the settings merge. This fixes ALL runtime consumers, not just the TS tools.
Evidence available: full setup-session transcript (JSONL) including the setup agent's own root-cause narrative, plus before/after tree listings — happy to share trimmed excerpts.
Found during day-one Linux (Debian) runtime validation of v6.
What happens
The shipped
LifeOS/install/settings.system.jsonenv block sets path variables as literal strings:Claude Code injects
settings.jsonenv values verbatim — it never shell-expands them. Verified directly: after setup, a fresh authed session'sprintenv LIFEOS_CONFIG_DIRreturns the literal string$HOME/.claude/LIFEOS.On a clean Debian 13 install (Claude Code 2.1.198, bun 1.3.14), during
/LifeOS setup:ScaffoldUserwrote the 93-file USER tree into a junk directory literally named$HOME/under the skill folderLinkUsercreated a broken, self-referential symlink~/.claude/LIFEOS/USER → $HOME/.claude/LIFEOS/USERThe setup agent caught it mid-run. From its own transcript:
It then repaired itself (moved USER into place, removed the junk tree) — genuinely impressive agentic recovery, but every fresh install is currently performing self-surgery. And the deeper issue: anything else that reads
LIFEOS_CONFIG_DIR/LIFEOS_DIRfrom env at runtime (hooks, Pulse, TOOLS) receives the literal string and will mis-resolve unless it defensively expands.Repro
Clean Linux box → bootstrap installer →
/LifeOS setup→ observe the$HOME/junk dir under the skill folder + broken symlink. Or simply, post-setup:claude -p 'printenv LIFEOS_CONFIG_DIR'.Scope note: a second same-day install on a machine with a full pre-existing config did NOT reproduce the junk-dir failure — USER landed correctly. The literal env value is constant (verified via
printenvon both runs), but whether the TS tools mis-resolve appears environment-dependent. The clean-box repro is deterministic, so: fresh installs affected.Prior art — this is a known class in this repo
${HOME}into settings.json, creating a bogus${HOME}/directorypaths.tsprecisely because "settings.json env values are not shell-expanded"The v6 payload reintroduces the same class in the new LIFEOS tree.
Suggested fix (either/both)
value.replace(/^\$HOME\b/, os.homedir())in a sharedresolvePath()used by ScaffoldUser / LinkUser / DetectEnv.settings.system.jsonenv block during the settings merge. This fixes ALL runtime consumers, not just the TS tools.Evidence available: full setup-session transcript (JSONL) including the setup agent's own root-cause narrative, plus before/after tree listings — happy to share trimmed excerpts.
Found during day-one Linux (Debian) runtime validation of v6.