Compare commits

...
Author SHA1 Message Date
Nicolò Boschi 95a8307759 fix(openclaw): pass enableKnowledgeTools through getPluginConfig
The flag was declared on PluginConfig and read at the
agent_knowledge_* tool registration site, but never copied through
getPluginConfig — so the runtime value was always undefined and the
if-branch never entered, regardless of what users (or the SDA CLI)
wrote into openclaw.json. Live since the feature was added on
Apr 29 2026.

Adds the field to the whitelist (defaulting to false on missing or
non-boolean values, matching the type definition) plus a regression
test in getPluginConfig.
2026-05-07 13:37:13 +02:00
Nicolò Boschi 27cf1c4b20 docs(claude-code): document knowledge tools and subagent skill
The Claude Code integration now ships an MCP server with
agent_knowledge_* tools and a /hindsight-memory:create-agent skill
for scaffolding memory-backed subagents. Document both, plus the
new enableKnowledgeTools config flag and venv bootstrap behavior.
2026-05-06 15:38:26 +02:00
Nicolò Boschi 94c8c16159 fix(claude-code): bootstrap Python deps via venv in CLAUDE_PLUGIN_DATA
Install Python deps into ${CLAUDE_PLUGIN_DATA}/venv on demand, and
launch the MCP server through that venv's interpreter — no global
pip install, isolated to the plugin, survives plugin updates.

How it works:
- requirements.txt declares deps (mcp>=1.0.0)
- scripts/run_mcp.sh creates the venv on first run (or when
  requirements.txt changes vs the cached copy in plugin data),
  pip-installs into it, and execs ${VENV}/bin/python on mcp_server.py
- .mcp.json now points at the wrapper instead of bare 'python3', so
  the MCP server always runs with the plugin's pinned interpreter
  (avoids version mismatches: e.g. system /usr/bin/python3 was 3.9
  but venv was built with 3.11)

Tested locally: cold start ~25s (venv + pip), warm start ~0.4s,
all 9 agent_knowledge_* tools register correctly.
2026-05-06 14:50:45 +02:00
7 changed files with 109 additions and 12 deletions
+62 -10
View File
@@ -6,7 +6,7 @@ description: "Add long-term memory to Claude Code with Hindsight. Automatically
# Claude Code
Biomimetic long-term memory for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) using [Hindsight](https://vectorize.io/hindsight). Automatically captures conversations and intelligently recalls relevant context — a complete port of [`hindsight-openclaw`](./openclaw) adapted to Claude Code's hook-based plugin architecture.
Biomimetic long-term memory for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) using [Hindsight](https://vectorize.io/hindsight). Automatically captures conversations, recalls relevant context, and exposes knowledge tools and a subagent-creation skill so Claude can read and write its own memory.
[View Changelog →](/changelog/integrations/claude-code)
@@ -41,21 +41,26 @@ That's it! The plugin will automatically start capturing and recalling memories.
- **Auto-recall** — on every user prompt, queries Hindsight for relevant memories and injects them as context (invisible to the chat transcript, visible to Claude)
- **Auto-retain** — after every response (or every N turns), extracts and retains conversation content to Hindsight for long-term storage
- **Knowledge tools** — Claude can read, write, and search its own memory via MCP tools (knowledge pages, recall, ingest)
- **Subagent skill** — `/hindsight-memory:create-agent` scaffolds a subagent backed by an isolated memory bank
- **Dynamic bank IDs** — per-agent, per-project, or per-session memory isolation (so each subagent gets its own brain)
- **Daemon management** — can auto-start/stop `hindsight-embed` locally or connect to an external Hindsight server
- **Dynamic bank IDs** — supports per-agent, per-project, or per-session memory isolation
- **Channel-agnostic** — works with Claude Code Channels (Telegram, Discord, Slack) or interactive sessions
- **Zero dependencies** — pure Python stdlib, no pip install required
## Architecture
The plugin uses all four Claude Code hook events:
The plugin combines hooks (for automatic recall/retain) with an MCP server (for explicit knowledge tools) and a skill (for subagent creation):
| Hook | Event | Purpose |
|------|-------|---------|
| `session_start.py` | `SessionStart` | Health check — verify Hindsight is reachable |
| `recall.py` | `UserPromptSubmit` | **Auto-recall** — query memories, inject as `additionalContext` |
| `retain.py` | `Stop` | **Auto-retain** — extract transcript, POST to Hindsight (async) |
| `session_end.py` | `SessionEnd` | Cleanup — stop auto-managed daemon if started |
| Component | Trigger | Purpose |
|-----------|---------|---------|
| `session_start.py` | `SessionStart` hook | Health check — verify Hindsight is reachable |
| `recall.py` | `UserPromptSubmit` hook | **Auto-recall** — query memories, inject as `additionalContext` |
| `retain.py` | `Stop` hook | **Auto-retain** — extract transcript, POST to Hindsight (async) |
| `session_end.py` | `SessionEnd` hook | Cleanup — stop auto-managed daemon if started |
| `mcp_server.py` | MCP server | Exposes `agent_knowledge_*` tools — list/get/create/update/delete pages, recall, ingest |
| `create-agent` | Skill | Scaffolds a subagent file under `~/.claude/agents/` and seeds its bank |
Python dependencies (`mcp`) are bootstrapped on first run into a private venv under `${CLAUDE_PLUGIN_DATA}/venv` — no global pip install, isolated to the plugin, survives plugin updates.
## Connection Modes
@@ -179,6 +184,51 @@ Auto-retain runs after Claude responds. It extracts the conversation transcript
---
### Knowledge Tools
The plugin runs an MCP server that exposes `agent_knowledge_*` tools, letting Claude explicitly read, write, and search its memory bank — as opposed to the hook-driven recall/retain which is fully automatic. None of the tools accept a `bank_id` parameter; the server resolves the active bank from the same config as the hooks, so tools and hooks always agree on which bank they touch.
| Tool | Purpose |
|------|---------|
| `agent_knowledge_get_current_bank` | Reports the bank ID the current session is bound to. |
| `agent_knowledge_list_pages` | Lists all knowledge pages (mental models) with IDs and names. |
| `agent_knowledge_get_page` | Reads the full synthesized content of a specific page. |
| `agent_knowledge_create_page` | Creates a new knowledge page with a `source_query` that re-synthesizes content after each consolidation. |
| `agent_knowledge_update_page` | Updates a page's name or `source_query`. |
| `agent_knowledge_delete_page` | Permanently deletes a knowledge page. |
| `agent_knowledge_recall` | Searches across retained conversations and documents for specific facts. |
| `agent_knowledge_ingest` | Uploads raw text content into the bank as a document. |
| `agent_knowledge_ingest_file` | Reads a file from disk and ingests its full content. |
| Setting | Env Var | Default | Description |
|---------|---------|---------|-------------|
| `enableKnowledgeTools` | `HINDSIGHT_ENABLE_KNOWLEDGE_TOOLS` | `false` | Master switch for the MCP knowledge tools. When `false`, the MCP server exits at startup and none of the `agent_knowledge_*` tools are exposed. |
---
### Subagents with Memory
The `/hindsight-memory:create-agent` skill creates a Claude Code subagent backed by its own Hindsight bank. Each subagent's prompt instructs it to use the knowledge tools above for recall and ingestion, so Claude treats persistent memory as a first-class capability of that agent.
Two modes:
- **From a directory** — `/hindsight-memory:create-agent <name> from <path>` ingests every text file under `<path>` (`.md`, `.txt`, `.html`, `.json`, `.csv`, `.xml`), creates a starter set of knowledge pages, and writes the subagent file to `~/.claude/agents/<name>.md`. If the directory contains a `bank-template.json` listing exact `mental_models`, those are used verbatim instead of auto-generated.
- **Interactive** — `/hindsight-memory:create-agent` (no arguments) prompts for the agent name and purpose, then writes the subagent file with no ingestion.
For per-subagent memory isolation, enable dynamic bank IDs:
```json
{
"dynamicBankId": true,
"dynamicBankGranularity": ["agent", "project"],
"enableKnowledgeTools": true
}
```
With `["agent", "project"]`, each subagent gets a unique bank per repository — `<agent-name>::<project-basename>`. Switch to `["agent"]` for a single bank per subagent across all projects, or `["agent", "session"]` for ephemeral per-session banks.
---
### Debug
| Setting | Env Var | Default | Description |
@@ -214,3 +264,5 @@ export HINDSIGHT_USER_ID="user-67890"
**Daemon not starting**: Ensure an LLM API key is set (or use `HINDSIGHT_LLM_PROVIDER=claude-code`). Review daemon logs at `~/.hindsight/profiles/claude-code.log`.
**High latency on recall**: The recall hook has a 12-second timeout. Use `recallBudget: "low"` or reduce `recallMaxTokens` for faster responses.
**Knowledge tools missing from Claude**: Make sure `enableKnowledgeTools` is `true` in `~/.hindsight/claude-code.json` and restart Claude Code. The first launch after enabling them takes ~2030 seconds to bootstrap the Python venv at `${CLAUDE_PLUGIN_DATA}/venv`; subsequent launches are instant.
+2 -2
View File
@@ -1,8 +1,8 @@
{
"mcpServers": {
"hindsight": {
"command": "python3",
"args": ["${CLAUDE_PLUGIN_ROOT}/scripts/mcp_server.py"]
"command": "bash",
"args": ["${CLAUDE_PLUGIN_ROOT}/scripts/run_mcp.sh"]
}
}
}
@@ -0,0 +1 @@
mcp>=1.0.0
@@ -17,6 +17,8 @@ import urllib.parse
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
# Launched via scripts/run_mcp.sh which execs the venv's interpreter, so
# `mcp` and friends resolve from ${CLAUDE_PLUGIN_DATA}/venv/site-packages.
from mcp.server.fastmcp import FastMCP
from lib.client import HindsightClient
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Launch the Hindsight MCP server inside the plugin's persistent venv.
# Bootstraps the venv if missing; otherwise just execs.
set -e
VENV="${CLAUDE_PLUGIN_DATA}/venv"
REQ_SRC="${CLAUDE_PLUGIN_ROOT}/requirements.txt"
REQ_CACHED="${CLAUDE_PLUGIN_DATA}/requirements.txt"
if [ ! -x "${VENV}/bin/python" ] || ! diff -q "${REQ_SRC}" "${REQ_CACHED}" >/dev/null 2>&1; then
mkdir -p "${CLAUDE_PLUGIN_DATA}"
if ! python3 -m venv "${VENV}" 2>/dev/null; then
python -m venv "${VENV}"
fi
"${VENV}/bin/pip" install --quiet -r "${REQ_SRC}"
cp "${REQ_SRC}" "${REQ_CACHED}"
fi
exec "${VENV}/bin/python" "${CLAUDE_PLUGIN_ROOT}/scripts/mcp_server.py"
@@ -1234,6 +1234,28 @@ describe("getPluginConfig — retainQueue whitelist (#1443)", () => {
});
});
describe("getPluginConfig — enableKnowledgeTools whitelist", () => {
// Regression: the field was declared on PluginConfig and read at the
// tool-registration site, but never copied through getPluginConfig, so the
// runtime value was always undefined and the agent_knowledge_* tools never
// registered (live since the feature was first added on Apr 29 2026).
it("passes enableKnowledgeTools=true through when set", () => {
const cfg = getPluginConfig(makeApi({ enableKnowledgeTools: true }));
expect(cfg.enableKnowledgeTools).toBe(true);
});
it("defaults to false when not set or set to a non-boolean truthy value", () => {
expect(getPluginConfig(makeApi({})).enableKnowledgeTools).toBe(false);
expect(getPluginConfig(makeApi({ enableKnowledgeTools: false })).enableKnowledgeTools).toBe(
false
);
expect(getPluginConfig(makeApi({ enableKnowledgeTools: "true" })).enableKnowledgeTools).toBe(
false
);
expect(getPluginConfig(makeApi({ enableKnowledgeTools: 1 })).enableKnowledgeTools).toBe(false);
});
});
describe("formatHookPerf (#1406)", () => {
it("emits the hook name, total ms, and field key=value pairs", () => {
const line = formatHookPerf("before_prompt_build", 4200, {
@@ -1503,6 +1503,7 @@ export function getPluginConfig(api: MoltbotPluginAPI): PluginConfig {
typeof config.retainQueueFlushIntervalMs === "number" && config.retainQueueFlushIntervalMs > 0
? config.retainQueueFlushIntervalMs
: undefined,
enableKnowledgeTools: config.enableKnowledgeTools === true,
};
}