# Gateway lifecycle

> Operate the Node Gateway with memory-tencentdb-ctl: standalone vs hermes modes, start/stop/status/health/logs, config llm/embedding/vdb writes, and path layout under ~/.memory-tencentdb.

- 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-5a33bbf5540a
- Complete Markdown: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-5a33bbf5540a/llms-full.txt

## Source Files

- `scripts/README.memory-tencentdb-ctl.md`
- `scripts/memory-tencentdb-ctl.sh`
- `scripts/install_hermes_memory_tencentdb.sh`
- `src/gateway/server.ts`
- `src/gateway/config.ts`
- `hermes-plugin/memory/memory_tencentdb/supervisor.py`

---

---
title: "Gateway lifecycle"
description: "Operate the Node Gateway with memory-tencentdb-ctl: standalone vs hermes modes, start/stop/status/health/logs, config llm/embedding/vdb writes, and path layout under ~/.memory-tencentdb."
---

`memory-tencentdb-ctl` (`scripts/memory-tencentdb-ctl.sh`) is the operator entry for the standalone Node Gateway (`src/gateway/server.ts`). It starts and stops the HTTP sidecar on `127.0.0.1:8420` by default, writes credentials into `$TDAI_DATA_DIR/tdai-gateway.json` (mode `0600`), and optionally wires Hermes via `$HERMES_HOME` env fragments and `config.yaml`. The script is **not** registered as an npm `bin`; invoke it from the package path or symlink it to your `PATH`.

## Modes

| Mode | Activate | Writes | Does not touch |
|------|----------|--------|----------------|
| `standalone` (default) | no flag, or `--standalone` / `MEMORY_TENCENTDB_MODE=standalone` | Gateway lifecycle; `$TDAI_DATA_DIR/tdai-gateway.json`; logs under `$TDAI_DATA_DIR/logs/` | `$HERMES_HOME/env.d/`, `$HERMES_HOME/config.yaml` |
| `hermes` | `--hermes` or `MEMORY_TENCENTDB_MODE=hermes` | Everything standalone does, plus `config llm` → `$HERMES_HOME/env.d/memory-tencentdb-llm.sh`; logs under `$HERMES_HOME/logs/memory_tencentdb/`; `enable-hermes-memory` | — |

Hermes mode exists because Hermes spawns the Gateway with `os.environ.copy()`. LLM secrets must be present in the parent shell (via `$HERMES_HOME/env.d/*.sh`), not only in `tdai-gateway.json`. Embedding and VDB config are written only to JSON in both modes.

```mermaid
flowchart TB
  subgraph ctl ["memory-tencentdb-ctl"]
    start["start / stop / restart"]
    status["status / health / logs"]
    cfg["config llm | embedding | vdb | vdb-off | show"]
  end
  subgraph root ["~/.memory-tencentdb"]
    install["tdai-memory-openclaw-plugin/"]
    data["memory-tdai/"]
    json["memory-tdai/tdai-gateway.json"]
    slog["memory-tdai/logs/  (standalone)"]
  end
  subgraph hermes_home ["~/.hermes  (hermes mode only)"]
    envd["env.d/memory-tencentdb-llm.sh"]
    hlogs["logs/memory_tencentdb/"]
    hyaml["config.yaml memory.provider"]
  end
  gw["Node TdaiGateway :8420"]
  sup["GatewaySupervisor ensure_running"]
  start --> gw
  cfg --> json
  cfg -->|config llm + hermes| envd
  gw --> data
  sup -->|spawn MEMORY_TENCENTDB_GATEWAY_CMD| gw
  envd -->|source into hermes env| sup
```

## Path layout

Canonical root since 0.4.x: `$MEMORY_TENCENTDB_ROOT` → `~/.memory-tencentdb`.

| Path | Role |
|------|------|
| `$MEMORY_TENCENTDB_ROOT` | Unified root (default `~/.memory-tencentdb`) |
| `$TDAI_INSTALL_DIR` | Plugin checkout + `node_modules` + `src/gateway/server.ts` (default `$MEMORY_TENCENTDB_ROOT/tdai-memory-openclaw-plugin`) |
| `$TDAI_DATA_DIR` | Gateway data `baseDir` (default `$MEMORY_TENCENTDB_ROOT/memory-tdai`) |
| `$TDAI_DATA_DIR/tdai-gateway.json` | Primary config: top-level `llm`, nested `memory.embedding` / `memory.tcvdb` / `memory.storeBackend`; written at `0600` |
| `$TDAI_DATA_DIR/logs/` | standalone: `gateway.pid`, `gateway.stdout.log`, `gateway.stderr.log` |
| `$HERMES_HOME/logs/memory_tencentdb/` | hermes mode log/pid location |
| `$HERMES_HOME/env.d/memory-tencentdb-llm.sh` | hermes-only LLM env for supervisor inheritance |
| `$HERMES_HOME/config.yaml` | `enable-hermes-memory` sets `memory.provider: memory_tencentdb` |

Override with: `MEMORY_TENCENTDB_ROOT`, `TDAI_INSTALL_DIR`, `TDAI_DATA_DIR`, `HERMES_HOME`, `MEMORY_TENCENTDB_LOG_DIR`, `MEMORY_TENCENTDB_GATEWAY_HOST`, `MEMORY_TENCENTDB_GATEWAY_PORT`.

Legacy top-level `~/tdai-memory-openclaw-plugin` and `~/memory-tdai` are still detected. `install_hermes_memory_tencentdb.sh` migrates them; `memory-tencentdb-ctl` only warns. The Gateway process falls back to legacy `~/memory-tdai` if the new data dir is missing.

:::files
~/.memory-tencentdb/
├── tdai-memory-openclaw-plugin/   # TDAI_INSTALL_DIR
│   └── src/gateway/server.ts
└── memory-tdai/                   # TDAI_DATA_DIR
    ├── tdai-gateway.json          # 0600
    ├── logs/                      # standalone pid + stdout/stderr
    ├── conversations/             # L0 runtime data
    ├── records/                   # L1
    └── ...
~/.hermes/                         # hermes mode only
├── config.yaml
├── env.d/memory-tencentdb-llm.sh
└── logs/memory_tencentdb/
:::

## Install and invoke

Dependencies: `bash`, `python3`, `node` ≥ 22, `npx`, and `lsof` or `ss`.

Deploy the install tree first (Hermes greenfield path):

```bash
bash scripts/install_hermes_memory_tencentdb.sh
```

That script packs `@tencentdb-agent-memory/memory-tencentdb` into `$TDAI_INSTALL_DIR`, runs `npm install`, and writes `MEMORY_TENCENTDB_GATEWAY_CMD` (absolute `node --import tsx/esm src/gateway/server.ts`) plus host/port into `/etc/profile.d/memory-tencentdb-env.sh` and `$HERMES_HOME/.env`.

Call the ctl without a global bin:

```bash
"$(npm root -g)/@tencentdb-agent-memory/memory-tencentdb/scripts/memory-tencentdb-ctl.sh" --help
# or from a clone:
./scripts/memory-tencentdb-ctl.sh --help
```

Optional symlink for ops:

```bash
SCRIPT="$(npm root -g)/@tencentdb-agent-memory/memory-tencentdb/scripts/memory-tencentdb-ctl.sh"
sudo ln -sf "$SCRIPT" /usr/local/bin/memory-tencentdb-ctl
```

## Lifecycle commands

```bash
memory-tencentdb-ctl start
memory-tencentdb-ctl stop
memory-tencentdb-ctl restart
memory-tencentdb-ctl status
memory-tencentdb-ctl health
memory-tencentdb-ctl logs            # tail -f stdout + stderr
memory-tencentdb-ctl logs err 500    # stderr only, last 500 lines then follow
```

### start

1. `source` `/etc/profile.d/memory-tencentdb-env.sh` (both modes). Hermes mode also sources `/etc/profile.d/hermes-env.sh` and `$HERMES_HOME/env.d/*.sh`.
2. If something already listens on `$GATEWAY_PORT`, exit success with a warning.
3. Resolve command: `MEMORY_TENCENTDB_GATEWAY_CMD` if set, else  
   `sh -c 'cd $TDAI_INSTALL_DIR && exec npx tsx src/gateway/server.ts'`.
4. Spawn with `setsid nohup` (or `nohup`), append to stdout/stderr logs, write wrapper PID to `gateway.pid`.
5. Poll up to ~15s for listen + `GET /health`.

### stop / restart

Stop finds the listener PID(s) on the configured port, sends `SIGTERM`, waits ~5s, then `SIGKILL` if needed, and removes `gateway.pid`. Restart is stop + short sleep + start.

### status

Prints mode, host:port, install/data/log/config paths, `RUNNING`/`STOPPED`, and health. Hermes mode also shows `memory.provider` from `config.yaml` and `env.d/*.sh` listing.

### health

`GET http://$GATEWAY_HOST:$GATEWAY_PORT/health` via `python3` + `urllib` (no `curl` required). Gateway response shape:

```json
{
  "status": "ok",
  "version": "0.1.0",
  "uptime": 12,
  "stores": {
    "vectorStore": true,
    "embeddingService": true
  }
}
```

`status` is `"ok"` when a vector store is present, otherwise `"degraded"`. Hermes `GatewaySupervisor` treats both `"ok"` and `"degraded"` as ready.

### logs

`tail -n N -f` on stdout, stderr, or both (`all` default, `N` default 200).

## Config writes

All config subcommands merge into `$TDAI_DATA_DIR/tdai-gateway.json` with atomic temp-file + rename and mode `0600`. Use `--restart` to recycle the process after a write. Prefix with `--dry-run` to print intended content without writing.

### LLM

```bash
memory-tencentdb-ctl config llm \
  --api-key "sk-..." \
  --base-url "https://api.openai.com/v1" \
  --model "gpt-4o" \
  --restart
```

| Flag | Required | Notes |
|------|----------|-------|
| `--api-key` | yes | |
| `--base-url` | yes | must start with `http://` or `https://` |
| `--model` | yes | |
| `--restart` | no | restart Gateway after write |

JSON: top-level `llm.{baseUrl,apiKey,model}`.

Hermes mode **also** writes `$HERMES_HOME/env.d/memory-tencentdb-llm.sh`:

```bash
export TDAI_LLM_BASE_URL=...
export TDAI_LLM_API_KEY=...
export TDAI_LLM_MODEL=...
export MEMORY_TENCENTDB_LLM_BASE_URL="$TDAI_LLM_BASE_URL"
export MEMORY_TENCENTDB_LLM_API_KEY="$TDAI_LLM_API_KEY"
export MEMORY_TENCENTDB_LLM_MODEL="$TDAI_LLM_MODEL"
```

### Embedding

Default in plugin config is effectively off (`provider=none` / keyword-only). Enable an OpenAI-compatible provider:

```bash
memory-tencentdb-ctl config embedding \
  --provider openai \
  --api-key "sk-..." \
  --base-url "https://api.openai.com/v1" \
  --model "text-embedding-3-small" \
  --dimensions 1536 \
  --restart

memory-tencentdb-ctl config embedding --provider none --restart
```

| Flag | Required | Notes |
|------|----------|-------|
| `--provider` | yes | `none` disables; otherwise e.g. `openai`, `deepseek`, `qclaw` |
| `--api-key` / `--base-url` / `--model` / `--dimensions` | yes if not `none` | dimensions must be a positive integer |
| `--proxy-url` | for `qclaw` | required when provider is `qclaw` |
| `--restart` | no | |

JSON: `memory.embedding.{provider,baseUrl,apiKey,model,dimensions,enabled,proxyUrl?}`.

### VectorDB (tcvdb)

```bash
memory-tencentdb-ctl config vdb \
  --url "http://xxx-vdb.example:8100" \
  --username root \
  --api-key "YOUR-VDB-API-KEY" \
  --database "openclaw_memory" \
  --alias "primary" \
  --embedding-model "bge-large-zh" \
  --ca-pem "/etc/ssl/vdb-ca.pem" \
  --restart
```

| Flag | Required | Notes |
|------|----------|-------|
| `--url` | yes | `http(s)://…` |
| `--api-key` | yes | |
| `--database` | yes | |
| `--username` | no | default `root` |
| `--alias` | no | |
| `--embedding-model` | no | server-side embedding model name |
| `--ca-pem` | no | path only; file must be readable; not copied |
| `--no-set-backend` | no | keep current `storeBackend`; default sets `memory.storeBackend` to `tcvdb` |
| `--restart` | no | |

JSON: `memory.tcvdb.{url,username,apiKey,database,alias?,caPemPath?,embeddingModel?}`.

### Fall back to SQLite

```bash
memory-tencentdb-ctl config vdb-off --restart
memory-tencentdb-ctl config vdb-off --purge-creds --restart
```

Sets `memory.storeBackend` to `sqlite`. Default keeps `memory.tcvdb` credentials for later re-enable; `--purge-creds` deletes the whole `tcvdb` object. Does **not** change Hermes `memory.provider`.

### Inspect config

```bash
memory-tencentdb-ctl config show
```

Prints redacted JSON (`apiKey` / `password` / `token` → `<redacted:N chars>`). Hermes mode also dumps `memory-tencentdb-*.sh` with keys redacted.

## Hermes wiring

```bash
memory-tencentdb-ctl --hermes enable-hermes-memory
```

Idempotently sets `$HERMES_HOME/config.yaml` → `memory.provider: memory_tencentdb` without rewriting the whole YAML:

1. Prefer `ruamel.yaml` round-trip (comments/order preserved).
2. Else minimal in-place `provider:` line edit.
3. Else append a minimal `memory:` block.

Fails in standalone mode. After enable:

```bash
source "$HERMES_HOME/env.d/memory-tencentdb-llm.sh"
# restart hermes so supervisor re-reads env and config
```

`GatewaySupervisor` (Hermes plugin) calls `ensure_running()`: health-check first; if down, spawn `MEMORY_TENCENTDB_GATEWAY_CMD`, wait up to 30s for `/health` `ok`|`degraded`, log under `MEMORY_TENCENTDB_LOG_DIR` or `~/.hermes/logs/memory_tencentdb/`. On shutdown it `SIGTERM`s its own child (10s then `SIGKILL`). It does **not** inject `TDAI_GATEWAY_API_KEY` into the child; server auth is operator-owned.

## Gateway process config resolution

`loadGatewayConfig()` resolution order for the config file:

1. `TDAI_GATEWAY_CONFIG` explicit path  
2. `./tdai-gateway.yaml` or `./tdai-gateway.json` in CWD  
3. `<dataDir>/tdai-gateway.yaml` or `tdai-gateway.json`  
4. env-only defaults  

| Concern | Env (Node Gateway) | Default |
|---------|--------------------|---------|
| Bind host/port | `TDAI_GATEWAY_HOST` / `TDAI_GATEWAY_PORT` | `127.0.0.1` / `8420` |
| API key | `TDAI_GATEWAY_API_KEY` | unset (auth off; `/health` always open) |
| CORS | `TDAI_CORS_ORIGINS` | empty (no CORS headers) |
| Data dir | `TDAI_DATA_DIR` | `$MEMORY_TENCENTDB_ROOT/memory-tdai` |
| LLM | `TDAI_LLM_BASE_URL` / `TDAI_LLM_API_KEY` / `TDAI_LLM_MODEL` | OpenAI-compatible defaults; empty key until configured |

Ctl / Hermes client address the same port via `MEMORY_TENCENTDB_GATEWAY_HOST` / `MEMORY_TENCENTDB_GATEWAY_PORT` (defaults also `127.0.0.1:8420`). Keep both sides aligned if you change the port.

## Typical workflows

### Standalone Gateway

```bash
bash scripts/install_hermes_memory_tencentdb.sh   # or install tree already present
memory-tencentdb-ctl config llm --api-key "sk-..." --base-url "https://api.openai.com/v1" --model gpt-4o
memory-tencentdb-ctl config embedding --provider openai --api-key "sk-..." \
  --base-url "https://api.openai.com/v1" --model text-embedding-3-small --dimensions 1536
# optional:
# memory-tencentdb-ctl config vdb --url "http://..." --api-key "..." --database openclaw_memory
memory-tencentdb-ctl start
memory-tencentdb-ctl status
memory-tencentdb-ctl health
```

### Hermes-integrated

```bash
export MEMORY_TENCENTDB_MODE=hermes   # optional sticky mode
memory-tencentdb-ctl --hermes config llm --api-key "sk-..." --base-url "https://api.openai.com/v1" --model gpt-4o --restart
memory-tencentdb-ctl --hermes enable-hermes-memory
memory-tencentdb-ctl --hermes start   # manual fallback; supervisor usually owns spawn
memory-tencentdb-ctl --hermes status
```

### Temporary SQLite while Hermes stays on `memory_tencentdb`

```bash
memory-tencentdb-ctl config vdb-off --restart
# later re-declare vdb (required fields must be supplied again):
memory-tencentdb-ctl config vdb --url "http://..." --api-key "..." --database openclaw_memory --restart
```

Do not change Hermes `memory.provider` only to switch storage; backend is Gateway-internal.

## Exit codes and ops notes

| Code | Meaning |
|------|---------|
| `0` | success |
| `1` | bad args / validation (e.g. non-http base URL; hermes-only cmd in standalone) |
| `2` | write failure |
| `127` | missing dependency (`python3` / `node` / `npx`) |

- Sensitive files are `0600`. Never commit `env.d/memory-tencentdb-llm.sh`.
- Startup failures: `memory-tencentdb-ctl logs err 200`, or foreground:  
  `cd "$TDAI_INSTALL_DIR" && npx tsx src/gateway/server.ts`  
  (or the absolute `node --import tsx/esm` command from install).
- Port conflict: `MEMORY_TENCENTDB_GATEWAY_PORT=18420 memory-tencentdb-ctl restart` and set matching `TDAI_GATEWAY_PORT` for the Node process.
- systemd: wrap `start`/`stop` as `Type=forking` if needed; the Gateway is a stateless HTTP sidecar without a custom readiness protocol beyond `/health`.

## Related pages

<CardGroup>
  <Card title="Hermes setup" href="/hermes-setup">
    Install path, Docker greenfield, auto-discovery, and health verification with Hermes.
  </Card>
  <Card title="Secure the Gateway" href="/secure-gateway">
    Bearer auth, CORS allow-list, non-loopback warnings, client key alignment.
  </Card>
  <Card title="Gateway HTTP API" href="/gateway-http-api">
    Routes: /health, /recall, /capture, search, /session/end, /seed.
  </Card>
  <Card title="Environment variables" href="/environment-variables">
    Full TDAI_* / MEMORY_TENCENTDB_* resolution and client vs server key names.
  </Card>
  <Card title="CLI reference" href="/cli-reference">
    Package bins plus memory-tencentdb-ctl subcommand inventory.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Auth 401, circuit breaker, embedding failures, and log/probe checklist.
  </Card>
</CardGroup>
