# Knowledge graph

> Enable Graphiti with Neo4j via docker-compose-graphiti.yml, GRAPHITI_* settings, graphiti_search tool behavior, and failure modes when the graph backend is down.

- Repository: vxcontrol/pentagi
- GitHub: https://github.com/vxcontrol/pentagi
- Human docs: https://grok-wiki.com/public/docs/vxcontrol-pentagi-eca0cf4de5f5
- Complete Markdown: https://grok-wiki.com/public/docs/vxcontrol-pentagi-eca0cf4de5f5/llms-full.txt

## Source Files

- `docker-compose-graphiti.yml`
- `backend/pkg/graphiti/client.go`
- `backend/pkg/tools/graphiti_search.go`
- `backend/pkg/config/config.go`
- `.env.example`
- `README.md`

---

---
title: "Knowledge graph"
description: "Enable Graphiti with Neo4j via docker-compose-graphiti.yml, GRAPHITI_* settings, graphiti_search tool behavior, and failure modes when the graph backend is down."
---

PentAGI’s optional knowledge graph is a **beta** Graphiti + Neo4j stack. Agents ingest episodes into a temporal graph and query them with the `graphiti_search` tool (`backend/pkg/tools/graphiti_search.go`), backed by `backend/pkg/graphiti.Client` and the `vxcontrol/graphiti-go-client` library. The feature is off unless `GRAPHITI_ENABLED=true`, `GRAPHITI_URL` is set, and the Graphiti HTTP service is reachable at startup health check.

<Warning>
Graphiti entity extraction uses a single OpenAI-compatible endpoint (`OPEN_AI_KEY` / `OPEN_AI_SERVER_URL`), not Anthropic, Gemini, Bedrock, DeepSeek, GLM, Kimi, or Qwen credentials configured for flows. Leave Graphiti disabled if that endpoint is unavailable.
</Warning>

## Architecture

```mermaid
flowchart LR
  subgraph pentagi [PentAGI runtime]
    FP[flowProvider<br/>storeToGraphiti]
    Tools[graphiti_search tool]
    Client[pkg/graphiti.Client]
  end
  subgraph graphiti_stack [docker-compose-graphiti.yml]
    API[graphiti :8000]
    Neo[neo4j :7687 / :7474]
  end
  FP -->|AddMessages group_id flow-N| Client
  Tools -->|search GroupID flow-N| Client
  Client -->|HTTP| API
  API --> Neo
```

| Layer | Role |
| --- | --- |
| `flowProvider` | Writes agent responses and tool executions as Graphiti messages under `group_id=flow-{id}` |
| `graphiti_search` | Read path for seven search types, same group scoping |
| `graphiti` container | `vxcontrol/graphiti:latest` API on port `8000` |
| `neo4j` container | Graph store (`neo4j:5.26.2`), Bolt `7687`, Browser `7474` |

When disabled or failed at init, pgvector memory and the rest of the stack continue; only graph features are skipped.

## Enable the stack

### Prerequisites

- Core compose already running so external network `pentagi-network` exists
- OpenAI-compatible API key for Graphiti extraction (`OPEN_AI_KEY`)
- Optional: change default Neo4j password (`NEO4J_PASSWORD`, default `devpassword`)

### Environment

Set in `.env` (see `.env.example`):

```bash
GRAPHITI_ENABLED=true
GRAPHITI_TIMEOUT=30
GRAPHITI_URL=http://graphiti:8000
GRAPHITI_MODEL_NAME=gpt-5-mini

NEO4J_USER=neo4j
NEO4J_DATABASE=neo4j
NEO4J_PASSWORD=devpassword
NEO4J_URI=bolt://neo4j:7687

OPEN_AI_KEY=your_openai_api_key
# OPEN_AI_SERVER_URL defaults to https://api.openai.com/v1
```

| Variable | Consumed by | Default | Purpose |
| --- | --- | --- | --- |
| `GRAPHITI_ENABLED` | PentAGI `Config` | `false` | Master switch |
| `GRAPHITI_URL` | PentAGI client | empty | Graphiti base URL; required with enabled |
| `GRAPHITI_TIMEOUT` | PentAGI client | `30` (seconds) | HTTP / store timeout |
| `GRAPHITI_MODEL_NAME` | Graphiti container only | `gpt-5-mini` | Extraction model (`MODEL_NAME` in compose) |
| `NEO4J_*` | Graphiti/Neo4j containers | see compose | Graph DB auth and Bolt URI |
| `OPEN_AI_KEY` / `OPEN_AI_SERVER_URL` | Mapped to container `OPENAI_API_KEY` / `OPENAI_BASE_URL` | API OpenAI default | Entity extraction LLM |

PentAGI reads only `GRAPHITI_ENABLED`, `GRAPHITI_TIMEOUT`, and `GRAPHITI_URL` in `backend/pkg/config/config.go`. Model name and Neo4j credentials are compose-side for the Graphiti service.

### Compose

```bash
# Core first if pentagi-network is missing
docker compose -f docker-compose.yml up -d

docker compose -f docker-compose.yml -f docker-compose-graphiti.yml up -d
```

`docker-compose-graphiti.yml` services:

| Service | Image | Host ports | Health |
| --- | --- | --- | --- |
| `neo4j` | `neo4j:5.26.2` | `127.0.0.1:7474`, `127.0.0.1:7687` | HTTP `7474` |
| `graphiti` | `vxcontrol/graphiti:latest` | `127.0.0.1:8000` | `GET /healthcheck` on `:8000` |

`graphiti` depends on healthy `neo4j`, joins `pentagi-network`, and uses volume `neo4j_data`.

Installer support: TUI Graphiti form can set embedded (`http://graphiti:8000`), external URL, or disabled modes (`GRAPHITI_ENABLED` + `GRAPHITI_URL`).

### Verify

```bash
docker compose -f docker-compose.yml -f docker-compose-graphiti.yml ps graphiti neo4j
docker compose -f docker-compose.yml -f docker-compose-graphiti.yml logs -f graphiti

# Optional UIs
# Neo4j Browser: http://localhost:7474
# Graphiti Swagger: http://localhost:8000/docs
```

Client init calls Graphiti `HealthCheck()` when enabled with a non-empty URL. On failure, providers log a warning and continue with a disabled client:

```text
failed to initialize graphiti client, continuing without it
```

## Runtime wiring

1. **Provider controller** constructs `graphiti.NewClient(url, timeout, enabled && url != "")`.
2. Client is shared into flow tools and `flowProvider`.
3. **Ingest** (when enabled): after agent turns, `storeAgentResponseToGraphiti` and `storeToolExecutionToGraphiti` render templates under `backend/pkg/templates/graphiti/` and call `AddMessages` with `GroupID: flow-{id}`.
4. **Search**: `graphiti_search` is registered only if `IsAvailable()` (client non-nil and `IsEnabled()`).

Agents that receive the tool when available: **coder**, **pentester**, **memorist**, **enricher**. Prompts inject `GraphitiEnabled` and `GraphitiSearchToolName` (`graphiti_search`) so protocol blocks appear only when the client is live.

### What is stored

| Episode kind | Source | Content |
| --- | --- | --- |
| Agent response | Agent completion text | Rendered via `agent_response.tmpl` with agent type, task/subtask |
| Tool execution | Tool call + output (or error) | Rendered via `tool_execution.tmpl`; status success/failure |

Store failures are logged as warnings and do not fail the agent turn. `AddMessages` is a no-op when the client is disabled.

### Scoping

Write and search use `group_id = flow-{id}`. Graph search context is per active flow, not a global cross-flow library (unlike the shared English-indexed pgvector store). Soft-deleted flows remain separate from optional graph reuse workflows.

## `graphiti_search` tool

| Property | Value |
| --- | --- |
| Tool name | `graphiti_search` |
| Registry type | `SearchVectorDbToolType` |
| Args type | `GraphitiSearchAction` |
| Availability | Client enabled after successful init |

### Arguments

| Field | Required | Notes |
| --- | --- | --- |
| `search_type` | yes | One of seven types below |
| `query` | yes | English technical-channel NL query (graph indexed in English) |
| `message` | yes | Engagement-language 1–2 sentence log line |
| `max_results` | no | Per-type defaults if ≤ 0 |
| `time_start` / `time_end` | for `temporal_window` | RFC3339 / ISO 8601; `time_end` after `time_start` |
| `center_node_uuid` | for `entity_relationships` | Center entity UUID |
| `max_depth` | no | Default `2`, capped at `3` |
| `node_labels` | for `entity_by_label` (required); optional filters elsewhere | e.g. `IP_ADDRESS`, `SERVICE`, `VULNERABILITY` |
| `edge_types` | no | e.g. `HAS_PORT`, `EXPLOITS` |
| `diversity_level` | no | `low` \| `medium` \| `high` (default `medium`) |
| `min_mentions` | no | Default `2` for `successful_tools` |
| `recency_window` | no | `1h` \| `6h` \| `24h` \| `7d` (default `24h`) |

### Search types and defaults

| `search_type` | Purpose | Default `max_results` | Extra params |
| --- | --- | --- | --- |
| `temporal_window` | Time-bounded facts, entities, episodes | 15 | `time_start`, `time_end` |
| `entity_relationships` | Graph traversal from a node | 20 | `center_node_uuid`, `max_depth`, labels/edges |
| `diverse_results` | MMR-style diverse communities/facts | 10 | `diversity_level` |
| `episode_context` | Agent responses and tool records | 10 | — |
| `successful_tools` | Proven tool/technique patterns | 15 | `min_mentions` |
| `recent_context` | Latest findings in a window | 10 | `recency_window` |
| `entity_by_label` | Inventory by node labels | 25 | `node_labels` (required) |

Results are formatted as Markdown (facts/edges, entities/nodes with UUIDs, episodes with content). Empty sets produce explicit “no results” strings.

### Example calls

```json
{
  "search_type": "recent_context",
  "query": "recent pentester findings about web application open ports",
  "recency_window": "6h",
  "message": "Checking Graphiti for recent recon on the target app."
}
```

```json
{
  "search_type": "temporal_window",
  "query": "all reconnaissance activities",
  "time_start": "2024-01-01T00:00:00Z",
  "time_end": "2024-01-01T23:59:59Z",
  "message": "Pulling recon episodes from the first day of the engagement."
}
```

```json
{
  "search_type": "entity_relationships",
  "query": "related vulnerabilities and services",
  "center_node_uuid": "<uuid-from-prior-search>",
  "max_depth": 2,
  "message": "Expanding relationships from the discovered host entity."
}
```

## Relationship to pgvector memory

| | Graphiti | pgvector memory tools |
| --- | --- | --- |
| Role | Episodic: what happened in this flow | Reusable knowledge: guides, code, Q&A |
| Index language | English queries | English queries |
| Scope | `flow-{id}` group | Optional task/subtask filters; shared store |
| Primary tool | `graphiti_search` | `search_in_memory`, store/search guide/code |

Memorist prompts (when Graphiti is on) instruct: search Graphiti first for execution history, then vector DB for reusable knowledge.

## Failure modes

| Condition | Runtime behavior |
| --- | --- |
| `GRAPHITI_ENABLED=false` or empty `GRAPHITI_URL` | Client created disabled; no health check; `AddMessages` no-op; tool not registered |
| Health check fails at provider init | Warning log; empty disabled client; same as off |
| Client disabled, search API called | Methods return `graphiti is not enabled` |
| Tool invoked while unavailable | Soft message: `Graphiti knowledge graph is not enabled. No historical context or memory data is available for this search.` (no hard error) |
| Store path error while enabled | Warning + Langfuse evaluator error; agent continues |
| Search transport/API error while enabled | Hard tool error: e.g. `temporal window search failed: ...` |
| Invalid args | Hard errors: missing `query`/`search_type`, bad times, unknown `search_type`, invalid `diversity_level`/`recency_window`, missing `center_node_uuid`/`node_labels` where required |
| Graphiti/Neo4j down after successful init | Ingest warns; searches fail for that call; flows otherwise proceed |
| No OpenAI-compatible key for Graphiti | Extraction/store quality fails in Graphiti service logs; configure `OPEN_AI_KEY` or disable |
| Missing `pentagi-network` | Compose overlay fails; start core `docker-compose.yml` first |

### Operational recovery

```bash
# Confirm health
curl -sS http://127.0.0.1:8000/healthcheck

# Restart graph stack
docker compose -f docker-compose.yml -f docker-compose-graphiti.yml up -d neo4j graphiti

# Temporarily disable without removing volumes
# GRAPHITI_ENABLED=false  (or empty GRAPHITI_URL)
```

Restart PentAGI after Graphiti becomes healthy if the first init failed the health check; the client does not auto-reenable mid-process after a failed `NewClient`.

## Limitations (beta)

- Single OpenAI-compatible extraction endpoint per deployment
- One model (`GRAPHITI_MODEL_NAME`) for all extractions; not per agent/flow
- Separate billing from the flow’s LLM provider
- No in-app graph explorer: use Neo4j Browser and Graphiti `/docs`
- Custom pentest entity/edge types come from the `vxcontrol/graphiti` image/fork

## Related pages

<CardGroup cols={2}>
  <Card title="Memory and knowledge" href="/memory-and-knowledge">
    pgvector tools, embeddings, summarizer budgets, and where Graphiti fits beside long-term memory.
  </Card>
  <Card title="Installation" href="/installation">
    Core compose, `.env`, volumes, and optional Graphiti/Langfuse/observability overlays.
  </Card>
  <Card title="Environment variables" href="/environment-variables">
    Full Config and `.env.example` reference including GRAPHITI_* and related keys.
  </Card>
  <Card title="Tools reference" href="/tools-reference">
    Named registry entries including graphiti_search argument shapes.
  </Card>
  <Card title="Interactive installer" href="/installer">
    TUI paths for embedded, external, or disabled Graphiti deployment.
  </Card>
  <Card title="Tools and sandbox" href="/tools-and-sandbox">
    Tool categories and how specialist executors attach optional tools.
  </Card>
</CardGroup>
