# `Nous.KnowledgeBase.Store`
[🔗](https://github.com/nyo16/nous/blob/v0.17.1/lib/nous/knowledge_base/store.ex#L1)

Storage behaviour for knowledge base backends.

Defines callbacks for document, entry, and link CRUD operations
plus search and graph traversal. Follows the same pattern as
`Nous.Memory.Store` but with wiki-specific operations.

All list/search callbacks accept a `:kb_id` option for scoping.

## State threading caveat

Several call sites (`kb_link`, `persist_to_store`) read `store_state`
once and reuse it across multiple write callbacks. This is safe for
backends where `state` is a mutable handle (the included ETS impl,
any process-wrapped backend) but **NOT** for purely-functional stores
that depend on threading the new state through every call. New
backends must either:

  * use mutable handles in `state` (ETS / process registry / database
    connection ref), OR
  * implement their own concurrency control / write log (the kb code
    cannot guarantee atomicity across multi-step operations).

This contract may tighten in a future version; for now, prefer
mutable-handle backends.

# `backlinks`

```elixir
@callback backlinks(state :: term(), entry_id :: String.t()) ::
  {:ok, [Nous.KnowledgeBase.Link.t()]}
```

# `delete_document`

```elixir
@callback delete_document(state :: term(), id :: String.t()) ::
  {:ok, term()} | {:error, term()}
```

# `delete_entry`

```elixir
@callback delete_entry(state :: term(), id :: String.t()) ::
  {:ok, term()} | {:error, term()}
```

# `delete_link`

```elixir
@callback delete_link(state :: term(), id :: String.t()) ::
  {:ok, term()} | {:error, term()}
```

# `fetch_document`

```elixir
@callback fetch_document(state :: term(), id :: String.t()) ::
  {:ok, Nous.KnowledgeBase.Document.t()} | {:error, :not_found}
```

# `fetch_entry`

```elixir
@callback fetch_entry(state :: term(), id :: String.t()) ::
  {:ok, Nous.KnowledgeBase.Entry.t()} | {:error, :not_found}
```

# `fetch_entry_by_slug`

```elixir
@callback fetch_entry_by_slug(state :: term(), slug :: String.t()) ::
  {:ok, Nous.KnowledgeBase.Entry.t()} | {:error, :not_found}
```

# `init`

```elixir
@callback init(opts :: keyword()) :: {:ok, term()} | {:error, term()}
```

# `link_counts_by_source`
*optional* 

```elixir
@callback link_counts_by_source(state :: term()) ::
  {:ok, %{optional(String.t()) =&gt; non_neg_integer()}}
```

Optional bulk callback for getting all link counts grouped by source entry.

Backends that can answer "for every entry, how many outgoing links does
it have?" with a single scan should implement this for O(L) instead of
O(E*L) health checks. Falls back to per-entry `outlinks/2` when not
implemented (the default in the macro below). Returns
`{:ok, %{entry_id => count}}`.

# `list_documents`

```elixir
@callback list_documents(state :: term(), opts :: keyword()) ::
  {:ok, [Nous.KnowledgeBase.Document.t()]}
```

# `list_entries`

```elixir
@callback list_entries(state :: term(), opts :: keyword()) ::
  {:ok, [Nous.KnowledgeBase.Entry.t()]}
```

# `outlinks`

```elixir
@callback outlinks(state :: term(), entry_id :: String.t()) ::
  {:ok, [Nous.KnowledgeBase.Link.t()]}
```

# `related_entries`
*optional* 

```elixir
@callback related_entries(state :: term(), entry_id :: String.t(), opts :: keyword()) ::
  {:ok, [Nous.KnowledgeBase.Entry.t()]}
```

# `search_entries`
*optional* 

```elixir
@callback search_entries(state :: term(), query :: String.t(), opts :: keyword()) ::
  {:ok, [{Nous.KnowledgeBase.Entry.t(), float()}]}
```

# `store_document`

```elixir
@callback store_document(state :: term(), doc :: Nous.KnowledgeBase.Document.t()) ::
  {:ok, term()} | {:error, term()}
```

# `store_entry`

```elixir
@callback store_entry(state :: term(), entry :: Nous.KnowledgeBase.Entry.t()) ::
  {:ok, term()} | {:error, term()}
```

# `store_link`

```elixir
@callback store_link(state :: term(), link :: Nous.KnowledgeBase.Link.t()) ::
  {:ok, term()} | {:error, term()}
```

# `update_document`

```elixir
@callback update_document(state :: term(), id :: String.t(), updates :: map()) ::
  {:ok, term()} | {:error, term()}
```

# `update_entry`

```elixir
@callback update_entry(state :: term(), id :: String.t(), updates :: map()) ::
  {:ok, term()} | {:error, term()}
```

---

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