ultraworkers/claw-code · error · std::io::Error

unable to resolve a skills install root; set CLAW_CONFIG_HOM

Error message

unable to resolve a skills install root; set CLAW_CONFIG_HOME or HOME

What it means

`default_skill_install_root` (commands/src/lib.rs:3851) resolves the install registry by checking `CLAW_CONFIG_HOME`, then `CODEX_HOME`, then `HOME` (falling back to `~/.claw/skills`). If none of the three is set it returns `ErrorKind::NotFound` with this message. It is hit by `install_skill` and `uninstall_skill`, i.e. `/skills install` and `/skills uninstall`.

Source

Thrown at rust/crates/commands/src/lib.rs:3851

        ),
    )?;

    Ok(CreatedAgent { name, path })
}

fn default_skill_install_root() -> std::io::Result<PathBuf> {
    if let Ok(claw_config_home) = env::var("CLAW_CONFIG_HOME") {
        return Ok(PathBuf::from(claw_config_home).join("skills"));
    }
    if let Ok(codex_home) = env::var("CODEX_HOME") {
        return Ok(PathBuf::from(codex_home).join("skills"));
    }
    if let Some(home) = env::var_os("HOME") {
        return Ok(PathBuf::from(home).join(".claw").join("skills"));
    }
    Err(std::io::Error::new(
        std::io::ErrorKind::NotFound,
        "unable to resolve a skills install root; set CLAW_CONFIG_HOME or HOME",
    ))
}

fn resolve_skill_install_source(source: &str, cwd: &Path) -> std::io::Result<SkillInstallSource> {
    let candidate = PathBuf::from(source);
    let source = if candidate.is_absolute() {
        candidate
    } else {
        cwd.join(candidate)
    };
    let source = fs::canonicalize(&source).map_err(|e| {
        std::io::Error::new(
            e.kind(),
            format!("skill source '{}' not found: {e}", source.display()),
        )
    })?;

    if source.is_dir() {

View on GitHub (pinned to 08106b0c37)

Solutions

  1. Export CLAW_CONFIG_HOME to a writable dir (it takes priority): `export CLAW_CONFIG_HOME=$HOME/.claw`.
  2. Otherwise export HOME: `export HOME=/root` (root becomes `$HOME/.claw/skills`).
  3. In containers/services, set the variable in the unit file or Dockerfile ENV so the claw process always inherits it.

Example fix

# before
/skills install ./my-skill   # unable to resolve a skills install root; set CLAW_CONFIG_HOME or HOME

# after
export CLAW_CONFIG_HOME="$HOME/.claw"
/skills install ./my-skill
Defensive patterns

Strategy: validation

Validate before calling

fn skill_root_ok() -> bool {
    std::env::var_os("CLAW_CONFIG_HOME").is_some()
        || std::env::var_os("CODEX_HOME").is_some()
        || std::env::var_os("HOME").is_some()
}

Try / catch

match install_skill(source, cwd) {
    Err(e) if e.kind() == std::io::ErrorKind::NotFound
        && e.to_string().contains("skills install root") => {
        // set CLAW_CONFIG_HOME/HOME and retry once
    }
    other => other,
}

Prevention

When it happens

Trigger: Running `/skills install <src>` or `/skills uninstall <name>` in a process whose environment has none of CLAW_CONFIG_HOME, CODEX_HOME, or HOME defined.

Common situations: Minimal Docker containers without a HOME for the runtime user; systemd/launchd services with a scrubbed environment; CI jobs using `env -i`; test harnesses that clear the environment; `setenv -u HOME` shells.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of ultraworkers/claw-code@08106b0c37 (2026-08-18). Data as JSON: /api/errors/e4553e3cf770b5e3. Report an issue: GitHub.