# Phase 5: Hindsight Memory Provider — Research **Researched:** 2026-06-14 **Domain:** Cross-session persistent memory provider (Hermes plugin) **Confidence:** HIGH ## Summary Phase 5 activates Hindsight as the external memory provider for ngn-agent, replacing the limited built-in MEMORY.md/USER.md with entity-aware knowledge graph memory that persists across sessions. This is a pure configuration change — no code, no new infrastructure. Hindsight runs in **local_embedded** mode: Hermes manages a local Hindsight daemon with embedded PostgreSQL for persistence. LLM extraction of memories uses the existing OpenRouter API key (model: `qwen/qwen3.5-9b`). Embeddings and reranking are local — no additional API keys needed. **Primary recommendation:** Install `hindsight-all` via uv into the Hermes venv, create latency-optimized `~/.hermes/hindsight/config.json` with `recall_budget: low`, `retain_every_n_turns: 5`, and `retain_async: true`, add `HINDSIGHT_LLM_API_KEY` to `~/.hermes/.env` reusing the existing OpenRouter key, then set `memory.provider: hindsight` via `hermes config set`. The `~/.hindsight/profiles/hermes.env` for the embedded daemon is already pre-configured from a previous setup attempt. **Estimated effort:** ~25 minutes including dependency installation and verification. ## User Constraints (from CONTEXT.md) ### Locked Decisions - **D-01:** Use **local embedded** mode — Hermes spins up a local PostgreSQL daemon. No external data send. Use existing OpenRouter API key (`OPENROUTER_API_KEY` in `~/.hermes/.env`) for LLM extraction via `HINDSIGHT_LLM_API_KEY`. - Config: `mode: local_embedded` in `~/.hermes/hindsight/config.json` - Env: `HINDSIGHT_LLM_API_KEY=sk-or-v1-...` (same as existing OpenRouter key) - Provider: `openrouter` with model per-provider default (`qwen/qwen3.5-9b`) - **D-02:** Use **default (hybrid)** mode — auto-inject relevant memories before each turn + expose all 3 hindsight tools (hindsight_retain, hindsight_recall, hindsight_reflect) - Config: `memory_mode: hybrid` (default) - **D-03:** No migration from built-in memory. MEMORY.md/USER.md continues as fallback in parallel. - **D-04:** `recall_budget: low` — fastest retrieval, minimal latency overhead per turn - **D-05:** `recall_prefetch_method: recall` — raw fact search (no LLM synthesis in hot path) - **D-06:** `auto_recall: true` — auto-inject context before each turn - **D-07:** `recall_types: observation` — default (observations only, denser per token) - **D-08:** `retain_async: true` — processing happens in background, never blocks agent loop - **D-09:** `retain_every_n_turns: 5` — extract memories every 5 turns instead of every turn - **D-10:** `auto_retain: true` — automatic retention active ### the agent's Discretion - **Bank configuration** (`bank_id`, `bank_mission`, `bank_retain_mission`): Use defaults (`bank_id: hermes`, no missions). - **Daemon startup logs and runtime monitoring**: Standard Hermes daemon management applies. ### Deferred Ideas (OUT OF SCOPE) None — no deferred items for this phase. ## Phase Requirements | ID | Description | Research Support | |----|-------------|------------------| | MEM-01 | Hindsight memory provider enabled for cross-session entity-aware recall | All dependencies, configuration paths, and latency-optimized settings documented below. Verification steps provided. | ## Architectural Responsibility Map | Capability | Primary Tier | Secondary Tier | Rationale | |------------|-------------|----------------|-----------| | Cross-session memory storage | Local daemon (Hindsight embedded) | — | Hindsight daemon runs locally with embedded PostgreSQL; no external services | | Memory extraction (LLM) | OpenRouter API | — | Existing OpenRouter key reused; daemon calls OpenRouter for entity extraction | | Memory recall injection | Hermes agent loop (pre-turn hook) | — | Hindsight plugin injects relevant memories into context before each LLM turn via `queue_prefetch()` | | Memory retain (background) | Hermes agent loop (post-turn) | Local daemon | `sync_turn()` enqueues retains on a background writer thread; daemon processes asynchronously | | Tool-based memory access | Hermes agent (LLM chooses tools) | — | `hindsight_recall`, `hindsight_retain`, `hindsight_reflect` tools exposed to agent | | Built-in memory fallback | Hermes agent loop | — | MEMORY.md/USER.md remains always active as a parallel fallback | | Memory provider selection | Hermes config (`memory.provider`) | — | Single-source-of-truth config change; Hermes ensures only one external provider | ## Standard Stack ### Core | Library | Version | Purpose | Why Standard | |---------|---------|---------|--------------| | `hindsight-all` | 0.8.2 | Full Hindsight embedded stack (daemon + client + API) | Bundled as Hermes plugin dependency; provides `hindsight-embed` daemon binary in Hermes venv; confirmed installed via uv | | `hindsight-client` | 0.8.2 | Python client library for Hindsight API | Hermes plugin `__init__.py` imports from `hindsight_client`; dependency of `hindsight-all` | | `OPENROUTER_API_KEY` | existing | LLM extraction for memory entities | Already in `~/.hermes/.env`; reused as `HINDSIGHT_LLM_API_KEY` (D-01) | ### Supporting | Library | Version | Purpose | When to Use | |---------|---------|---------|-------------| | `hindsight-embed` | 0.8.2 | Local embedded daemon (PostgreSQL + API server) | Auto-started by Hermes on first session access; handled by plugin's daemon manager | | `uv` | 0.11.19 | Python package manager | Already installed at `~/.local/bin/uv`; used by `hermes memory setup` and manual install | ### Alternatives Considered | Instead of | Could Use | Tradeoff | |------------|-----------|----------| | `hindsight-all` (local_embedded) | `hindsight-client` only (cloud mode) | Local mode requires ~200MB download and has ~2-4GB RAM overhead but zero external data send and no cloud dependency | | OpenRouter for LLM extraction | Direct Anthropic/Gemini API key | OpenRouter key already exists; no additional credential management needed | | `hermes memory setup` (wizard) | Manual config.json + env | Wizard is interactive (curses); manual approach is faster for automation but requires precise config file creation | **Installation:** ```bash # Install the full Hindsight embedded stack into Hermes venv uv pip install --python ~/.hermes/hermes-agent/venv/bin/python hindsight-all ``` **Version verification:** Both `hindsight-all` and `hindsight-client` resolve to version 0.8.2 [VERIFIED: installed via uv, confirmed in venv]. ## Package Legitimacy Audit > Required: this phase installs external packages. | Package | Registry | Age | Downloads | Source Repo | Verdict | Disposition | |---------|----------|-----|-----------|-------------|---------|-------------| | `hindsight-all` | PyPI (via uv) | ~1yr | Unknown | [github.com/vectorize-io/hindsight](https://github.com/vectorize-io/hindsight) | OK | Approved — Hermes v0.16.0 bundles Hindsight plugin; package is the official embedded distribution from Vectorize.io | | `hindsight-client` | PyPI (via uv) | ~1yr | Unknown | [github.com/vectorize-io/hindsight](https://github.com/vectorize-io/hindsight) | OK | Approved — dependency of `hindsight-all`, listed in Hermes pyproject.toml extras | | `hindsight-embed` | PyPI (via uv) | ~1yr | Unknown | [github.com/vectorize-io/hindsight](https://github.com/vectorize-io/hindsight) | OK | Approved — dependency of `hindsight-all` | | `hindsight-api-slim` | PyPI (via uv) | ~1yr | Unknown | [github.com/vectorize-io/hindsight](https://github.com/vectorize-io/hindsight) | OK | Approved — dependency of `hindsight-all` | **Packages removed due to [SLOP] verdict:** none **Packages flagged as suspicious [SUS]:** none **Postinstall scripts check:** None of these packages have `postinstall` scripts [VERIFIED: `npm view` not applicable — Python packages. Checked via `uv pip show` — no postinstall field.]. ## Architecture Patterns ### System Architecture Diagram ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ Hermes Agent Process │ │ │ │ ┌────────────────────────────┐ ┌──────────────────────────────────┐ │ │ │ MemoryManager │ │ HindsightMemoryProvider │ │ │ │ (orchestrates providers) │───▶│ (MemoryProvider ABC impl) │ │ │ │ │ │ │ │ │ │ ┌─────────────────────┐ │ │ ┌───────────────────────────┐ │ │ │ │ │ Built-in Memory │ │ │ │ Retain Queue (per-session)│ │ │ │ │ │ (MEMORY.md/USER.md) │ │ │ └───────────┬───────────────┘ │ │ │ │ │ always active │ │ │ │ writer thread │ │ │ │ └─────────────────────┘ │ │ ▼ │ │ │ └────────────────────────────┘ │ ┌───────────────────────────┐ │ │ │ │ │ Prefetch Thread │ │ │ │ ┌────────────────────────────┐ │ │ (async recall per turn) │ │ │ │ │ Agent Loop (per turn) │ │ └───────────┬───────────────┘ │ │ │ │ │ │ │ │ │ │ │ 1. queue_prefetch(query)──┼────┼──────────────┘ │ │ │ │ 2. prefetch() → inject ──┼────┼───────────────► context injection │ │ │ │ 3. LLM turn │ │ │ │ │ │ 4. sync_turn(turn) ──────┼────┼───────────────► enqueue retain │ │ │ └────────────────────────────┘ └───────────────┬───────────────────┘ │ │ │ │ │ ┌──────────────────────────────────────────────────┼──────────────┐ │ │ │ Background Threads │ │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ │ │ Hindsight Embedded Daemon (localhost:9177) │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ │ │ PostgreSQL │ │ Embeddings │ │ Reranker │ │ │ │ │ │ │ │ (embedded │ │ (local BGE │ │ (local cross-│ │ │ │ │ │ │ │ pg0) │ │ small-en) │ │ encoder) │ │ │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ └──────────────────────────┬─────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ │ │ OpenRouter API (external) │ │ │ │ │ │ LLM extraction: qwen/qwen3.5-9b via OpenRouter │ │ │ │ │ │ Model per-provider default from plugin __init__.py │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ ▲ │ ┌──────────────────────┴──────────────────────┐ │ Hindsight Tools (hybrid mode) │ │ hindsight_retain │ hindsight_recall │ │ hindsight_reflect │ │ └─────────────────────────────────────────────┘ ``` ### Data Flow 1. **Session start → Daemon auto-start**: Plugin `initialize()` launches embedded daemon in a background thread. The daemon process runs on `localhost:9177` with embedded PostgreSQL. 2. **Pre-turn recall**: Agent loop calls `queue_prefetch(query)` → background thread calls `client.arecall()` with `budget=low`, `method=recall` → results cached → `prefetch()` injects into context preamble. 3. **Post-turn retain**: Agent loop calls `sync_turn(user_msg, assistant_msg)` → turn appended to `_session_turns` → every 5th turn (D-09) enqueues a retain job → writer thread calls `client.aretain_batch()` asynchronously. 4. **Tool use**: Agent can call `hindsight_recall`, `hindsight_retain`, `hindsight_reflect` directly — these execute synchronously via `_run_sync()`. 5. **Idle shutdown**: Daemon auto-stops after `idle_timeout: 300` seconds of inactivity (D-08 means retains are async but daemon stays alive for background processing). ### Recommended Project Structure ``` ~/.hermes/ ├── hindsight/ │ └── config.json # Hindsight configuration (latency-optimized) ├── hermes-agent/ │ └── venv/ │ ├── bin/ │ │ └── hindsight-embed # Daemon binary (auto-installed) │ └── lib/python3.11/site-packages/ │ ├── hindsight_client/ # Python client library │ ├── hindsight_embed/ # Daemon management │ └── hindsight_api_slim/ # API server ├── logs/ │ └── hindsight-embed.log # Daemon startup logs ├── .env # Add HINDSIGHT_LLM_API_KEY here └── config.yaml # Set memory.provider: hindsight ~/.hindsight/ ├── profiles/ │ ├── hermes.env # Daemon LLM config (already exists, pre-configured) │ ├── hermes.lock # Daemon lock file │ └── hermes.log # Daemon runtime logs └── config.json # Legacy fallback (optional) ``` ### Pattern 1: Non-Interactive Memory Provider Setup **What:** Skip the interactive `hermes memory setup` wizard by manually creating config files and setting config values. The wizard uses curses and prompts for values we already know. **When to use:** Automation/scripted setup, repeatable provisioning. **Steps:** 1. Install packages into Hermes venv 2. Create `~/.hermes/hindsight/config.json` 3. Add env var to `~/.hermes/.env` 4. Set config value in `~/.hermes/config.yaml` **Source:** [VERIFIED: hermes-cli/memory_setup.py and plugins/memory/hindsight/__init__.py — both support post_setup wizard OR manual config] ### Pattern 2: Latency-optimized Memory Profile **What:** Hindsight's config supports three latency tiers for recall (`low`/`mid`/`high`). The `low` budget returns fewer results faster. Combined with `recall` (not `reflect`) prefetch and `retain_every_n_turns: 5`, this minimizes per-turn overhead. **When to use:** Production deployments where every millisecond of agent latency matters. ### Anti-Patterns to Avoid - **Setting `memory.provider` to two external providers:** `MemoryManager.add_provider()` silently rejects the second one with only a log warning. Only one external provider can be active. - **Disabling built-in memory:** Built-in MEMORY.md/USER.md continues as fallback. No config removes it. Trying to disable it has no effect. - **Using cloud mode instead of local_embedded:** Requires Hindsight Cloud API key; sends data externally. Phase already decided local_embedded. ## Don't Hand-Roll | Problem | Don't Build | Use Instead | Why | |---------|-------------|-------------|-----| | Custom memory provider | Python ABC impl of MemoryProvider | Hindsight plugin (bundled in Hermes v0.16.0) | Production-ready, entity-aware KG, multi-strategy retrieval, already integrated | | Custom daemon management | Systemd/launchd for PostgreSQL | Hermes-managed embedded daemon | Plugin auto-starts/stops daemon; handles idle timeout, profile env, restart on config change | | Custom memory migration script | Script to move MEMORY.md → hindsight | Skip (D-03: parallel systems) | Hindsight builds its own KG from new sessions; old data remains in MEMORY.md as fallback | | Custom entity extraction | LLM prompt for entity parsing | Hindsight auto-extraction | Plugin already handles entity resolution, deduplication, and knowledge graph construction server-side | **Key insight:** Hindsight is production-ready, bundled in Hermes, and the plugin handles daemon lifecycle, LLM extraction, and entity management. Every custom solution in this domain would be slower, buggier, and less feature-complete. ## Common Pitfalls ### Pitfall 1: Memory Provider Conflict **What goes wrong:** Setting two external memory providers (e.g., Hindsight + Honcho) silently fails — only the first is registered. User thinks both are active but only one works. **Why it happens:** `MemoryManager.add_provider()` (agent/memory_manager.py:342-354) explicitly rejects a second external provider with a warning log. **How to avoid:** Set `memory.provider: hindsight` only. Never add a second external provider. **Warning signs:** `hermes memory list` shows only one provider. Grep logs for "Rejected memory provider." ### Pitfall 2: Async Retain Silent Failure **What goes wrong:** Hindsight API fails during `aretain_batch()` but the error is swallowed — only logged as a warning. Agent thinks it saved facts but they never persisted. **Why it happens:** `sync_turn()` enqueues to a background writer thread (`memory_manager.py:115-131`). Failures are logged, not surfaced to agent. **How to avoid:** Monitor `~/.hermes/hermes-agent/logs/` for "Hindsight retain failed" warnings. Use `grep "Hindsight retain failed"` in monitoring. **Warning signs:** Agent can't recall facts it previously discussed. ### Pitfall 3: Daemon Startup Failure **What goes wrong:** The embedded daemon fails to start on first session access, causing all hindsight operations to fail. **Why it happens:** Missing/incomplete `hindsight-all` installation, port conflict, or incompatible Python version. The startup happens in a background thread and logs to `~/.hermes/logs/hindsight-embed.log`. **How to avoid:** Verify `hindsight-all` is installed in the correct venv. Check `~/.hermes/logs/hindsight-embed.log` after first session start. **Warning signs:** `hermes memory status` shows hindsight as "not available." Session logs contain "Hindsight local mode disabled" warnings. ### Pitfall 4: OpenRouter API Key Format **What goes wrong:** The `HINDSIGHT_LLM_API_KEY` env var uses the wrong key format for OpenRouter, causing LLM extraction to fail and memories not to be created. **Why it happens:** OpenRouter keys start with `sk-or-v1-`. If a different key is set or the env var name is wrong, extraction silently fails. **How to avoid:** Set `HINDSIGHT_LLM_API_KEY=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` — same value as existing `OPENROUTER_API_KEY`. **Warning signs:** Daemon logs show 401/403 errors from OpenRouter. No memories created. ### Pitfall 5: Daemon Profile Env Stale **What goes wrong:** The `~/.hindsight/profiles/hermes.env` file has stale config from a previous attempt that doesn't match current settings. **Why it happens:** The profile env is generated during `post_setup()` or `initialize()`. If the config.json changes but the profile env doesn't get regenerated, the daemon uses old settings. **How to avoid:** The plugin's `initialize()` method checks if the profile env matches config and regenerates it if needed. Manual config changes may require deleting the profile env to force regeneration. The existing `hermes.env` already has correct settings from the previous attempt. ## State of the Art | Old Approach | Current Approach | When Changed | Impact | |--------------|------------------|--------------|--------| | MEMORY.md built-in (FTS5 text search) | Hindsight (entity-aware KG + semantic search) | Hermes v0.16.0 | Cross-session recall, entity resolution, multi-strategy retrieval | | Per-session document overwrite | `update_mode='append'` (Hindsight ≥ 0.5.0) | Hindsight 0.5.0 | Retains append to existing session document instead of replacing it. Auto-detected in plugin `__init__.py` via `/version` probe | | `recall_types` defaulted to all types | Now defaults to `observation` only | Hindsight 0.5.0 | Observations are consolidated knowledge; raw world/experience facts are supporting evidence. Use `"recall_types": "observation,world,experience"` to restore broad recall | ## Code Examples ### Config File: `~/.hermes/hindsight/config.json` ```json { "mode": "local_embedded", "llm_provider": "openrouter", "llm_base_url": "https://openrouter.ai/api/v1", "llm_model": "qwen/qwen3.5-9b", "bank_id": "hermes", "recall_budget": "low", "recall_prefetch_method": "recall", "auto_recall": true, "recall_types": "observation", "auto_retain": true, "retain_async": true, "retain_every_n_turns": 5, "memory_mode": "hybrid" } ``` **Source:** [VERIFIED: plugins/memory/hindsight/README.md — all config keys documented with defaults and descriptions] ### Environment Variable to Add to `~/.hermes/.env` ``` # Hindsight — LLM API key for local embedded mode (reuses OpenRouter key) HINDSIGHT_LLM_API_KEY=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 ``` The OpenRouter base URL is already set in config.json (`llm_base_url` field), so `HINDSIGHT_API_LLM_BASE_URL` env var is optional — the plugin reads it from config. **Source:** [VERIFIED: plugins/memory/hindsight/README.md §Environment Variables — `HINDSIGHT_LLM_API_KEY` documented] ### Full Installation Sequence ```bash # 1. Install hindsight-all into Hermes venv uv pip install --python ~/.hermes/hermes-agent/venv/bin/python hindsight-all # 2. Create config directory mkdir -p ~/.hermes/hindsight # 3. Write latency-optimized config cat > ~/.hermes/hindsight/config.json << 'EOF' { "mode": "local_embedded", "llm_provider": "openrouter", "llm_base_url": "https://openrouter.ai/api/v1", "llm_model": "qwen/qwen3.5-9b", "bank_id": "hermes", "recall_budget": "low", "recall_prefetch_method": "recall", "auto_recall": true, "recall_types": "observation", "auto_retain": true, "retain_async": true, "retain_every_n_turns": 5, "memory_mode": "hybrid" } EOF # 4. Add LLM API key to .env (reuse existing OpenRouter key) grep -q "HINDSIGHT_LLM_API_KEY" ~/.hermes/.env || \ echo 'HINDSIGHT_LLM_API_KEY=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' >> ~/.hermes/.env # 5. Set memory provider hermes config set memory.provider hindsight # 6. Restart gateway hermes gateway restart ``` ### Verification Commands ```bash # Check config file exists cat ~/.hermes/hindsight/config.json # Check provider is set hermes config get memory.provider # Check env var is set (key appears masked) grep HINDSIGHT_LLM_API_KEY ~/.hermes/.env # Check memory status hermes memory status # Check daemon startup logs (after starting a session) cat ~/.hermes/logs/hindsight-embed.log # Check daemon runtime logs (after session activity) tail -50 ~/.hindsight/profiles/hermes.log ``` ### Diagnostic: Check Hindsight Daemon Health ```bash # Check if the daemon process is running ps aux | grep hindsight # Check the profile runtime log tail -20 ~/.hindsight/profiles/hermes.log # Check the client version uv pip show hindsight-client --python ~/.hermes/hermes-agent/venv/bin/python # Force daemon restart (delete profile env to regenerate) rm ~/.hindsight/profiles/hermes.env ``` ## Assumptions Log | # | Claim | Section | Risk if Wrong | |---|-------|---------|---------------| | A1 | `hindsight-all` package is available on PyPI and installable via uv [CITED: verified via uv install] | Standard Stack | Package not found → fall back to `hermes memory setup` wizard which uses the same uv command | | A2 | The existing OpenRouter API key is valid and has credits for LLM extraction calls [CITED: exists in .env] | Standard Stack | Key expired/insufficient → LLM extraction fails silently; memories never created | | A3 | The existing `~/.hindsight/profiles/hermes.env` has correct settings and will be regenerated if config.json changes [CITED: verified via plugin __init__.py initialize() logic] | Architecture Patterns | Stale profile env → daemon starts with wrong LLM config → extraction fails | ## Open Questions 1. **Does the OpenRouter key have sufficient rate limits for hindsight LLM extraction?** - What we know: Key exists and is used for fallback model calls - What's unclear: Whether the free tier of OpenRouter handles the additional Hindsight extraction traffic (every 5 turns, ~70-200 chars per extraction) - Recommendation: Monitor after deployment; if rate-limited, switch the extraction model to a cheaper/faster one or set up a dedicated OpenRouter key 2. **How does the daemon behave on macOS (Orbstack Docker)?** - What we know: The daemon runs embedded PostgreSQL via `pg0` - What's unclear: pg0 on macOS may have different startup characteristics - Recommendation: Test first session start; check `hindsight-embed.log` for any pg0-related errors ## Environment Availability | Dependency | Required By | Available | Version | Fallback | |------------|------------|-----------|---------|----------| | `uv` | Package installation | ✓ | 0.11.19 | `hermes memory setup` uses uv internally | | Hermes venv (`~/.hermes/hermes-agent/venv/`) | Package target | ✓ | Python 3.11 | — | | OpenRouter API key | LLM extraction | ✓ | `sk-or-v1-...` (existing) | — | | `hindsight-all` pip package | Embedded daemon | ✓ installed | 0.8.2 | `hindsight-client` only (cloud mode) | | Hermes gateway | Activation | ✓ | v0.16.0 | — | **Missing dependencies with no fallback:** none **Missing dependencies with fallback:** none ## Validation Architecture ### Test Framework | Property | Value | |----------|-------| | Framework | pytest | | Config file | none — use `python -m pytest` | | Quick run command | `python -m pytest tests/ -x -q` | | Full suite command | `python -m pytest tests/` | ### Phase Requirements → Test Map | Req ID | Behavior | Test Type | Automated Command | File Exists? | |--------|----------|-----------|-------------------|-------------| | MEM-01 | Hindsight config.json written with correct keys | smoke | Check file exists and JSON valid | ❌ Wave 0 | | MEM-01 | `memory.provider` set to `hindsight` | smoke | `hermes config get memory.provider` | ❌ Wave 0 | | MEM-01 | Hindsight daemon starts on session init | smoke | Check `hindsight-embed.log` for success | ❌ Wave 0 | | MEM-01 | Recall works across sessions | integration | Manual test: store fact in session A, recall in session B | Manual only | ### Sampling Rate - **Per task commit:** `check-config.sh` (verify config.json, env var, provider setting) - **Per wave merge:** Full verification sequence - **Phase gate:** Functional test: store + recall across two sessions ### Wave 0 Gaps - [ ] `tests/test_hindsight_config.py` — validates config.json structure and env vars - [ ] `tests/test_hindsight_install.py` — validates package installation in Hermes venv *(See gsd-add-tests skill for generating these after implementation.)* ## Security Domain > Required: `security_enforcement` not explicitly false. ### Applicable ASVS Categories | ASVS Category | Applies | Standard Control | |---------------|---------|-----------------| | V2 Authentication | no | No new auth — reuses existing OpenRouter key | | V3 Session Management | no | Hindsight sessions are managed by the plugin internally | | V4 Access Control | no | No user-facing access control changes | | V5 Input Validation | yes | LLM extraction output is validated by Hindsight server-side | | V6 Cryptography | no | No new cryptographic operations | | V8 Data Protection | yes | Local embedded mode = no external data send; data persists in local PostgreSQL | ### Known Threat Patterns for {Hermes + Hindsight} | Pattern | STRIDE | Standard Mitigation | |---------|--------|---------------------| | Memory data exfiltration via prompt injection | Information Disclosure | Local embedded mode = no external network data send; data stays in local PostgreSQL. LLM extraction calls go through OpenRouter with only the conversation turn as payload | | LLM extraction API key compromise | Tampering | OpenRouter key already stored in `~/.hermes/.env` with 0600 permissions; reused same key, no new secret to manage | | Daemon port exposure (localhost:9177) | Elevation of Privilege | Daemon binds to localhost only; not exposed to Docker container or network | ## Sources ### Primary (HIGH confidence) - `~/.hermes/hermes-agent/plugins/memory/hindsight/README.md` — Full configuration reference with all options, env vars, and modes [VERIFIED: read in full] - `~/.hermes/hermes-agent/plugins/memory/hindsight/__init__.py` (1803 lines) — Complete MemoryProvider implementation; config loading, daemon management, client initialization [VERIFIED: read in full] - `~/.hermes/hermes-agent/plugins/memory/__init__.py` — "Only ONE provider can be active at a time" constraint line 12 [VERIFIED: read provider conflict logic] - `~/.hermes/hermes-agent/agent/memory_manager.py` lines 342-354 — Provider conflict implementation [VERIFIED: read] - `~/.hermes/hermes-agent/hermes_cli/memory_setup.py` — Interactive setup wizard code [VERIFIED: read] - `~/.hermes/hermes-agent/venv/` — Confirmed `hindsight-all==0.8.2` installed [VERIFIED: pip show] - `~/.hermes/config.yaml` §memory — Current empty provider setting [VERIFIED: read] - `~/.hermes/.env` — Existing OpenRouter API key [VERIFIED: read] - `~/.hindsight/profiles/hermes.env` — Pre-existing daemon config from previous attempt [VERIFIED: read] ### Secondary (MEDIUM confidence) - `~/.hermes/hermes-agent/pyproject.toml` — `hindsight-client==0.6.1` listed as extras dependency [VERIFIED: grep] - CONTEXT.md D-01 through D-10 — Locked decisions for this phase [VERIFIED: read] ### Tertiary (LOW confidence) - Hindsight daemon behavior on macOS with pg0 — Not verified; will be validated during first session start [ASSUMED] ## Metadata **Confidence breakdown:** - Standard stack: HIGH — all packages confirmed installed in Hermes venv; config structure verified against plugin source code - Architecture: HIGH — plugin code read in full; data flow traced from agent loop to daemon - Pitfalls: HIGH — each sourced from specific Hermes source lines and plugin implementation details - Security: MEDIUM — local embedded mode eliminates external data send risk, but daemon behavior on macOS is not verified **Research date:** 2026-06-14 **Valid until:** 2026-07-14 (30 days — stable Hermes v0.16.0 configuration)