Skip to content

install/update ignore $CLAUDE_CONFIG_DIR; writes always go to ~/.claude #320

@halindrome

Description

@halindrome

Summary

codebase-memory-mcp install and codebase-memory-mcp update ignore the CLAUDE_CONFIG_DIR environment variable and unconditionally write Claude Code skills, MCP entries, hook scripts, and settings.json under $HOME/.claude/.

Users who keep their Claude Code config under a non-default location (e.g. CLAUDE_CONFIG_DIR=$HOME/.config/claude-code, the location Claude Code itself uses on macOS when configured that way) end up with:

  1. A new ~/.claude/ tree silently created by the installer.
  2. Their real Claude Code config dir untouched — so the skills/MCP entry/hooks the installer claims it wrote are not visible to Claude Code at runtime.
  3. cbm_detect_agents() checking $HOME/.claude (not CLAUDE_CONFIG_DIR) and reporting Claude Code as "detected" or "not detected" based on the wrong path.

This was first observed during a 0.6.0 → 0.6.1 upgrade.

Reproduce

export CLAUDE_CONFIG_DIR="$HOME/.config/claude-code"
mkdir -p "$CLAUDE_CONFIG_DIR"

codebase-memory-mcp install -y

# Expected: writes under $CLAUDE_CONFIG_DIR
# Actual:   writes under $HOME/.claude
ls -la ~/.claude/skills          # populated (wrong)
ls -la "$CLAUDE_CONFIG_DIR/skills"   # empty / missing (should be populated)

Affected paths

All hardcoded in src/cli/cli.c:

Line Path written Function
cli.c:981 ${HOME}/.claude cbm_detect_agents (detection)
cli.c:1466 ~/.claude/hooks/cbm-code-discovery-gate CMM_HOOK_COMMAND macro
cli.c:1650 ${HOME}/.claude/hooks cbm_install_hook_gate_script
cli.c:1687,1694 ~/.claude/hooks/... session-reminder hook
cli.c:2629 ${HOME}/.claude/skills install_claude_code_config
cli.c:2640 ${HOME}/.claude/.mcp.json install MCP
cli.c:2654 ${HOME}/.claude/settings.json install hooks
cli.c:2949..2967 same paths uninstall_claude_code

Same bug at the shell layer: scripts/setup.sh:212,218, scripts/security-install.sh:124.

Note: hooks installed into ~/.claude/hooks/ already read CLAUDE_CONFIG_DIR correctly at runtime — only the install/uninstall path ignores it.

Proposal

Add a small helper:

static void cbm_claude_config_dir(const char *home, char *out, size_t out_sz) {
    const char *env = getenv("CLAUDE_CONFIG_DIR");
    if (env && env[0]) {
        snprintf(out, out_sz, "%s", env);
    } else {
        snprintf(out, out_sz, "%s/.claude", home);
    }
}

…and route every "%s/.claude..." install/uninstall write through it. Replace CMM_HOOK_COMMAND / CMM_SESSION_COMMAND macro literals with strings composed at install time so settings.json records the actual hook path.

Bundle a one-line stderr migration hint: when the resolved dir differs from $HOME/.claude and a stale ~/.claude install is detected, list legacy artifacts so users can remove them. Bundling this with the fix avoids a two-release rollout where users upgrade, find their config silently moved, and have no nudge to clean up the old tree.

Mirror the change in scripts/setup.sh and scripts/security-install.sh (CLAUDE_HOME="${CLAUDE_CONFIG_DIR:-$HOME/.claude}").

Add a smoke-test case (scripts/smoke-test.sh) asserting that with CLAUDE_CONFIG_DIR set the artifacts land there, not in $FAKE_HOME/.claude.

Out of scope

  • Adding a project-local --scope=project install flag (separate feature gap, future work).
  • The Phase-07 plan in some downstream forks targeting a Go installer — that installer is no longer the install path; only the C install subcommand is in use.

Environment

  • macOS, codebase-memory-mcp 0.6.1
  • CLAUDE_CONFIG_DIR=$HOME/.config/claude-code (Claude Code's own configured location)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions