Windows install of v7.1.1 is unlaunchable: Core launcher depends on the optional hooks tree, and process.env.HOME is undefined on Windows
Environment
|
|
| LifeOS |
v7.1.1 (installed via install.sh) |
| OS |
Windows 11 Pro 10.0.22631 |
| Harness |
Claude Code |
| bun |
1.3.14 (Windows x64) |
| git |
2.55.0.windows.3 |
| Config root |
C:\Users\<user>\.claude |
Install path followed: install.sh bootstrap → the Workflows/Setup.md steps (DetectEnv, ScanConflicts, InstallSettings, DeployCore, ScaffoldUser, LinkUser, ActivateImports, DeployComponents). LifeOS Core deployed cleanly — 52 skills, 532 runtime files, identity @-imports all resolving. The two bugs below then made the installed system impossible to launch.
Bug 1 — The Core launcher imports from the Enhancement-tier hooks tree
Workflows/Setup.md presents hooks as à la carte: step 7 says the user picks "some, all, or none", and hooks are deployed only by Tools/InstallHooks.ts. But the launch command is Core (step 8.5, and INSTALL.md step 7), and LIFEOS/TOOLS/lifeos.ts:22 does:
import { getIdentity, getStartupCatchphrase } from "../../hooks/lib/identity";
Tools/DeployCore.ts deploys install/skills/ and install/LIFEOS/ but never install/hooks/. So declining hooks — a documented, supported choice — leaves <configRoot>/hooks/ absent and the launcher dead.
Reproduce
- Install v7.1.1.
- At the step 7 enhancements menu, decline
hooks.
- Run
lifeos.
error: Cannot find module '../../hooks/lib/identity' from 'C:\Users\<user>\.claude\LIFEOS\TOOLS\lifeos.ts'
This is platform-independent — declining hooks on macOS or Linux should break the launcher identically.
Notes
The dependency is genuinely narrow: lifeos.ts needs only identity from hooks/lib, and identity.ts in turn needs only LIFEOS/TOOLS/LifeosConfig (Core) and yaml (already in the deployed package.json). None of the other 23 files in hooks/lib/ are required.
Suggested fixes
- Move
identity.ts into LIFEOS/TOOLS/ — it is a shared identity loader, not hook logic; or
- have
DeployCore.ts deploy install/hooks/lib/ as a Core library (this registers nothing in settings.json and executes no hooks, so it does not violate the opt-in model); or
- make the import lazy with a graceful fallback to the default identity when the hooks tree is absent.
Bug 2 — process.env.HOME is undefined on Windows (206 occurrences, 119 files)
Windows does not define HOME; it defines USERPROFILE. hooks/lib/identity.ts:18-19:
const HOME = process.env.HOME!;
const SETTINGS_PATH = join(HOME, '.claude/settings.json');
The non-null assertion (!) suppresses this at compile time, so it surfaces only at runtime, as a confusing error that names paths[0] rather than HOME.
Reproduce
On Windows, run any LIFEOS tool (after working around Bug 1):
TypeError: The "paths[0]" property must be of type string, got undefined
code: "ERR_INVALID_ARG_TYPE"
at C:\Users\<user>\.claude\hooks\lib\identity.ts:19:23
Scope
process.env.HOME appears 206 times across 119 files under LIFEOS/, including LIFEOS/TOOLS/ (Doctor.ts, Banner.ts, LifeosConfig.ts, GenerateTelosSummary.ts, MemoryRetriever.ts, …) and most of LIFEOS/PULSE/. So this is not one bad line — the Windows install is broadly affected.
Notably, lifeos.ts itself already does the right thing on line 24:
import { homedir } from "os";
const CLAUDE_DIR = join(homedir(), ".claude");
so the codebase is internally inconsistent about this.
Suggested fix
Prefer homedir() from node:os, which is correct on every platform. Where an env var must be read, use process.env.HOME ?? process.env.USERPROFILE. Dropping the ! assertions would let the type checker surface the remaining cases.
Workaround
Defining HOME in the environment resolves the whole class at once, and with it the launcher, Banner.ts, and Doctor.ts all run correctly:
- PowerShell launch function:
$env:HOME = $env:USERPROFILE
- Claude Code sessions:
"HOME": "C:\\Users\\<user>" in the env block of settings.json
Minor — LinkUser cannot succeed when the config root is the harness tree
Tools/LinkUser.ts tries to symlink the USER tree into the harness tree, but on this layout both resolve to the same path, so it attempts USER → USER:
{
"ok": false,
"action": "linked",
"error": "symlink creation failed (live USER preserved at ...USER.pre-link-backup-<ts>): EEXIST: file already exists, symlink 'C:\\Users\\<user>\\.claude\\LIFEOS\\USER' -> 'C:\\Users\\<user>\\.claude\\LIFEOS\\USER'",
"contract": { "passed": false, "detail": "USER is not a symlink (system/user separation broken)" }
}
Practically harmless — a real LIFEOS/USER/ directory is exactly what the @LIFEOS/USER/... imports need, and they resolve fine. But it reports ok: false and a failed contract, which reads as a broken install, and it leaves behind a full duplicate of the 95-file USER tree in USER.pre-link-backup-<ts>. Suggest detecting src === dst and treating it as a satisfied no-op.
Minor — install.sh fallback tag points at a nonexistent release
install.sh sets LIFEOS_FALLBACK_TAG="v7.11.0", but no such release exists; the newest published release is v7.1.1. The fallback is unreachable in the normal path (the releases/latest redirect resolves correctly), so this is latent — but it is precisely the path taken when GitHub is rate-limited, which is the scenario the surrounding comment says was already a real incident on 2026-07-12. As stamped, that recovery path would fetch a 404 tarball.
Windows install of v7.1.1 is unlaunchable: Core launcher depends on the optional hooks tree, and
process.env.HOMEis undefined on WindowsEnvironment
install.sh)C:\Users\<user>\.claudeInstall path followed:
install.shbootstrap → theWorkflows/Setup.mdsteps (DetectEnv,ScanConflicts,InstallSettings,DeployCore,ScaffoldUser,LinkUser,ActivateImports,DeployComponents). LifeOS Core deployed cleanly — 52 skills, 532 runtime files, identity@-imports all resolving. The two bugs below then made the installed system impossible to launch.Bug 1 — The Core launcher imports from the Enhancement-tier hooks tree
Workflows/Setup.mdpresents hooks as à la carte: step 7 says the user picks "some, all, or none", and hooks are deployed only byTools/InstallHooks.ts. But the launch command is Core (step 8.5, andINSTALL.mdstep 7), andLIFEOS/TOOLS/lifeos.ts:22does:Tools/DeployCore.tsdeploysinstall/skills/andinstall/LIFEOS/but neverinstall/hooks/. So declining hooks — a documented, supported choice — leaves<configRoot>/hooks/absent and the launcher dead.Reproduce
hooks.lifeos.This is platform-independent — declining hooks on macOS or Linux should break the launcher identically.
Notes
The dependency is genuinely narrow:
lifeos.tsneeds onlyidentityfromhooks/lib, andidentity.tsin turn needs onlyLIFEOS/TOOLS/LifeosConfig(Core) andyaml(already in the deployedpackage.json). None of the other 23 files inhooks/lib/are required.Suggested fixes
identity.tsintoLIFEOS/TOOLS/— it is a shared identity loader, not hook logic; orDeployCore.tsdeployinstall/hooks/lib/as a Core library (this registers nothing insettings.jsonand executes no hooks, so it does not violate the opt-in model); orBug 2 —
process.env.HOMEis undefined on Windows (206 occurrences, 119 files)Windows does not define
HOME; it definesUSERPROFILE.hooks/lib/identity.ts:18-19:The non-null assertion (
!) suppresses this at compile time, so it surfaces only at runtime, as a confusing error that namespaths[0]rather thanHOME.Reproduce
On Windows, run any LIFEOS tool (after working around Bug 1):
Scope
process.env.HOMEappears 206 times across 119 files underLIFEOS/, includingLIFEOS/TOOLS/(Doctor.ts,Banner.ts,LifeosConfig.ts,GenerateTelosSummary.ts,MemoryRetriever.ts, …) and most ofLIFEOS/PULSE/. So this is not one bad line — the Windows install is broadly affected.Notably,
lifeos.tsitself already does the right thing on line 24:so the codebase is internally inconsistent about this.
Suggested fix
Prefer
homedir()fromnode:os, which is correct on every platform. Where an env var must be read, useprocess.env.HOME ?? process.env.USERPROFILE. Dropping the!assertions would let the type checker surface the remaining cases.Workaround
Defining
HOMEin the environment resolves the whole class at once, and with it the launcher,Banner.ts, andDoctor.tsall run correctly:$env:HOME = $env:USERPROFILE"HOME": "C:\\Users\\<user>"in theenvblock ofsettings.jsonMinor —
LinkUsercannot succeed when the config root is the harness treeTools/LinkUser.tstries to symlink the USER tree into the harness tree, but on this layout both resolve to the same path, so it attemptsUSER → USER:{ "ok": false, "action": "linked", "error": "symlink creation failed (live USER preserved at ...USER.pre-link-backup-<ts>): EEXIST: file already exists, symlink 'C:\\Users\\<user>\\.claude\\LIFEOS\\USER' -> 'C:\\Users\\<user>\\.claude\\LIFEOS\\USER'", "contract": { "passed": false, "detail": "USER is not a symlink (system/user separation broken)" } }Practically harmless — a real
LIFEOS/USER/directory is exactly what the@LIFEOS/USER/...imports need, and they resolve fine. But it reportsok: falseand a failed contract, which reads as a broken install, and it leaves behind a full duplicate of the 95-file USER tree inUSER.pre-link-backup-<ts>. Suggest detectingsrc === dstand treating it as a satisfied no-op.Minor —
install.shfallback tag points at a nonexistent releaseinstall.shsetsLIFEOS_FALLBACK_TAG="v7.11.0", but no such release exists; the newest published release isv7.1.1. The fallback is unreachable in the normal path (thereleases/latestredirect resolves correctly), so this is latent — but it is precisely the path taken when GitHub is rate-limited, which is the scenario the surrounding comment says was already a real incident on 2026-07-12. As stamped, that recovery path would fetch a 404 tarball.