Add a new "Constellation" memory visualization as the default view in the
control plane, powered by @chenglou/pretext for DOM-free text layout on canvas.
- Canvas-rendered zoomable/pannable memory map with spatial label deconfliction
- Nodes colored by link-count heat gradient (Hindsight brand teal→cyan→blue)
- Star-like rendering with varied size/opacity based on connectivity
- Hover shows rich tooltip with full memory metadata (text, entities, tags, dates)
- Hover highlights connected nodes and their links, dims the rest
- Click to select and view memory details in the side panel
- Fullscreen mode toggle
- Link type legend and heat gradient legend on the HUD
Also optimizes the graph API endpoint:
- Entity query now filters by visible unit IDs (was doing full table scan)
- Links query caps at 10k edges sorted by weight (was returning 500k+ uncapped)
- Replaced expensive DISTINCT ON with LEAST/GREATEST sort with simple ORDER BY
* fix(deps): address critical and high severity security vulnerabilities
Bump vulnerable dependencies to patched versions across the monorepo:
Python (critical/high):
- fastmcp >=2.14.0 → >=3.2.0 (SSRF, path traversal, OAuth confused deputy, command injection)
- langchain-core >=1.2.11 → >=1.2.22 (path traversal in legacy load_prompt)
Python (low):
- cryptography >=46.0.5 → >=46.0.6 (incomplete DNS name constraint enforcement)
- pygments: add >=2.20.0 pin (ReDoS via GUID regex)
Node.js:
- serialize-javascript ^7.0.3 → ^7.0.5 (CPU exhaustion DoS)
- handlebars: add >=4.7.9 override (JS injection via AST type confusion)
- path-to-regexp: add >=0.1.13 override (ReDoS via route params)
- brace-expansion: add version range override (process hang/memory exhaustion)
Also adds type: ignore comments for FastMCP 2.x private attribute access that
ty now flags since FastMCP 3.x removed _tool_manager (guarded by try/except
and hasattr at runtime).
Regenerated all lock files across API, integrations, and tests.
* fix(deps): add ajv v8 scoped overrides for schema-utils and ajv-keywords
The global ajv ^6.14.0 override caused schema-utils and ajv-keywords to
receive ajv v6, but they require ajv v8 (for dist/compile/codegen). Add
scoped overrides to ensure these packages get ajv v8 while the global
override remains for packages that need v6.
* fix(tests): remove stateless_http from FastMCP() constructor calls
FastMCP 3.x no longer accepts stateless_http in the constructor. The
tests call tools directly without HTTP transport, so the parameter is
not needed.
* fix: update MCP tests for FastMCP 3.x _tool_manager removal
FastMCP 3.x removed _tool_manager. Tests now use
_local_provider._components for sync tool dict access and
mcp.list_tools() for async filtered tool listing.
* fix: resolve docusaurus build failures (ajv overrides + missing blog date)
- Remove global ajv ^6.14.0 override and scoped ajv-keywords/schema-utils
overrides that caused webpack compilation errors manifesting as
"Cannot read properties of undefined (reading 'date')" during SSR
and "these parameters are deprecated" warnings. Natural version
resolution (v6.12.6+ for v6 consumers, v8+ for v8 consumers) already
satisfies the security fix (>= 6.12.3).
- Add missing date frontmatter to learning-capabilities blog post.
* chore: regenerate openapi spec and docs skill
* Initial plan
* Fix timeline sort to use numeric datetime comparison instead of string localeCompare
* chore: remove accidentally committed root package-lock.json
Agent-Logs-Url: https://github.com/ThePlenkov/hindsight/sessions/d02f10c5-cc48-4977-84a9-48870f9460ec
Co-authored-by: ThePlenkov <6381507+ThePlenkov@users.noreply.github.com>
* chore: restore package-lock.json to its original state from main
Agent-Logs-Url: https://github.com/ThePlenkov/hindsight/sessions/2ede4783-55ef-4f36-8ea7-7d65c5362a0a
Co-authored-by: ThePlenkov <6381507+ThePlenkov@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ThePlenkov <6381507+ThePlenkov@users.noreply.github.com>
When a mental model has tags, refresh_mental_model hardcoded
tags_match="all_strict", causing empty results when most memories
are untagged. Add configurable tags_match and tag_groups fields
to MentalModelTrigger so users can control refresh filtering.
- Add tags_match (any/all/any_strict/all_strict) to override default
- Add tag_groups for compound boolean tag expressions during refresh
- Default behavior unchanged (all_strict when tags present)
- Update both refresh paths (task-based and direct)
- Add UI controls in Create/Update mental model dialogs
- Regenerate OpenAPI spec and client SDKs
CI failures are unrelated to this PR:
- test_mental_models_dimension_change_empty_table: database OID error (infrastructure flake)
- test_reflect_searches_mental_models_when_available: LLM-dependent assertion (flaky)
When using Azure AI Foundry Cohere rerank endpoints, the Cohere SDK
incorrectly appends /v1/rerank to the base_url, but Azure endpoints
already include the full path (e.g., /models/.../invoke). This causes
double-pathing and 404 errors.
This commit modifies CohereCrossEncoder to detect when base_url is
provided and use httpx directly for custom endpoints, while keeping
the native Cohere SDK for standard API usage. The Azure Cohere API
response format is compatible with the native format.
Fixes#783
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Enable passing arbitrary extra_body parameters to OpenAI-compatible API
calls via a JSON-encoded env var. This supports custom model servers
(e.g. vLLM) that need parameters like chat_template_kwargs to control
thinking mode.
Co-authored-by: EMIRHAN GAZI <emirhan.gazi+tcell@turkcell.com.tr>
Replace the `pull_request_target` + `safe-to-test` label mechanism with
`pull_request_review` (submitted, approved). External contributor PRs now
get basic builds/lints on open, and full secret-dependent CI only after
a maintainer approves — no manual labeling needed.
* feat: add optional LiteLLM SDK embedding output dimensions
Allow configuring an optional output dimension for litellm-sdk embeddings and pass it through only when set, while preserving default behavior.
Made-with: Cursor
* test: assert wrapped init error for invalid dimensions
Add a LiteLLM SDK embeddings test that verifies invalid OpenAI dimensions fail during initialize() and preserve provider error details in the wrapped RuntimeError.
Made-with: Cursor
* feat: expose document_metadata in API and control plane
Add document_metadata (sourced from retain_params.metadata) to both
list and get document endpoints. Display it in the control plane
documents table and detail panel. Drop the unused metadata column
from the documents table (was always stored as empty {}).
* fix: code review fixes for document_metadata feature
- Remove unnecessary `import json as _json` (json already imported at module level)
- Simplify redundant truthiness checks in retain_params parsing
- Regenerate OpenAPI spec and client SDKs (Python, TypeScript, Go)
- Add tests for document_metadata in get_document and list_documents
* feat(ui): improve documents table and detail panel
- Relative timestamps with full date on hover
- Remove context column from table
- Metadata shown as k=v badges (blue, like tags)
- Size in bytes instead of chars
- Document IDs wrap instead of truncating
- Detail panel wider (560px)
- Retain params: context, event_date, metadata badges
* feat: add /code-review skill for automated code quality checks
Adds a Claude Code skill that reviews changes against project standards:
missing tests, dead code, type safety, lint, and CLAUDE.md conventions.
CLAUDE.md now instructs contributors to run /code-review after implementation.
* refactor: move code standards from CLAUDE.md into /code-review skill
Single source of truth for coding conventions (Python style, type safety,
TypeScript style) is now .claude/skills/code-review.md. CLAUDE.md points
to the skill for reading before coding and running after implementation.
* feat: add code comments convention to /code-review skill
Require comments explaining non-trivial technical decisions, with history
of previous approaches. Review step checks for missing reasoning comments,
stale comments, and undocumented approach changes.
* fix: move skill to directory structure for Claude Code discovery
Claude Code requires .claude/skills/<name>/SKILL.md, not loose .md files.
* feat: add branch hygiene checks to /code-review skill
Review step 1 now verifies branch is based on recent origin/main and
all commits are relevant to the feature. Unrelated commits flagged as
must-fix.
* feat: strengthen code review rules and fix stale CLAUDE.md references
- Enforce no multi-item tuple returns and no raw dicts even for internal code
- Add mandatory /code-review gate before push/PR
- Add integration completeness checklist (tests, CI job, release-integration.sh)
- Fix stale references: remove hindsight/ dir, update integrations list,
update LLM providers, remove hardcoded file sizes, fix _HIERARCHICAL_FIELDS
-> _CONFIGURABLE_FIELDS
* docs: add ./scripts/dev/start.sh for local dev in CLAUDE.md
* feat(api): warn on unknown request parameters via X-Ignored-Params header
Add middleware that detects unknown query params and JSON body fields,
logs a server-side warning, and returns an X-Ignored-Params response
header listing the ignored parameters. This surfaces silent parameter
ignoring (e.g. tag=source:slack on /memories/list) without breaking
forward compatibility between client and server versions.
Closes#792
* ci: report safe-to-test CI results on PR via status and comment
pull_request_target workflow runs are not linked to the PR by GitHub,
so the CI results are invisible on the PR page after adding safe-to-test.
Add a report-pr-status job that:
- Creates a commit status on the PR head SHA
- Posts/updates a summary comment with pass/fail counts and failed job names
* ci: skip secret-dependent jobs on fork pull_request events
Adds a has_secrets output to detect-changes that is false for fork PRs
via pull_request events. All 15 secret-dependent jobs now check this
output before running, avoiding guaranteed failures on fork PRs.
Fork contributors will see these jobs as skipped instead of failed,
and can use the safe-to-test label to run the full CI suite.
Add middleware that detects unknown query params and JSON body fields,
logs a server-side warning, and returns an X-Ignored-Params response
header listing the ignored parameters. This surfaces silent parameter
ignoring (e.g. tag=source:slack on /memories/list) without breaking
forward compatibility between client and server versions.
Closes#792
* feat: add /code-review skill for automated code quality checks
Adds a Claude Code skill that reviews changes against project standards:
missing tests, dead code, type safety, lint, and CLAUDE.md conventions.
CLAUDE.md now instructs contributors to run /code-review after implementation.
* refactor: move code standards from CLAUDE.md into /code-review skill
Single source of truth for coding conventions (Python style, type safety,
TypeScript style) is now .claude/skills/code-review.md. CLAUDE.md points
to the skill for reading before coding and running after implementation.
* feat: add code comments convention to /code-review skill
Require comments explaining non-trivial technical decisions, with history
of previous approaches. Review step checks for missing reasoning comments,
stale comments, and undocumented approach changes.
* fix: move skill to directory structure for Claude Code discovery
Claude Code requires .claude/skills/<name>/SKILL.md, not loose .md files.
* feat: add branch hygiene checks to /code-review skill
Review step 1 now verifies branch is based on recent origin/main and
all commits are relevant to the feature. Unrelated commits flagged as
must-fix.
Fork PRs don't have access to repository secrets, so integration tests
that need API keys (GCP, OpenAI, Cohere, etc.) are skipped. Maintainers
can now add the `safe-to-test` label after reviewing fork PR code to
trigger the full test suite with secrets via pull_request_target.
Follow-up to #764. Upgrades the silent debug log in waitForReady to
log.warn so unexpected calls before service.start() are visible, and
adds tests covering the CLI mode no-op path.
OpenClaw loads plugins on every CLI command (status, models auth add,
config validate, etc.), not just gateway start. The plugin was starting
LLM detection, daemon initialization, and API health checks immediately
in the default export, causing unnecessary resource usage and terminal
noise on routine CLI operations.
Move all heavy initialization (detectLLMConfig, embedManager.start(),
checkExternalApiHealth, client creation) into service.start() which is
only called when the gateway starts. The default export now only does
lightweight config parsing and service/hook registration.
Hooks (before_prompt_build, agent_end) gracefully no-op when called
before service.start() via the waitForReady guard.
Closes#746
* fix(engine): classify first-person agent experiences as 'experience' fact type
The extraction prompt defined "assistant" too narrowly as only "interactions
with assistant (requests, recommendations)", causing the LLM to classify
first-person agent actions (code changes, debugging, discoveries) as "world".
Broadened the fact_type definition in the prompt and Pydantic model descriptions
to cover all first-person actions, experiences, and observations by the speaker.
* style: fix line length in fact_extraction.py
The installer skipped settings.json entirely if it already existed,
leaving version and new config keys stale. Now merges: updates version,
adds new upstream keys, preserves user customizations.
Also fixes pre-existing typo: RERANK_URL → rerank_url in ZeroEntropy
cross-encoder.
* SEO: add title and description to all integration pages
All 17 integration docs pages were missing title and description
frontmatter, causing Docusaurus to generate unhelpful titles like
"OpenClaw | Hindsight" and pull body text as meta descriptions.
- Add keyword-rich title and description frontmatter to all integration
pages in both docs/ (current) and versioned_docs/version-0.4/
- Add scripts/check-integration-seo.mjs to enforce title + description
on all future integration pages
- Wire the check into the build script so it runs locally and in CI
* Fix missing frontmatter on docs/sdks/integrations/openclaw.md
* Regenerate docs skill after integration page SEO updates
- Retitle to match search intent: "How to Add Persistent Memory to
OpenClaw with Hindsight" targets openclaw memory/persistent memory queries
- Add intro paragraph before <!-- truncate --> so Docusaurus generates a
proper meta description instead of "TL;DR"
- Expand tags from [openclaw] to include memory, agents, persistent-memory,
knowledge-graph
* fix(llamaindex): use uuid for document_id and sync version metadata
- Replace timestamp-based document_id with uuid4 hex to prevent
collisions on rapid retains (timestamp_ms can duplicate in tight loops)
- Sync __version__ in __init__.py to match pyproject.toml (0.1.2)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(docs): pass memory to run() instead of ReActAgent constructor
LlamaIndex 0.14.x ReActAgent does not accept a memory parameter in
its constructor — it's silently dropped via **kwargs. Memory must be
passed to agent.run(memory=...) where AgentWorkflow picks it up.
Also fixes the undefined `tools` variable (now `tools=[]`).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(llamaindex): strip ReAct reasoning traces from retained assistant messages
HindsightMemory.put/aput now extracts only the final Answer: text from
assistant messages containing ReAct reasoning (Thought:/Action:/Observation:
prefixes), preventing internal reasoning traces from polluting long-term memory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(llamaindex): fix docstring example to pass memory to run()
The HindsightMemory class docstring showed the broken pattern of passing
memory= to the ReActAgent constructor, which silently drops it. Updated
to show the correct pattern: pass memory to agent.run().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Document the new configurable base URL for the ZeroEntropy reranker
provider added in #766. Also fix a type error where RERANK_URL was
renamed to rerank_url but one usage was missed.
The automatic memory example referenced an undefined `tools` variable.
Since HindsightMemory handles retain/recall transparently, no tools
are needed — use an empty list.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Fixes#771 — two trailing commas in openclaw.plugin.json caused OpenClaw's
strict JSON parser to reject the plugin manifest during installation.
Also adds JSON validation tests for both the openclaw plugin manifest and
the claude-code hooks.json so CI catches invalid JSON before release.