Skip to content

hook_augment PreToolUse augmenter is a structural no-op on Windows (POSIX-only path guards) #618

Description

@catsmonster

Summary

codebase-memory-mcp hook-augment (the non-blocking Claude Code PreToolUse Grep/Glob augmenter) is a structural no-op on Windows. It runs, inits, and exits 0 with no additionalContext for every input, because the path guards in src/cli/hook_augment.c require POSIX-style /-prefixed absolute paths, which a Windows drive-letter cwd (C:\... / C:/...) can never satisfy.

Net effect: on Windows the Grep/Glob graph augmentation never fires, even for an exactly-indexed symbol. (The "never block a tool" guarantee is intact — it just never contributes anything.)

  • Version: codebase-memory-mcp 0.8.1
  • Platform: Windows (x64)
  • Install channel: install.ps1
  • Binary variant: standard

What happened, and what did you expect?

Expected: running a Grep on an indexed symbol fires the PreToolUse hook and injects matching graph symbols as additionalContext.

Actual: hook-augment emits 0 bytes of stdout for any Grep/Glob payload on Windows; no context is ever added.

Reproduction

Platform-level, no proprietary code needed — reproduces with any indexed project on Windows.

  1. On Windows, index any repo (e.g. a clone of a public repo) so it appears in list_projects with a root_path like C:/Users/me/proj.

  2. Invoke the augmenter exactly as the installed PreToolUse hook does, with a realistic Claude Code payload:

    echo '{"hook_event_name":"PreToolUse","tool_name":"Grep","cwd":"C:/Users/me/proj","tool_input":{"pattern":"someIndexedSymbol"}}' \
      | codebase-memory-mcp hook-augment
    
  3. Result: empty stdout (no hookSpecificOutput). Expected: a {"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"[codebase-memory] N graph symbol(s) match ..."}} payload.

search_graph for the same project/token returns correct hits, confirming the index and project name are fine — only hook-augment's path handling fails.

Root cause

src/cli/hook_augment.c — two POSIX-only guards:

  1. cbm_cmd_hook_augment, the _WIN32 branch (~L330):

    if (!cwd || cwd[0] != '/') {   // Windows cwd starts with a drive letter → always true → bail
        ...
        return 0;
    }

    A Windows absolute path (C:\... or C:/...) never has cwd[0] == '/', so this returns early on every invocation. This alone makes the hook a guaranteed no-op on Windows.

  2. ha_resolve_and_query walk-up loop (~L254):

    for (int level = 0; level < HA_MAX_WALKUP && dir[0] == '/'; level++) {

    The loop only iterates while the path starts with /, and the parent-climb terminator (slash == dir, ~L277) assumes a /-root. So even if guard Windows support: CGO/tree-sitter build fails — WSL2 workaround included #1 were relaxed, a C:/... path would never enter the loop / would mis-terminate.

cbm_project_name_from_path (src/pipeline/fqn.c) already handles Windows paths correctly (it produced the indexed project name from the C:\... root), so the project-name derivation is not the problem — only these /-prefix assumptions are.

The _WIN32 branch comment already acknowledges the walk-up loop "requires POSIX-style absolute paths" and chooses to bail — i.e. this is effectively unfinished Windows support for the augmenter rather than a subtle regression.

Proposed fix

Teach both guards about Windows drive roots and normalize \/:

/* absolute = POSIX "/..." OR Windows drive "X:/..." */
static bool ha_is_abs(const char *d) {
    if (!d || !d[0]) return false;
    if (d[0] == '/') return true;
    return isalpha((unsigned char)d[0]) && d[1] == ':' && (d[2] == '/' || d[2] == '\0');
}
  • Guard 1: normalize cwd backslashes to /, then if (!ha_is_abs(cwd)) return 0;
  • Guard 2: loop while ha_is_abs(dir); stop the parent-climb at the drive root (X:) as well as the POSIX root.

Happy to open a PR with this (I'll mark it build-unverified for Windows CI to confirm, since I don't have the full C toolchain locally).

Related

Fits under the Windows umbrella tracker #394 (not currently listed there). Distinct from #513 (stdio hang), #548 (UI drive selection), and #409 (install wiring the legacy gate).

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable steps (platform-level, any public repo), not proprietary code.

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