{"record":{"id":"fd5f43e0bcde2504","repo":"zeroclaw-labs/zeroclaw","slug":"neither-shell-nor-comspec-is-set","errorCode":null,"errorMessage":"neither $SHELL nor %ComSpec% is set","messagePattern":"neither \\$SHELL nor %ComSpec% is set","errorType":"console","errorClass":"DiagItem","httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-runtime/src/doctor/mod.rs","lineNumber":1731,"sourceCode":"    }\n}\n\n// ── Environment checks ───────────────────────────────────────────\n\nfn check_environment(items: &mut Vec<DiagItem>) {\n    let cat = \"environment\";\n\n    // git\n    check_command_available(\"git\", &[\"--version\"], cat, items);\n\n    // Shell — Unix uses $SHELL, Windows uses %ComSpec% (path to cmd.exe).\n    let shell = std::env::var(\"SHELL\")\n        .ok()\n        .filter(|s| !s.is_empty())\n        .or_else(|| std::env::var(\"ComSpec\").ok().filter(|s| !s.is_empty()));\n    match shell {\n        Some(s) => items.push(DiagItem::ok(cat, format!(\"shell: {s}\"))),\n        None => items.push(DiagItem::warn(cat, \"neither $SHELL nor %ComSpec% is set\")),\n    }\n\n    // HOME\n    if std::env::var(\"HOME\").is_ok() || std::env::var(\"USERPROFILE\").is_ok() {\n        items.push(DiagItem::ok(cat, \"home directory env set\"));\n    } else {\n        items.push(DiagItem::error(\n            cat,\n            \"neither $HOME nor $USERPROFILE is set\",\n        ));\n    }\n\n    // Optional tools\n    check_command_available(\"curl\", &[\"--version\"], cat, items);\n\n    if crate::service::linux_systemd_runtime_present() {\n        items.push(systemd_linger_diag_item(\n            crate::service::systemd_user_linger_status(),","sourceCodeStart":1713,"sourceCodeEnd":1749,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/doctor/mod.rs#L1713-L1749","documentation":"A `zeroclaw doctor` warning from `check_environment`: neither the Unix `SHELL` nor the Windows `ComSpec` environment variable is set to a non-empty value. ZeroClaw shells out for tool execution and version probes, and this pair is its shell discovery order; when both are missing, shell-based operations degrade. On Windows the check expects `%ComSpec%` (path to cmd.exe).","triggerScenarios":"Running `zeroclaw doctor` (or the daemon) in an environment where `SHELL` is unset — cron jobs, systemd services without a PAM session, minimal Docker images, some CI runners — and, on Windows, `ComSpec` unset.","commonSituations":"Daemon installed as a systemd user service where the unit has no shell environment; container images derived from `FROM scratch`-style minimal bases; CI pipelines that scrub env; Windows contexts with a stripped environment.","solutions":["Export a valid shell before running doctor/the daemon: `export SHELL=/bin/bash`.","For systemd units add `Environment=\"SHELL=/bin/bash\"` to the `[Service]` section.","On Windows ensure `ComSpec` points at `cmd.exe`.","Re-run `zeroclaw doctor` and confirm the `shell: ...` ok line appears."],"exampleFix":"# before (systemd unit): SHELL unset -> \"neither $SHELL nor %ComSpec% is set\"\n[Service]\nExecStart=/usr/bin/zeroclaw daemon\n\n# after\n[Service]\nEnvironment=\"SHELL=/bin/bash\"\nExecStart=/usr/bin/zeroclaw daemon","handlingStrategy":"fallback","validationCode":"let shell = std::env::var(\"SHELL\").ok().filter(|s| !s.is_empty())\n    .or_else(|| std::env::var(\"ComSpec\").ok().filter(|s| !s.is_empty()))\n    .unwrap_or_else(|| \"/bin/sh\".to_string());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set `Environment=\"SHELL=/bin/bash\"` in any systemd unit that runs zeroclaw.","In containers, `ENV SHELL=/bin/sh` so shell discovery never depends on a login session."],"tags":["environment","shell","doctor","systemd","zeroclaw"],"backgroundTag":"missing-env-var","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}