Find code kept alive only by tests.
A must-have for your coding agent's toolkit. AI refactors can leave old
implementations behind, kept alive by their own tests. Everything stays green.
The leftovers stay hidden. Run ghostrefs after agent-driven changes to expose
test-only code, follow the reference chains, and give your agent concrete
candidates to review and remove.
- Finds production symbols whose only known consumers are tests
- Follows transitive dependencies, including
test → helper → target - Uses language server references to build a usage graph
- Explains findings with reference locations and test chains
- Supports custom production entry points and ignore patterns
- Written in Rust, currently supports Python via Pyright
Requires Rust with Cargo and pyright-langserver in your PATH.
Install from crates.io:
npm install -g pyright
cargo install ghostrefsFrom a checkout of this repository, run against the included sample project:
ghostrefs --root . --source fixtures/python/project --tests fixtures/python/tests…/main.py:6:5 test_only_used_func (Function)
…/main.py:14:7 TestOnlyUsedClass (Class)
TestOnly candidates: 2 (6 production symbols analyzed)
For your own project, set --root to the directory matching your Python imports.
The --source and --tests paths are relative to that root.
--tests accepts one or more files, directories, or glob patterns. You can
also repeat the flag. Quote patterns so ghostrefs expands them relative to
--root, independently of your shell:
ghostrefs --root . --source src --tests tests/unit tests/integration
ghostrefs --root . --source app --tests '**/test_*.py' --tests '**/tests/**'A directory includes its entire subtree. Each path must exist and each glob must match at least one file or directory. Patterns classify whole files as tests; they do not select test functions within production files.
Try the scattered-tests fixture with either explicit paths or a glob. Both
commands report unit_only, integration_only, and colocated_only:
ghostrefs --root fixtures/python/scattered --source app \
--tests tests/unit checks/integration --tests app/test_services.py
ghostrefs --root fixtures/python/scattered --source app --tests '**/test_*.py'Collection progress is always printed to stderr. Add --verbose to see why a
symbol was flagged, or --graph to inspect the usage graph.
Add --fail-on-findings to exit with status 1 when TestOnly candidates are
found, for example in CI. A scan with no findings exits with status 0.
This flag cannot be combined with --graph.
Configure ignore patterns, production entry points, and Pyright settings in
ghostrefs-lsp.json at the project root.
Ghostrefs uses a single Pyright process and sends reference requests sequentially.
Findings are candidates for review: dynamic imports, reflection, and external consumers may be invisible to the language server.
Add .github/workflows/ghostrefs.yml to your Python project:
name: ghostrefs
on: [push, pull_request]
permissions:
contents: read
jobs:
ghostrefs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: milssky/ghostrefs@master
with:
source: app
tests: testsSee the GitHub Action guide for inputs and examples.
Start with Getting started, then explore the CLI reference, configuration, and analysis model.
See the development guide to build the searchable HTML documentation locally.