# Specifying Custom Entry Points for Dead Code Analysis in Code-Graph-RAG

> Prevent false positives in dead code analysis with Code-Graph-RAG. Use the --entry-points flag or entry_points parameter to specify custom roots and ensure accurate results.

- Repository: [Vitali Avagyan/code-graph-rag](https://github.com/vitali87/code-graph-rag)
- Tags: how-to-guide
- Published: 2026-08-15

---

**Use the `--entry-points` flag or `entry_points` parameter in `DeadCodeConfig` to declare external call roots and prevent false-positive dead code detection.**

Code-Graph-RAG automatically traces reachability from framework entry points (module-load callees, test code, hooks). However, dynamically invoked functions—CLI wrappers, background workers, or framework dispatchers—fall outside this static graph. By **specifying custom entry points for dead code analysis in Code-Graph-RAG**, you register these external roots explicitly so legitimate code is never flagged as dead.

## How Custom Entry Points Flow Through the System

The path from user input to root detection spans three core files:

1. [`codebase_rag/cli.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/cli.py) — parses CLI flags
2. [`codebase_rag/types_defs.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/types_defs.py) — stores configuration
3. [`codebase_rag/dead_code.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/dead_code.py) — evaluates reachability

### CLI Parsing in [`cli.py`](https://github.com/vitali87/code-graph-rag/blob/main/cli.py)

The `_dead_code_config` helper in [`codebase_rag/cli.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/cli.py) (lines 1184–1200) converts the `--entry-points` arguments into a `DeadCodeConfig` instance:

```python
def _dead_code_config(..., entry_points: list[str], ...) -> DeadCodeConfig:
    return DeadCodeConfig(
        ...,
        entry_points=tuple(entry_points),          # ← custom entry points

        ...
    )

```

The CLI accepts `-e` or `--entry-points` as a repeatable option. Each value becomes one string in the tuple.

### Configuration Storage in [`types_defs.py`](https://github.com/vitali87/code-graph-rag/blob/main/types_defs.py)

The `DeadCodeConfig` dataclass in [`codebase_rag/types_defs.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/types_defs.py) (lines 75–81) declares the field:

```python
@dataclass(frozen=True)
class DeadCodeConfig:
    ...
    entry_points: tuple[str, ...] = ()

```

This immutable tuple propagates to the analysis engine.

### Root Detection in [`dead_code.py`](https://github.com/vitali87/code-graph-rag/blob/main/dead_code.py)

The `dead_code_from_graph` function in [`codebase_rag/dead_code.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/dead_code.py) (lines 690–693) performs the final root check:

```python
elif any(qn.endswith(entry) for entry in config.entry_points):
    roots.add(qn)

```

Notice the **suffix match**: `entry_points=("main",)` matches `mypkg.main`, `mypkg.sub.main`, or `other.ns.main`. This flexible matching reduces the need for fully qualified names in every case.

## Command-Line Usage

Pass `--entry-points` (or `-e`) multiple times to register each external root:

```bash
cgr dead-code --project myproj \
    --entry-points mypkg.main \
    --entry-points mypkg.utils.helper

```

Both `mypkg.main` and `mypkg.utils.helper` are treated as reachability roots. Any code reachable from them—directly or transitively—is excluded from dead code reports.

## Programmatic API Usage

For custom pipelines or CI integrations, construct `DeadCodeConfig` directly and pass it to `collect_dead_code`:

```python
from codebase_rag.types_defs import DeadCodeConfig
from codebase_rag.dead_code import collect_dead_code

cfg = DeadCodeConfig(
    include_tests=False,
    include_classes=False,
    root_decorators=frozenset(),
    entry_points=("myproj.main", "myproj.utils.helper"),
    test_patterns=(),
)

dead_rows = collect_dead_code(ingestor, "myproj", cfg)

for row in dead_rows:
    print(row["qualified_name"])

```

This pattern integrates cleanly with automated workflows where CLI invocation is impractical.

## When to Specify Custom Entry Points

Add explicit entry points when your codebase contains:

- **CLI wrappers** that launch functions via string names
- **Background workers** started by external schedulers (Celery, RQ, cron)
- **Plugin systems** with dynamic import and dispatch
- **Framework hooks** registered by decorators unknown to the static analyzer

Without these roots, Code-Graph-RAG sees no incoming calls and marks the functions dead.

## Summary

- **CLI flag**: `--entry-points` / `-e`, repeatable for multiple roots
- **Config field**: `DeadCodeConfig.entry_points` as `tuple[str, ...]`
- **Matching logic**: suffix match on qualified names in [`dead_code.py`](https://github.com/vitali87/code-graph-rag/blob/main/dead_code.py)
- **Key files**: [`cli.py`](https://github.com/vitali87/code-graph-rag/blob/main/cli.py) → [`types_defs.py`](https://github.com/vitali87/code-graph-rag/blob/main/types_defs.py) → [`dead_code.py`](https://github.com/vitali87/code-graph-rag/blob/main/dead_code.py)

## Frequently Asked Questions

### Can I use partial module paths as entry points?

Yes. The matching logic in [`dead_code.py`](https://github.com/vitali87/code-graph-rag/blob/main/dead_code.py) uses `qn.endswith(entry)`, so `main` matches any qualified name ending in `main`. For precise targeting, supply the full `package.module.name` path.

### What happens if I specify entry points that don't exist?

Unreachable symbols in `entry_points` are silently ignored. No error is raised, and they simply contribute no roots to the reachability graph.

### How do entry points interact with test detection?

`DeadCodeConfig` has separate flags: `include_tests`, `test_patterns`, and `entry_points`. Entry points are additive—tests may add their own roots via `include_tests=True`, while your custom entry points cover non-test external callers.

### Is there a limit to how many entry points I can specify?

No hard limit exists. The CLI accepts any number of `--entry-points` repetitions, and the `tuple[str, ...]` type in `DeadCodeConfig` scales with available memory. For large lists, consider generating the config programmatically rather than via CLI.