Skip to content

[Bug]: ctx_index refuses directory paths, blocking project-wide indexing on all 4 tested clients #687

@matiasduartee

Description

@matiasduartee

Platform

Claude Code

context-mode version

1.0.148

Debug script output (REQUIRED)

{
  "context_mode": {
    "version": "1.0.148",
    "binary_path": "C:\\Users\\<user>\\AppData\\Roaming\\npm\\node_modules\\context-mode\\",
    "available_commands": ["doctor", "upgrade", "hook", "statusline"]
  },
  "runtime": {
    "node": "v25.9.0",
    "bun": "1.3.14",
    "npm": "11.12.1",
    "perl": "v5.38.2",
    "python": "3.14.4",
    "shell": "GNU bash 5.2.37 (Git Bash msys)"
  },
  "os": {
    "platform": "Windows 11 Pro",
    "version": "10.0.26200",
    "arch": "x64"
  },
  "doctor_output": {
    "platform_detection": "Claude Code (high confidence)",
    "storage_sessions": "C:\\Users\\<user>\\.claude\\context-mode\\sessions",
    "storage_content": "C:\\Users\\<user>\\.claude\\context-mode\\content",
    "storage_stats": "C:\\Users\\<user>\\.claude\\context-mode\\sessions",
    "performance": "FAST (Bun detected)",
    "language_coverage": "5/11 (45%) — javascript, shell, typescript, python, perl",
    "server_test": "PASS",
    "hooks_configured": ["PreToolUse", "SessionStart"],
    "hook_scripts_pass": ["pretooluse", "posttooluse", "precompact", "sessionstart", "userpromptsubmit"],
    "plugin_cache_integrity": "PASS",
    "plugin_enabled": "PASS — context-mode@context-mode",
    "hook_config_portability": "PASS — .github/hooks/context-mode.json (no hard-coded paths)",
    "fts5_sqlite": "PASS"
  }
}

Exact prompt that triggered the bug (REQUIRED)

Run ctx_index on the project root directory:

ctx_index(path: "<project-root>")

Then verify the same behavior on any other absolute directory path
(e.g. "C:\\Users\\me\\repo" or "/home/user/project").

Full error output (REQUIRED)

Tool: ctx_index
Input: { "path": "<project-root>" }
Output: Index error: refusing to index d:\Desenvolvimento\Agent_Kit: not a regular file

Reproduced verbatim on FOUR independent client/model combinations
running v1.0.148 with Bun 1.3.14 on the same Windows 11 host:

┌────────────────────────────────────┬──────────────────────────────────────────────────────────────────┐
│ Client                             │ Result                                                           │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Claude Code (Opus 4.7)             │ "Index error: refusing to index <project-root>:    │
│ npm global install                 │  not a regular file" — 0 files processed                         │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Codex CLI (GPT-5)                  │ Same error — 0 files processed, took 0.114s                      │
│ npm global install                 │                                                                  │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Antigravity (Gemini 3.5 Flash)     │ Same error — 0 files                                             │
│ Bundled at                         │                                                                  │
│ .gemini/antigravity-ide/mcp/       │                                                                  │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Antigravity (Gemini 3.1 Pro)       │ Same error — 0 files (~0.000s, fail instant)                     │
│ Same bundled install               │                                                                  │
└────────────────────────────────────┴──────────────────────────────────────────────────────────────────┘

No stack trace surfaces to the MCP client; the rejection happens before
any traversal logic runs. The error string ("not a regular file")
strongly suggests an `fs.statSync().isFile()` check that returns early
without attempting recursive walk.

We also re-ran the same prompts on v1.0.146 before upgrading to v1.0.148
(same 4 clients) — identical error in all 8 runs. The 1.0.146 → 1.0.148
upgrade did NOT touch this behavior.

Steps to reproduce (REQUIRED)

  1. Install / upgrade:
    npm install -g context-mode@1.0.148

  2. (Optional) Install Bun for FAST performance — reproduces with or without:
    powershell -c "irm bun.sh/install.ps1 | iex"

  3. Configure MCP in any client. Examples:

    • Claude Code: claude mcp add --transport stdio --scope user context-mode -- bun x context-mode
    • Codex CLI: [mcp_servers.context-mode]\n command = "bun"\n args = ["x","context-mode"]
    • Antigravity: ~/.gemini/config/mcp_config.json → { "mcpServers": { "context-mode": { "command": "bun", "args": ["x","context-mode"] } } }
  4. From any agent session, call:
    ctx_index(path: "")

  5. Observe error:
    Index error: refusing to index : not a regular file

  6. Confirm that a file path works (proves the bug is the dir branch, not perms):
    ctx_index(path: "/README.md") → succeeds, returns sections count

What have you tried to fix it?

  1. Verified across 4 client/model combinations on Windows 11 with both
    v1.0.146 and v1.0.148 — behavior is server-side and identical, ruling
    out client adapter issues.

  2. Inspected installed CLI surface: context-mode --help exposes only
    doctor, upgrade, hook, statusline. No index subcommand to
    bypass the MCP path. No scripts/ctx-debug.sh shipped (the script
    this issue template requests does not exist in npm install).

  3. Verified bun-mode does not change the behavior — error is byte-identical
    with and without Bun, with and without our wrapper installer.

  4. Workarounds attempted, all brittle:
    a) Have the agent shell out (Glob / find / Get-ChildItem) and loop
    ctx_index per file. This works but caps real-world value:
    across our 4 test clients, agents indexed only 0–11 individual
    files manually before giving up.
    b) Use ctx_search with array of queries — does NOT replace indexing,
    only batches search over already-indexed content.
    c) Use ctx_batch_execute — surprise gotcha: its queries parameter
    is scoped only to the batch's own output, NOT the global index
    (the tool's own tip confirms: "Results are scoped to this batch
    only. To search across all indexed sources, use ctx_search").

  5. Measured impact: cache hit rate / token savings correlate directly
    with how many files the agent successfully indexed manually:

    ┌──────────────────────┬─────────────┬──────────────┬──────────────────────┐
    │ Client (v1.0.148) │ Files mgr. │ Tokens saved │ Reduction │
    │ │ indexed │ in session │ │
    ├──────────────────────┼─────────────┼──────────────┼──────────────────────┤
    │ Antigravity (Flash) │ 11 │ 27.1K │ 88.1% │
    │ Claude Code (Opus) │ 5 │ 15.1K │ 79.8% │
    │ Codex CLI (GPT-5) │ 0 │ 8.2K │ 46.0% │
    │ Antigravity (Pro) │ 0 │ NEG (86→80%) │ regression! │
    └──────────────────────┴─────────────┴──────────────┴──────────────────────┘

    In the worst case (Antigravity Pro), querying without a real index
    actually DECREASED the cache ratio because queries consumed more
    tokens than they saved. Project-wide indexing is the missing
    feature that closes this gap.

Expected behavior:

ctx_index(path: "") should walk the directory respecting:
- a default ignore list (node_modules, .git, dist, build, .next, etc.)
- optional include / exclude glob arrays
- optional maxDepth and maxFiles to prevent runaway
- optional extensions filter (default to .md, .mjs, .js, .ts,
.py, .json, etc.)

This matches every comparable indexer (ripgrep, fd, tree-sitter
walkers, LlamaIndex SimpleDirectoryReader, etc.) and is the obvious
user expectation given the tool's name.

Proposed PR shape (happy to implement if approach is approved):

  1. In ctx_index handler, detect fs.statSync(path).isDirectory().
  2. If directory, call new indexDirectory(path, opts) that:
    • uses fs.readdir({ recursive: true }) (Node 20+) or fast-glob
    • applies default ignore + user-provided include/exclude
    • calls existing per-file index path in parallel
      (concurrency cap, e.g. 8)
    • aggregates and returns { filesIndexed, sectionsIndexed,
      durationMs, skipped, errors }.
  3. Backwards-compatible: file paths still go through the original
    code path unchanged.
  4. Tests: regular file (existing green), directory defaults,
    directory with ignore, empty directory, non-existent path, deeply
    nested directory with maxDepth.

Happy to open a PR against next branch — confirm the API shape
(opts.include / opts.exclude / opts.maxDepth / opts.maxFiles
/ opts.extensions) and I'll write it.

Pre-submission checklist

  • I have run the debug script and pasted the output above
  • I am using the latest version of context-mode
  • I have searched existing issues for duplicates
  • I have included steps to reproduce the issue

Operating System

Windows (PowerShell)

JS Runtime

Bun 1.3.14 (also reproduced with Node 25.9.0 fallback before installing Bun)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions