- Created ~/.hermes/scripts/archive-stale-sessions.sh (1146 bytes, executable) - Script has DRY_RUN=true safe default (export only, no prune) - Export uses date-stamped JSONL filename - Prune gated behind DRY_RUN=false with --older-than 30 --yes - set -euo pipefail strict error handling - Created ~/.hermes/archive/sessions/ archive directory - Progress echo statements for Telegram delivery
33 KiB
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_KEYin~/.hermes/.env) for LLM extraction viaHINDSIGHT_LLM_API_KEY.- Config:
mode: local_embeddedin~/.hermes/hindsight/config.json - Env:
HINDSIGHT_LLM_API_KEY=sk-or-v1-...(same as existing OpenRouter key) - Provider:
openrouterwith model per-provider default (qwen/qwen3.5-9b)
- Config:
- 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)
- Config:
- 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:
# 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 | 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 | OK | Approved — dependency of hindsight-all, listed in Hermes pyproject.toml extras |
hindsight-embed |
PyPI (via uv) | ~1yr | Unknown | github.com/vectorize-io/hindsight | OK | Approved — dependency of hindsight-all |
hindsight-api-slim |
PyPI (via uv) | ~1yr | Unknown | 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
- Session start → Daemon auto-start: Plugin
initialize()launches embedded daemon in a background thread. The daemon process runs onlocalhost:9177with embedded PostgreSQL. - Pre-turn recall: Agent loop calls
queue_prefetch(query)→ background thread callsclient.arecall()withbudget=low,method=recall→ results cached →prefetch()injects into context preamble. - 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 callsclient.aretain_batch()asynchronously. - Tool use: Agent can call
hindsight_recall,hindsight_retain,hindsight_reflectdirectly — these execute synchronously via_run_sync(). - Idle shutdown: Daemon auto-stops after
idle_timeout: 300seconds 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:
- Install packages into Hermes venv
- Create
~/.hermes/hindsight/config.json - Add env var to
~/.hermes/.env - 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.providerto 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
{
"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
# 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
# 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
# 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
-
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
-
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.logfor any pg0-related errors
- What we know: The daemon runs embedded PostgreSQL via
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 varstests/test_hindsight_install.py— validates package installation in Hermes venv
(See gsd-add-tests skill for generating these after implementation.)
Security Domain
Required:
security_enforcementnot 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.pylines 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/— Confirmedhindsight-all==0.8.2installed [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.1listed 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)