# Install on Hermes

> Hermes MemoryProvider install paths (Docker greenfield, install_hermes_memory_tencentdb.sh, symlink/copy), Gateway sidecar supervision, and config.yaml provider keys.

- Repository: TencentCloud/TencentDB-Agent-Memory
- GitHub: https://github.com/TencentCloud/TencentDB-Agent-Memory
- Human docs: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-14fefdd76c97
- Complete Markdown: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-14fefdd76c97/llms-full.txt

## Source Files

- `hermes-plugin/memory/memory_tencentdb/README.md`
- `hermes-plugin/memory/memory_tencentdb/__init__.py`
- `hermes-plugin/memory/memory_tencentdb/supervisor.py`
- `hermes-plugin/memory/memory_tencentdb/plugin.yaml`
- `scripts/install_hermes_memory_tencentdb.sh`
- `docker/opensource/Dockerfile.hermes`
- `docker/opensource/README-hermes.md`

---

---
title: "Install on Hermes"
description: "Hermes MemoryProvider install paths (Docker greenfield, install_hermes_memory_tencentdb.sh, symlink/copy), Gateway sidecar supervision, and config.yaml provider keys."
---

Hermes loads `memory_tencentdb` as a bundled `MemoryProvider` under `plugins/memory/memory_tencentdb/`. The Python package is a thin HTTP client plus process supervisor; capture, extraction, storage, and recall run in a Node.js Gateway sidecar (default `127.0.0.1:8420`) that hosts the same Core engine as the OpenClaw plugin.

```mermaid
flowchart TB
  subgraph hermes["Hermes Agent (Python)"]
    MM[MemoryManager]
    PROV["MemoryTencentdbProvider\nhermes-plugin/memory/memory_tencentdb/"]
    SUP[GatewaySupervisor]
    SDK[MemoryTencentdbSdkClient]
    MM --> PROV
    PROV --> SUP
    PROV --> SDK
  end

  subgraph gw["Gateway sidecar (Node.js)"]
    SRV["src/gateway/server.ts"]
    CORE[memory-tencentdb Core]
    L0[L0 conversations]
    L1[L1 atoms]
    L2[L2 scene blocks]
    L3[L3 persona]
    SRV --> CORE
    CORE --> L0
    CORE --> L1
    CORE --> L2
    CORE --> L3
  end

  SUP -->|"Popen + /health (≤30s)"| SRV
  SDK -->|"HTTP POST /recall /capture /search/* /session/end"| SRV
```

| Hermes lifecycle | Gateway | Behavior |
|---|---|---|
| `prefetch(query)` | `POST /recall` | Sync; injects `<memory-context>` text |
| `sync_turn(user, assistant)` | `POST /capture` | Background thread; max 4 in-flight |
| `shutdown` / `on_session_end` | `POST /session/end` | Flush pending pipeline work |
| `get_tool_schemas()` | — | Registers `memory_tencentdb_memory_search`, `memory_tencentdb_conversation_search` |

## Prerequisites

| Requirement | Notes |
|---|---|
| Hermes Agent installed | Bundled discovery path: `<hermes-agent>/plugins/memory/` |
| Node.js ≥ 22 | Gateway + `tsx` / `tsx/esm` launch |
| Directory name | Must be exactly `memory_tencentdb` (underscore), matching `plugin.yaml` `name` and `memory.provider` |
| LLM credentials | OpenAI-compatible endpoint for L1/L2/L3 (Gateway-side) |

Discovery requires `__init__.py` and `plugin.yaml` in the provider directory, and `__init__.py` must contain the literal string `MemoryProvider` or `register_memory_provider`.

## Choose an install path

<Tabs>
  <Tab title="Docker greenfield">

Single container: Hermes + npm package Gateway. No local repo checkout required.

```bash
docker build -f docker/opensource/Dockerfile.hermes -t hermes-memory .

docker run -d \
  --name hermes-memory \
  --restart unless-stopped \
  -p 8420:8420 \
  -e MODEL_API_KEY="your-api-key" \
  -e MODEL_BASE_URL="https://api.lkeap.cloud.tencent.com/v1" \
  -e MODEL_NAME="deepseek-v3.2" \
  -e MODEL_PROVIDER="custom" \
  -v hermes_data:/opt/data \
  hermes-memory
```

Image defaults bake Tencent Cloud DeepSeek-V3.2 for `MODEL_BASE_URL` / `MODEL_NAME` / `MODEL_PROVIDER`. You can pass only `MODEL_API_KEY` when using that endpoint.

**What the image does**

1. `npm install @tencentdb-agent-memory/memory-tencentdb@latest` under `/opt/tdai-gateway`
2. Official Hermes installer → `/usr/local/lib/hermes-agent/`
3. Symlink provider into Hermes bundled discovery:

```text
/usr/local/lib/hermes-agent/plugins/memory/memory_tencentdb
  → /opt/tdai-gateway/node_modules/@tencentdb-agent-memory/memory-tencentdb/hermes-plugin/memory/memory_tencentdb
```

4. On `CMD`: sync `MODEL_*` → `TDAI_LLM_*`, write `/opt/data/config.yaml` with `memory.provider: memory_tencentdb`, write `/opt/data/.env`, foreground-start Gateway on `:8420`

| Variable | Default | Role |
|---|---|---|
| `MODEL_API_KEY` | *(required at runtime)* | Shared LLM key for Hermes + Gateway |
| `MODEL_BASE_URL` | `https://api.lkeap.cloud.tencent.com/v1` | OpenAI-compatible base URL |
| `MODEL_NAME` | `deepseek-v3.2` | Model id |
| `MODEL_PROVIDER` | `custom` | Hermes model provider key |
| `TDAI_GATEWAY_PORT` | `8420` | Gateway listen port |
| `TDAI_GATEWAY_HOST` | `0.0.0.0` | Gateway bind address |
| `TDAI_DATA_DIR` | `/opt/data/tdai-memory` | L0–L3 data root |
| `HERMES_HOME` | `/opt/data` | Hermes config/session home |
| `MEMORY_TENCENTDB_GATEWAY_HOST` | `127.0.0.1` | Provider → Gateway host |
| `MEMORY_TENCENTDB_GATEWAY_PORT` | `8420` | Provider → Gateway port |

```bash
curl http://localhost:8420/health
docker exec -it hermes-memory hermes
```

  </Tab>
  <Tab title="install_hermes_memory_tencentdb.sh">

Host install after Hermes is already present (for example after `install_hermes_ubuntu.sh`).

```bash
# As the target user (recommended)
bash scripts/install_hermes_memory_tencentdb.sh

# Or as root for another user
INSTALL_AS_USER=ubuntu bash scripts/install_hermes_memory_tencentdb.sh
```

**Path defaults** (override with env):

| Variable | Default |
|---|---|
| `MEMORY_TENCENTDB_ROOT` | `~/.memory-tencentdb` |
| `TDAI_INSTALL_DIR` | `$MEMORY_TENCENTDB_ROOT/tdai-memory-openclaw-plugin` |
| `TDAI_DATA_DIR` | `$MEMORY_TENCENTDB_ROOT/memory-tdai` |
| `HERMES_AGENT_DIR` | `~/.hermes/hermes-agent` |
| `HERMES_HOME` | `~/.hermes` |

**Script steps**

1. **Step 0** — Migrate legacy `~/tdai-memory-openclaw-plugin` and `~/memory-tdai` into the new root (skip if both old and new exist; warn and keep new).
2. **Step 1** — `npm install @tencentdb-agent-memory/memory-tencentdb@latest` into a temp dir; copy package tree to `$TDAI_INSTALL_DIR`.
3. **Step 2** — `npm install --omit=dev` in install dir; ensure `tsx` available.
4. **Step 2.5** — Symlink provider:

```bash
ln -sf "$TDAI_INSTALL_DIR/hermes-plugin/memory/memory_tencentdb" \
       "$HERMES_AGENT_DIR/plugins/memory/memory_tencentdb"
```

5. **Step 3** — **Does not auto-enable** the provider. Prints the `config.yaml` snippet if `memory.provider` is not already `memory_tencentdb`.
6. **Step 4** — Writes Gateway launch env:
   - `/etc/profile.d/memory-tencentdb-env.sh` (interactive SSH)
   - `~/.hermes/.env` (systemd / `load_dotenv` path — authoritative for service-managed Hermes)

Resolved `MEMORY_TENCENTDB_GATEWAY_CMD` (absolute `node` path, no runtime PATH dependency):

```bash
sh -c 'cd $TDAI_INSTALL_DIR && exec "$NODE_BIN" --import tsx/esm src/gateway/server.ts'
```

  </Tab>
  <Tab title="Symlink or copy (dev)">

Source of truth in this repo: `hermes-plugin/memory/memory_tencentdb/`. Hermes does **not** load that path unless it is linked or copied under Hermes discovery.

**Install A — symlink (recommended while iterating)**

```bash
ln -s "$(pwd)/hermes-plugin/memory/memory_tencentdb" \
      <hermes-agent-checkout>/plugins/memory/memory_tencentdb
```

**Install B — copy (frozen vendored tree)**

```bash
cp -r hermes-plugin/memory/memory_tencentdb \
      <hermes-agent-checkout>/plugins/memory/memory_tencentdb
```

| Location | Precedence | Use |
|---|---|---|
| `<hermes-agent>/plugins/memory/<name>/` | Bundled (wins on name collision) | Ship path for `memory_tencentdb` |
| `$HERMES_HOME/plugins/<name>/` (default `~/.hermes/plugins/`) | User-installed | Third-party providers; not used by this package |

Gateway source (`src/gateway/`) stays in the npm/plugin checkout. The Python provider auto-discovers it or uses `MEMORY_TENCENTDB_GATEWAY_CMD`. Do not copy Gateway into hermes-agent.

  </Tab>
</Tabs>

## Enable in Hermes config

Edit `$HERMES_HOME/config.yaml` (default `~/.hermes/config.yaml`; Docker uses `/opt/data/config.yaml`):

```yaml
memory:
  provider: memory_tencentdb   # canonical
  # Aliases: memory-tencentdb, tdai
```

`plugin.yaml` metadata:

| Field | Value |
|---|---|
| `name` | `memory_tencentdb` |
| `display_name` | `memory-tencentdb` |
| `aliases` | `tdai`, `memory-tencentdb` |
| `hooks` | `on_memory_write` (reserved), `on_session_end` → `POST /session/end` |

Hyphenated `memory-tencentdb` is a **config alias only**, not a valid on-disk directory name.

## Gateway sidecar supervision

`GatewaySupervisor` (`supervisor.py`) owns process lifecycle. `MemoryTencentdbProvider.initialize()`:

1. Resolves host/port/api key and `MEMORY_TENCENTDB_GATEWAY_CMD` or auto-discovery.
2. Sets `_initialized = True` immediately so tools register even before health is green.
3. If `/health` already returns `ok` or `degraded`, attaches synchronously.
4. Otherwise starts the Gateway on a daemon thread (`tdai-gateway-init`) so Hermes `__init__` is not blocked up to 30s.
5. Starts a watchdog (~10s interval) that can re-spawn a dead supervised child.

### Start modes

| Mode | When | Mechanism |
|---|---|---|
| **Auto-discovery** | `MEMORY_TENCENTDB_GATEWAY_CMD` unset | Search for `src/gateway/server.ts`; launch via `sh -c 'cd <plugin-root> && exec pnpm exec tsx src/gateway/server.ts'` |
| **Explicit CMD** | Env set (install script writes this) | `Popen(shlex.split(cmd))`; env inherits Hermes process env |
| **External** | Gateway already listening | Health check only; no subprocess |

**Discovery order** (first existing file wins):

1. In-tree: `<plugin-root>/src/gateway/server.ts` (from provider path `parents[3]`)
2. `~/.memory-tencentdb/tdai-memory-openclaw-plugin/src/gateway/server.ts`
3. `~/tdai-memory-openclaw-plugin/src/gateway/server.ts` (legacy)
4. `~/.hermes/plugins/tdai-memory-openclaw-plugin/src/gateway/server.ts`

### Health and crash behavior

| Parameter | Value |
|---|---|
| Health poll interval | 0.5s |
| Startup max wait | 30s |
| Acceptable `/health` status | `ok`, `degraded` |
| Child logs | `gateway.stdout.log` / `gateway.stderr.log` under log dir |
| Default log dir | `MEMORY_TENCENTDB_LOG_DIR` → else `~/.hermes/logs/memory_tencentdb` |
| Crash diagnostics | Last ~2KB of stderr log on failed startup |
| Shutdown | SIGTERM, wait 10s, then SIGKILL |
| Process group | `start_new_session=True` (detached from Hermes PG) |

### Provider reliability knobs

| Mechanism | Behavior |
|---|---|
| Circuit breaker | 5 consecutive Gateway failures → pause calls 60s |
| Capture back-pressure | Max 4 in-flight `sync_turn` threads; 5th waits ≤5s on oldest |
| Recover cooldown | ≥15s between in-flight `ensure_running` retries |

### Optional ops control

After install, day-2 start/stop/config can use `scripts/memory-tencentdb-ctl.sh` with `--hermes` / `MEMORY_TENCENTDB_MODE=hermes` so LLM env lands under `$HERMES_HOME/env.d/` for supervised children. Full subcommands: [Gateway control](/gateway-control).

## Environment and provider keys

Provider config schema (`get_config_schema`) maps to env vars:

<ParamField body="gateway_cmd" type="string">
  Launch command. Env: `MEMORY_TENCENTDB_GATEWAY_CMD`. Optional if auto-discovery or external Gateway works.
</ParamField>

<ParamField body="gateway_host" type="string">
  Default `127.0.0.1`. Env: `MEMORY_TENCENTDB_GATEWAY_HOST`.
</ParamField>

<ParamField body="gateway_port" type="string">
  Default `8420` (validated 1..65535). Env: `MEMORY_TENCENTDB_GATEWAY_PORT`.
</ParamField>

<ParamField body="gateway_api_key" type="string" required>
  Optional client Bearer. Env: `MEMORY_TENCENTDB_GATEWAY_API_KEY` or `TDAI_GATEWAY_API_KEY`. Supervisor does **not** inject this into the child; set the same secret on the Gateway (`TDAI_GATEWAY_API_KEY` / `server.apiKey`) for enforcement.
</ParamField>

<ParamField body="llm_api_key" type="string" required>
  Gateway LLM key. Env: `MEMORY_TENCENTDB_LLM_API_KEY`. Required for L1/L2/L3.
</ParamField>

<ParamField body="llm_base_url" type="string">
  Default `https://api.openai.com/v1`. Env: `MEMORY_TENCENTDB_LLM_BASE_URL`.
</ParamField>

<ParamField body="llm_model" type="string">
  Default `gpt-4o`. Env: `MEMORY_TENCENTDB_LLM_MODEL`.
</ParamField>

### Data directory (Gateway-owned)

Resolved inside the Gateway, not the Python provider:

1. `TDAI_DATA_DIR`
2. `data.baseDir` in `tdai-gateway.yaml` / `tdai-gateway.json`
3. Default `~/.memory-tencentdb/memory-tdai` (parent overridable via `MEMORY_TENCENTDB_ROOT`)
4. Legacy fallback `~/memory-tdai` with deprecation warning if new path missing

`MEMORY_TENCENTDB_DATA_DIR` is **not** read. Hermes inherits env into the child, so exporting `TDAI_DATA_DIR` before Hermes is sufficient.

### Minimal host `.env` example

```bash
# ~/.hermes/.env (systemd / load_dotenv)
MEMORY_TENCENTDB_GATEWAY_CMD="sh -c 'cd /home/you/.memory-tencentdb/tdai-memory-openclaw-plugin && exec /usr/bin/node --import tsx/esm src/gateway/server.ts'"
MEMORY_TENCENTDB_GATEWAY_HOST="127.0.0.1"
MEMORY_TENCENTDB_GATEWAY_PORT="8420"
MEMORY_TENCENTDB_LLM_API_KEY="sk-..."
MEMORY_TENCENTDB_LLM_BASE_URL="https://api.openai.com/v1"
MEMORY_TENCENTDB_LLM_MODEL="gpt-4o"
```

## Verify install

```bash
# 1. Hermes discovers the provider
cd <hermes-agent-checkout>
python -c 'from plugins.memory import discover_memory_providers; \
           [print(n, a) for n, _, a in discover_memory_providers()]'
# expect: memory_tencentdb True

# 2. Gateway health
curl -s http://127.0.0.1:8420/health

# 3. Recall smoke (Docker or host)
curl -s -X POST http://127.0.0.1:8420/recall \
  -H "Content-Type: application/json" \
  -d '{"query":"test","session_key":"debug"}'
```

**Success signals**

| Signal | Where |
|---|---|
| `memory_tencentdb True` | `discover_memory_providers()` |
| Auto-discovery log | `memory-tencentdb Gateway command auto-discovered: …` in Hermes agent log |
| Gateway ready | `memory-tencentdb Gateway ready` / `already running` |
| Health | `status` is `ok` or `degraded` |
| Data tree | Under `TDAI_DATA_DIR` / `~/.memory-tencentdb/memory-tdai` |

## Troubleshooting

| Symptom | Check |
|---|---|
| Provider missing from discovery | Path is `…/plugins/memory/memory_tencentdb/` (underscore); `__init__.py` + `plugin.yaml` present |
| `memory-tencentdb Gateway not available` | CMD unset **and** discovery failed **and** nothing on `:8420`. Tail `~/.hermes/logs/memory_tencentdb/gateway.stderr.log` |
| Wrong checkout started | Set `MEMORY_TENCENTDB_GATEWAY_CMD` (always wins over discovery) |
| Tools missing from LLM | `get_tool_schemas()` returns `[]` until Gateway reachable **or** `MEMORY_TENCENTDB_GATEWAY_CMD` / `MEMORY_TENCENTDB_GATEWAY_PORT` set (optimistic register) |
| Circuit breaker tripped | Five failures; 60s pause; inspect Gateway health/logs |
| Capture backlog | ≥4 in-flight captures; look for stuck L1/LLM timeouts |
| systemd no auto-start | Put vars in `~/.hermes/.env`, not only `/etc/profile.d/` |
| Auth mismatches | Client key (`MEMORY_TENCENTDB_GATEWAY_API_KEY`) must match Gateway `TDAI_GATEWAY_API_KEY` / `server.apiKey` |

## Related pages

<CardGroup>
  <Card title="Host adapters" href="/host-adapters">
    TdaiCore boundary and Hermes Gateway adapter path versus OpenClaw.
  </Card>
  <Card title="Gateway HTTP API" href="/gateway-http-api">
    `/health`, `/recall`, `/capture`, search, `/session/end`, and auth fields.
  </Card>
  <Card title="Gateway control" href="/gateway-control">
    `memory-tencentdb-ctl` start/stop/status and hermes vs standalone modes.
  </Card>
  <Card title="Data directories" href="/data-directories">
    `MEMORY_TENCENTDB_ROOT` trees: conversations, records, vectors, persona.
  </Card>
  <Card title="Configure storage" href="/configure-storage">
    SQLite vs tcvdb and embedding settings for the Gateway.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Gateway circuit breaker, silent memory, and recovery probes.
  </Card>
</CardGroup>
