> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cognee.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Code Graph

> Build a knowledge graph of a code repository with enola and query it with SearchType.CODE

A minimal guide to turning a code repository into a knowledge graph and querying it. The pipeline extracts facts such as modules, symbols, routes, storage, services, and dependencies with the external enola extractor, loads them as typed graph nodes and edges, and answers structured queries — no LLM or embedding provider involved.

## Before You Start

* Complete [Quickstart](/getting-started/quickstart) to understand basic operations
* Read [Pipelines](/core-concepts/building-blocks/pipelines) and [Tasks](/core-concepts/building-blocks/tasks) for how a custom pipeline is assembled from tasks
* Have the enola binary available: it is installed automatically on the first run (pinned release, checksum-verified, placed in `~/.cognee/bin`), or [install it yourself](https://github.com/enola-labs/enola#installation) and point `ENOLA_PATH` at it
* Set `CODE_GRAPH_REPO_PATH` to the repository you want to index — it defaults to the current working directory
* No [LLM Providers](/setup-configuration/llm-providers) or embedding configuration is required: both the pipeline and `SearchType.CODE` are deterministic

## Code in Action

```python theme={null}
import asyncio
import json
import os

import cognee
from cognee import SearchType
from cognee.shared.logging_utils import ERROR, setup_logging
from cognee.tasks.code_graph import get_code_graph_tasks


async def main():
    repo_path = os.getenv("CODE_GRAPH_REPO_PATH", os.getcwd())

    # Start clean so the example is reproducible.
    await cognee.prune.prune_data()
    await cognee.prune.prune_system(metadata=True)

    print(f"Extracting code graph from: {repo_path}")
    await cognee.run_custom_pipeline(
        # Pass index_vectors=True only if these facts should also be available
        # to semantic/LLM retrievers; SearchType.CODE does not need it.
        tasks=get_code_graph_tasks(repo_path),
        data=repo_path,
        dataset="code_graph_demo",
        pipeline_name="code_graph_pipeline",
        # This pipeline is deterministic (no LLM/embedding calls), so skip the
        # first-run LLM/embedding connection checks and stay truly keyless.
        skip_connection_test=True,
    )

    print("Listing the first indexed code facts")
    search_results = await cognee.search(
        query_type=SearchType.CODE,
        query_text="",
        datasets=["code_graph_demo"],
        code_query={
            "operation": "query_facts",
            "kinds": ["module", "symbol", "route", "storage", "service"],
            "limit": 20,
        },
    )

    print(json.dumps(search_results, indent=2, default=str))

    # Other deterministic operations use the same API shape:
    # code_query={"operation": "explore", "id": "<fact id>", "max_depth": 2}
    # code_query={"operation": "traverse", "node_ids": ["<fact id>"], "direction": "reverse"}
    # code_query={"operation": "find_path", "source_id": "<id>", "target_id": "<id>"}
    # code_query={"operation": "impact_analysis", "id": "<fact id>", "max_depth": 3}


if __name__ == "__main__":
    logger = setup_logging(log_level=ERROR)
    asyncio.run(main())
```

## What Just Happened

### Step 1: Choose the Repository and Start Clean

```python theme={null}
repo_path = os.getenv("CODE_GRAPH_REPO_PATH", os.getcwd())

# Start clean so the example is reproducible.
await cognee.prune.prune_data()
await cognee.prune.prune_system(metadata=True)
```

The repository to index comes from `CODE_GRAPH_REPO_PATH`, falling back to the directory you run the script from. Pruning first means the graph you inspect afterwards contains only what this run extracted.

### Step 2: Run the Code Graph Pipeline

```python theme={null}
print(f"Extracting code graph from: {repo_path}")
await cognee.run_custom_pipeline(
    # Pass index_vectors=True only if these facts should also be available
    # to semantic/LLM retrievers; SearchType.CODE does not need it.
    tasks=get_code_graph_tasks(repo_path),
    data=repo_path,
    dataset="code_graph_demo",
    pipeline_name="code_graph_pipeline",
    # This pipeline is deterministic (no LLM/embedding calls), so skip the
    # first-run LLM/embedding connection checks and stay truly keyless.
    skip_connection_test=True,
)
```

`get_code_graph_tasks()` returns the three ordered tasks the pipeline runs: extract (run enola over the repository and map its facts to DataPoints), load the graph nodes, then load the typed relations as edges. Because nothing here calls an LLM or an embedding model, `skip_connection_test=True` skips the first-run provider checks so the pipeline runs without any API key.

### Step 3: Query the Graph with SearchType.CODE

```python theme={null}
print("Listing the first indexed code facts")
search_results = await cognee.search(
    query_type=SearchType.CODE,
    query_text="",
    datasets=["code_graph_demo"],
    code_query={
        "operation": "query_facts",
        "kinds": ["module", "symbol", "route", "storage", "service"],
        "limit": 20,
    },
)

print(json.dumps(search_results, indent=2, default=str))
```

`SearchType.CODE` is driven by the structured `code_query` argument rather than by `query_text`, which stays empty here. The `query_facts` operation filters the extracted facts — by `kinds` in this case — and returns the first `limit` matches, so the result is a deterministic listing rather than a similarity ranking.

### Step 4: Reuse the Same Shape for Other Operations

```python theme={null}
# Other deterministic operations use the same API shape:
# code_query={"operation": "explore", "id": "<fact id>", "max_depth": 2}
# code_query={"operation": "traverse", "node_ids": ["<fact id>"], "direction": "reverse"}
# code_query={"operation": "find_path", "source_id": "<id>", "target_id": "<id>"}
# code_query={"operation": "impact_analysis", "id": "<fact id>", "max_depth": 3}
```

Every other operation is the same `cognee.search()` call with a different `code_query`. Take a fact id from the `query_facts` output above and feed it to `explore` to see a fact's neighborhood, `traverse` to walk edges in one direction, `find_path` to connect two facts, or `impact_analysis` to see what depends on a fact. There is also a `delta` operation, which needs no fact id: `code_query={"operation": "delta"}` reports what the last ingestion changed in each repository.

## Advanced Usage

<AccordionGroup>
  <Accordion title="Make the Facts Available to Semantic Retrievers">
    `get_code_graph_tasks(repo_path, index_vectors=True)` also writes the extracted facts to the vector store, so semantic and LLM-backed retrievers can reach them. It is opt-in because `SearchType.CODE` reads the graph only; enabling it adds embedding calls and therefore needs an [embedding provider](/setup-configuration/embedding-providers) configured.
  </Accordion>

  <Accordion title="Query Across Repositories">
    Graph paths only exist inside a single dataset. To follow paths across repositories, generate one Enola append/multi-repository snapshot covering all of them and ingest that into one dataset. Repositories indexed into separate datasets are searched independently, and no path can connect them.
  </Accordion>

  <Accordion title="Provide Your Own enola Binary">
    `ENOLA_PATH` always wins over the auto-installed binary, so point it at your own build to control the version. Setting `ENOLA_AUTO_INSTALL=false` disables the automatic download entirely — the run then fails with an install error instead of fetching the pinned release.
  </Accordion>
</AccordionGroup>

<Columns cols={3}>
  <Card title="Pipelines" icon="git-merge" href="/core-concepts/building-blocks/pipelines">
    How tasks are orchestrated into a pipeline.
  </Card>

  <Card title="run_custom_pipeline()" icon="route" href="/python-api/custom-pipeline">
    The full parameter surface of the call this guide uses.
  </Card>

  <Card title="Custom Tasks and Pipelines" icon="workflow" href="/guides/custom-tasks-pipelines">
    Write your own tasks and assemble them into a pipeline.
  </Card>
</Columns>
