# `Gralkor.GraphitiPool`
[🔗](https://github.com/elimydlarz/gralkor/blob/main/lib/gralkor/graphiti_pool.ex#L1)

Per-group Graphiti instance cache, plus the gateway for graphiti operations.

Holds one shared `AsyncFalkorDB` (the embedded redis-server child lives
here) and lazily constructs one `Graphiti` instance per `group_id`. Cached
in ETS for concurrent reads — `for/1` only hits the GenServer on a cache
miss (i.e. the first time any caller asks for a given group). Once cached,
thousands of callers can read the instance simultaneously without going
through the GenServer.

This is intentional. The spike (`pythonx-spike/LEARNINGS.md`) showed that
Pythonx releases the GIL during graphiti's awaited I/O, so concurrent
Elixir callers parallelise naturally. Serialising calls through a single
GenServer would throw that away.

See `ex-graphiti-pool` in `gralkor/TEST_TREES.md`.

# `add_episode`

```elixir
@spec add_episode(GenServer.server(), String.t(), String.t(), String.t()) ::
  :ok | {:error, term()}
```

Ingest one episode (text content) into `group_id` via graphiti's
`add_episode`. Auto-generates `name` and `idempotency_key`.

# `build_communities`

```elixir
@spec build_communities(GenServer.server(), String.t()) ::
  {:ok, %{communities: non_neg_integer(), edges: non_neg_integer()}}
  | {:error, term()}
```

Build communities for `group_id`.

# `build_indices`

```elixir
@spec build_indices(GenServer.server()) ::
  {:ok, %{status: String.t()}} | {:error, term()}
```

Build indices and constraints across the whole graph.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `for`

```elixir
@spec for(GenServer.server(), String.t()) :: any()
```

Return the Graphiti instance for `group_id`, creating it on first use.

Concurrent callers do not block each other once the instance is cached.
Construction itself is serialised through the GenServer so two callers
asking for the same group_id at the same time don't both construct it.

# `search`

```elixir
@spec search(GenServer.server(), String.t(), String.t(), pos_integer()) ::
  {:ok, [map()]} | {:error, term()}
```

Run graphiti's hybrid search against `group_id`. Returns
`{:ok, [%{fact:, created_at:, valid_at:, invalid_at:, expired_at:}]}`
ready for `Gralkor.Format.format_facts/1`.

# `start_link`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
