# Hermes provider integration

> Integrate via `HermesOKFProvider` and `HermesOKFMemoryProvider`: session hooks, memory/tool/decision/plan callbacks, `prefetch`/`sync_turn`, exposed tool schemas (`search_memory`, `snapshot_memory`), and model sync from Hermes `config.yaml`.

- Repository: EliaszDev/hermes-okf
- GitHub: https://github.com/EliaszDev/hermes-okf
- Human docs: https://www.grok-wiki.com/public/docs/eliaszdev-hermes-okf-b71befaafe02
- Complete Markdown: https://www.grok-wiki.com/public/docs/eliaszdev-hermes-okf-b71befaafe02/llms-full.txt

## Source Files

- `src/hermes_okf/hermes_integration.py`
- `src/hermes_okf/memory_plugin.py`
- `docs/HERMES_USERS.md`
- `docs/HERMES_PLUGIN.md`
- `tests/test_hermes_integration.py`
- `tests/test_hermes.py`

---

---
title: "Hermes provider integration"
description: "Integrate via `HermesOKFProvider` and `HermesOKFMemoryProvider`: session hooks, memory/tool/decision/plan callbacks, `prefetch`/`sync_turn`, exposed tool schemas (`search_memory`, `snapshot_memory`), and model sync from Hermes `config.yaml`."
---

`hermes-okf` exposes two integration surfaces for Hermes Agent: `HermesOKFProvider` (the core hook implementation backed by `HermesAgent` and an OKF bundle) and `HermesOKFMemoryProvider` (the Hermes `MemoryProvider` ABC adapter that Hermes loads at session start). Together they mirror Hermes lifecycle events into typed OKF concepts, buffer fast writes through `HotMemoryBuffer`, and sync the active LLM model from `~/.hermes/config.yaml` into the `config/agent` concept.

## Architecture

```mermaid
flowchart TB
    subgraph Hermes["Hermes Agent runtime"]
        MP["MemoryProvider ABC"]
        CLI["hermes okf CLI"]
    end

    subgraph Adapter["hermes_okf.memory_plugin"]
        MMP["HermesOKFMemoryProvider"]
    end

    subgraph Core["hermes_okf.hermes_integration"]
        HOP["HermesOKFProvider"]
        HMB["HotMemoryBuffer"]
        CFG["HermesOKFConfig"]
    end

    subgraph State["OKF bundle (~/.hermes/okf_memory)"]
        HA["HermesAgent"]
        OKF["OKFBundle + SearchIndex"]
    end

    MP --> MMP
    MMP --> HOP
    CLI --> HOP
    HOP --> CFG
    HOP --> HMB
    HOP --> HA
    HA --> OKF
    HMB -->|"flush on session end / buffer max"| HA
```

| Component | Module | Role |
|-----------|--------|------|
| `HermesOKFProvider` | `hermes_integration.py` | Session, memory, tool, decision, and plan hooks; search, snapshot, and optional RAG |
| `HermesOKFMemoryProvider` | `memory_plugin.py` | Hermes `MemoryProvider` ABC: `initialize`, `sync_turn`, `prefetch`, `shutdown`, tool schemas |
| `get_provider()` | `hermes_integration.py` | Process-wide singleton `HermesOKFProvider` |
| `HermesOKFConfig` | `hermes_integration.py` | Config dataclass with env/file resolution |

<Note>
Hermes discovers memory providers from `~/.hermes/plugins/` (filesystem) and the `hermes.memory_providers` pip entry point. Run `hermes-okf-install` to create the plugin wrapper and update `~/.hermes/config.yaml`.
</Note>

## Discovery and registration

Hermes loads `HermesOKFMemoryProvider` through two paths:

1. **Filesystem plugin** — `hermes-okf-install` writes `~/.hermes/plugins/hermes-okf/__init__.py` and `plugin.yaml`, and sets `memory.provider: hermes-okf` in `config.yaml`.
2. **Pip entry point** — `pyproject.toml` registers `hermes-okf = "hermes_okf.memory_plugin:HermesOKFMemoryProvider"` under `hermes.memory_providers`.

The `hermes okf` CLI subcommand registers separately via the `hermes_agent.plugins` entry point (`hermes_okf.plugin.register` → `cli_extension.register_cli`).

<Steps>
<Step title="Install and register">

```bash
pip install hermes-okf
hermes-okf-install
```

Creates `~/.hermes/plugins/hermes-okf/` and updates `plugins.enabled` and `memory.provider` in `~/.hermes/config.yaml`.

</Step>
<Step title="Configure memory keys">

```yaml
plugins:
  enabled:
    - hermes-okf

memory:
  provider: hermes-okf
  bundle_path: ~/.hermes/okf_memory
  agent_id: hermes-agent
  auto_snapshot: true
  log_tool_calls: true
  hot_memory_max: 50
```

`plugins.enabled` must be a YAML list, not a string.

</Step>
<Step title="Activate and verify">

```bash
hermes memory setup   # optional: customize bundle_path, agent_id, auto_snapshot
hermes                # start a session — provider initializes on first turn
hermes okf show config/agent
```

Expect an `AgentConfig` concept with the model read from Hermes `config.yaml`.

</Step>
</Steps>

## Configuration resolution

`HermesOKFConfig.from_hermes_config()` resolves settings in this order:

1. `HERMES_OKF_*` environment variables (`BUNDLE_PATH`, `AGENT_ID`, `AUTO_SNAPSHOT`, `ENABLE_RAG`)
2. `~/.hermes/hermes-okf.yaml`
3. `~/.hermes/config.yaml` → `plugins.hermes_okf`
4. Built-in defaults

`HermesOKFMemoryProvider.initialize()` reads the `memory` block from `~/.hermes/config.yaml` directly and additionally pulls the active model from the top-level `model` key or `llm.model`.

<ParamField body="bundle_path" type="string" default="~/.hermes/okf_memory">
OKF bundle root directory.
</ParamField>

<ParamField body="agent_id" type="string" default="hermes">
Agent identifier written into OKF concepts and log entries.
</ParamField>

<ParamField body="model" type="string" default="">
LLM model identifier. Empty in `HermesOKFConfig` defaults; populated from Hermes `config.yaml` during `initialize()`.
</ParamField>

<ParamField body="auto_snapshot" type="boolean" default="true">
Save a snapshot on session start and end (and on plan completion).
</ParamField>

<ParamField body="log_tool_calls" type="boolean" default="true">
Record tool invocations to the hot buffer and lazy-register tools in OKF.
</ParamField>

<ParamField body="log_decisions" type="boolean" default="true">
Record strategic decisions to the hot buffer.
</ParamField>

<ParamField body="hot_memory_max" type="integer" default="50">
Maximum hot-buffer items before automatic flush to the cold archive.
</ParamField>

<ParamField body="enable_rag" type="boolean" default="false">
Enable ChromaDB vector search (requires `pip install hermes-okf[rag]`).
</ParamField>

## Model sync from Hermes config.yaml

On every `HermesOKFMemoryProvider.initialize()` call, the adapter:

1. Reads `model` from `config.yaml` (top-level `model`, falling back to `llm.model`)
2. Sets `config.model` on the underlying `HermesOKFProvider`
3. Writes or updates the `config/agent` OKF concept with `type: AgentConfig`, the synced model, system prompt, and package version

```yaml
# ~/.hermes/config.yaml
model: anthropic/claude-sonnet-4
# or
llm:
  model: openai/gpt-4o
```

If `config/agent` shows a stale model, restart Hermes to trigger re-initialization. Inspect with `hermes okf show config/agent`.

## Session hooks

### HermesOKFProvider

| Hook | Signature | OKF effect |
|------|-----------|------------|
| Session start | `on_session_start(session_id)` | Calls `agent.start_session`, records a `Session` observation, optional snapshot |
| Session end | `on_session_end(session_id)` | Flushes hot buffer, records end observation, calls `agent.end_session`, optional snapshot |

On init, `HermesOKFProvider` creates the Hermes-native directory layout under the bundle: `hermes/sessions`, `hermes/tools`, `hermes/plans`, `hermes/plans/archive`, `hermes/decisions`, `hermes/observations`, `hermes/snapshots`.

### HermesOKFMemoryProvider

| Hook | When called | Delegates to |
|------|-------------|--------------|
| `initialize(session_id, **kwargs)` | Session bootstrap | Builds `HermesOKFConfig` from `config.yaml`, creates `HermesOKFProvider`, calls `on_session_start`, syncs `config/agent` |
| `shutdown()` | Clean exit | `on_session_end` + hot-buffer flush |
| `on_session_start(session_id)` | Post-initialize lifecycle | `provider.on_session_start` |
| `on_session_end(messages)` | End-of-session extraction | `provider.on_session_end` |

`initialize` accepts `hermes_home`, `platform`, and `agent_identity` kwargs from Hermes but reads bundle settings from the `memory` config block.

## Memory, tool, decision, and plan callbacks

### Memory writes

`HermesOKFProvider.on_memory_write(target, content)` maps Hermes flat memory to typed OKF storage:

| `target` | Storage | OKF type |
|----------|---------|----------|
| `"memory"` | Hot buffer → flush | `Observation` (category `HermesMemory`) |
| `"user"` | Direct write | `UserProfile` at `hermes/observations/user_profile_<date>` |

`HermesOKFMemoryProvider.on_memory_write(action, target, content, metadata)` mirrors built-in Hermes writes when `action == "add"` and `target` is `"memory"` or `"user"`.

<Warning>
`sync_turn` passes `target="assistant"` for assistant content, but `HermesOKFProvider.on_memory_write` does not handle the `"assistant"` target. Assistant turn text is not persisted unless you extend the provider or route it through `target="memory"`.
</Warning>

### Tool calls

`on_tool_call(tool_name, args, result)`:

- Pushes a `tool_call` item to `HotMemoryBuffer` when `log_tool_calls` is true
- Lazy-registers the tool via `_ensure_tool_registered` if not already in the registry
- Optionally snapshots when `snapshot_on_tool_call` is true

### Decisions

`on_decision(decision, rationale="", tags=None)` pushes a `decision` item to the hot buffer when `log_decisions` is true. On flush, `HermesAgent.memory.record_decision` writes a `Decision` concept under `decisions/`.

### Plans

| Hook | Effect |
|------|--------|
| `on_plan_create(plan_name, steps)` | Creates a `Plan` concept; returns `plan_id` |
| `on_plan_step_complete(plan_id, step_index, result)` | Marks step complete, updates progress |
| `on_plan_complete(plan_id)` | Records completion observation, archives plan, flushes hot buffer, optional snapshot |

## Hot memory and flush behavior

`HotMemoryBuffer` holds in-process items (`observation`, `decision`, `tool_call`) with UTC timestamps. Flush triggers:

- `on_session_end`
- Buffer length ≥ `hot_memory_max` (checked after each push via `_maybe_flush`)
- Explicit `snapshot()`, `restore()`, or `on_plan_complete`

On flush, items route to `HermesAgent.memory.record_observation`, `record_decision`, or `record_tool_call`.

## Turn sync and prefetch

### `sync_turn`

```python
def sync_turn(
    self,
    user_content: str,
    assistant_content: str,
    *,
    session_id: str = "",
    messages: list[dict[str, Any]] | None = None,
) -> None
```

Persists a completed conversation turn:

- **User content** → `on_memory_write("user", user_content)` (writes `UserProfile`)
- **Assistant content** → `on_memory_write("assistant", assistant_content)` (no-op at provider level today)
- **Messages** — extracts `tool_calls` from assistant messages and tool results from `role: tool` messages, forwarding each to `on_tool_call`

### `prefetch`

```python
def prefetch(self, query: str, *, session_id: str = "") -> str
```

Runs full-text search (`provider.search(query, top_k=5)`), reads matching concepts, and returns a formatted markdown block:

```
## Relevant Memory (from OKF bundle)

- [Decision] Use Python (score: 0.85)
  User prefers Python for scripting tasks...
```

Returns an empty string when the provider is uninitialized or the query is empty. Hermes injects this block into context before the model call.

## Exposed tool schemas

`get_tool_schemas()` returns function definitions Hermes can expose to the agent:

### `search_memory`

<ResponseField name="query" type="string" required>
Full-text search query against the OKF bundle.
</ResponseField>

<ResponseField name="top_k" type="integer" default="5">
Number of results to return.
</ResponseField>

### `snapshot_memory`

<ResponseField name="note" type="string" default="">
Optional note stored with the snapshot.
</ResponseField>

<Info>
The `get_tool_schemas` docstring references `restore_memory`, but the current implementation returns only `search_memory` and `snapshot_memory`. Use `hermes okf restore` or `provider.restore()` for snapshot recovery.
</Info>

## Direct Python usage

For custom integrations without the Hermes `MemoryProvider` ABC, use `HermesOKFProvider` directly:

```python
from hermes_okf import HermesOKFProvider

provider = HermesOKFProvider()
provider.on_session_start("deploy-001")

provider.on_memory_write("memory", "User prefers dark mode")
provider.on_tool_call("search_web", {"query": "OKF"}, "Found 5 results")
provider.on_decision("Use 3 replicas", "Moderate traffic expected", tags=["deploy"])

plan_id = provider.on_plan_create("Deploy service", ["Build", "Push", "Deploy"])
provider.on_plan_step_complete(plan_id, 0, "Built in 45s")
provider.on_plan_complete(plan_id)

provider.on_session_end("deploy-001")
```

Or use the singleton:

```python
from hermes_okf import get_provider

provider = get_provider()
results = provider.search("deployment", top_k=5)
context = provider.build_context("What did we decide about replicas?")
```

`HermesOKFProvider.__getattr__` delegates unknown attributes to the underlying `HermesAgent`, so `provider.agent`, `provider.create_plan`, and `provider.list_tools` are available.

## State management

| Method | Behavior |
|--------|----------|
| `snapshot(note="")` | Flushes hot buffer, saves full agent state to `hermes/snapshots/` |
| `restore()` | Flushes hot buffer, returns snapshot metadata dict |
| `resume()` | Calls `restore()` and records a `Resume` observation |

CLI equivalents: `hermes okf snapshot --note "..."` and `hermes okf restore`.

## System prompt block

`HermesOKFMemoryProvider.system_prompt_block()` returns static text informing the model that memory is persisted as OKF markdown at `~/.hermes/okf_memory/`. This supplements Hermes' native `MEMORY.md` / `USER.md` hot memory.

## Config wizard integration

`get_config_schema()` defines fields for `hermes memory setup`:

- `bundle_path` (default `~/.hermes/okf_memory`)
- `agent_id` (default `hermes-agent`)
- `auto_snapshot` (default `true`, choices `[True, False]`)

`save_config(values, hermes_home)` writes non-secret keys into `config.yaml` under the `memory` block and sets `memory.provider` to `hermes-okf`.

## Hook event reference

| Hermes event | Provider method | OKF output |
|--------------|-----------------|------------|
| Session start | `on_session_start` | `Session` concept, optional snapshot |
| Session end | `on_session_end` | Hot flush, end observation, optional snapshot |
| `memory(action="add", target="memory")` | `on_memory_write("memory", …)` | `Observation` via hot buffer |
| `memory(action="add", target="user")` | `on_memory_write("user", …)` | `UserProfile` concept |
| Tool invocation | `on_tool_call` | `Tool-Call` log entry + tool registry |
| Strategic choice | `on_decision` | `Decision` concept |
| Plan created | `on_plan_create` | `Plan` concept with checkable steps |
| Plan step done | `on_plan_step_complete` | Step marked `[x]`, progress updated |
| Plan finished | `on_plan_complete` | Plan archived, hot flush, snapshot |
| Turn completed | `sync_turn` | User profile update + tool call extraction |
| Pre-turn recall | `prefetch` | Top-5 search results as markdown context |

## Troubleshooting

| Symptom | Cause | Recovery |
|---------|-------|----------|
| Provider not loaded | Missing plugin directory or wrong `plugins.enabled` shape | Run `hermes-okf-install`; ensure `plugins.enabled` is a YAML list |
| Stale model in `config/agent` | Session not re-initialized after config change | Restart Hermes to re-run `initialize()` |
| `is_available()` returns false | `pyyaml` not installed | `pip install pyyaml` (core dependency) |
| Empty `prefetch` results | Bundle empty or query mismatch | Write concepts first; verify with `hermes okf search` |
| Assistant turns not in OKF | `"assistant"` target unmapped in `on_memory_write` | Route important assistant facts through `target="memory"` |

## Related pages

<CardGroup>
<Card title="Install Hermes plugin" href="/install-hermes-plugin">
Register via `hermes-okf-install`, configure `plugins.enabled`, and run `hermes memory setup`.
</Card>
<Card title="Two-memory model" href="/two-memory-model">
Hot `HotMemoryBuffer` vs cold OKF archive, flush triggers, and Hermes flat-memory mapping.
</Card>
<Card title="Configuration reference" href="/configuration-reference">
`HermesOKFConfig` fields, `HERMES_OKF_*` env vars, and resolution order.
</Card>
<Card title="Hermes CLI reference" href="/hermes-cli-reference">
`hermes okf` subcommands dispatched through `HermesOKFProvider`.
</Card>
<Card title="Python SDK reference" href="/python-sdk-reference">
`HermesAgent`, `get_provider()`, and exported public API.
</Card>
<Card title="Example: full agent" href="/example-full-agent">
End-to-end session, plan, tool, and snapshot workflow.
</Card>
</CardGroup>
