Skip to content

blast: exclude .claude/worktrees/ from graph scanning (Claude Code ghost paths) #94

@stackbilt-admin

Description

@stackbilt-admin

Summary

`@stackbilt/blast` picks up `.claude/worktrees/agent-*/` directories when scanning, which pollutes the reverse-dependency graph with ghost copies of real source files. Most visible in the `hotFiles` output, where a single canonical file like `web/src/types.ts` appears multiple times with fractional importer counts split across the worktree clones.

Context

Claude Code (the CLI agent tool) uses git worktrees under `.claude/worktrees/agent-/` for parallel agent isolation. Each worktree is a full checkout of the repo, so from a filesystem scan's perspective there can be hundreds or thousands of ghost `.ts` files that are bit-identical copies of the canonical tree. Any project using Claude Code will have these, and they grow linearly with concurrent agent sessions.

This is the same class of exclude that `@stackbilt/blast` already handles for `node_modules/`, `.git/`, `tests/`, and `.test.`.

Reproduction

From a repo that has one or more active Claude Code worktrees:

```
$ charter --version
charter v0.10.0

$ find .claude/worktrees -name '*.ts' | wc -l
886

$ charter blast web/src/kernel/router.ts --format json | jq '.hotFiles[:5]'
[
{"file": "web/src/types.ts", "importers": 65},
{"file": ".claude/worktrees/agent-a60fd4fb/web/src/types.ts", "importers": 45},
{"file": "web/src/kernel/dispatch.ts", "importers": 45},
{"file": ".claude/worktrees/agent-a60fd4fb/web/src/kernel/dispatch.ts", "importers": 31},
{"file": ".claude/worktrees/agent-a60fd4fb/web/src/kernel/memory/index.ts", "importers": 27}
]
```

`web/src/types.ts` and its worktree ghost are counted as separate nodes. The importer counts should sum together (110 instead of being split 65/45), and the second entry shouldn't exist at all.

Observed impact

  • `hotFiles` gets polluted most visibly — the top-N popularity list shows ghost duplicates
  • `affected` appears unaffected for the seed I tested (router.ts yielded zero ghost entries), but this is probably because the seed's reverse-dep walk starts from canonical paths and doesn't naturally cross into worktree trees. Other seeds might behave differently.
  • `fileCount` includes worktree files in the total scan budget, so large worktree trees inflate the total and may affect performance on big projects

Expected behavior

`charter blast` should exclude `.claude/worktrees/**` from graph construction by default, matching the existing exclusion posture for `node_modules/`, `.git/`, test fixtures, etc.

Suggested fix

In `@stackbilt/blast` (presumably in the graph builder's directory walk): add `.claude/worktrees` to the default ignore list alongside `node_modules`, `.git`, `dist`, `build`, `coverage`. A one-liner.

Optional enhancement: add `.charterignore` or a `blast.exclude` field in `.charter/config.json` for project-specific overrides, though that's scope creep for this fix.

Related

  • charter 0.10.0 first publish of `@stackbilt/blast`
  • Discovered while dogfooding `charter blast` in Stackbilt-dev/aegis after bumping the repo's `@stackbilt/cli` dep from 0.9.2 to ^0.10.0
  • Downstream consumer: `scripts/taskrunner.sh` in aegis uses `charter blast --format json` as the signal source for the self-improvement blast-radius gate. Ghost-count inflation there would make the `CC_BLAST_BLOCK` (default 50-file) threshold trip incorrectly on mid-size refactors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions