Skip to content

feat: Claude Code hooks for automatic memory integration#124

Open
russellbrenner wants to merge 57 commits intoCaviraOSS:mainfrom
russellbrenner:main
Open

feat: Claude Code hooks for automatic memory integration#124
russellbrenner wants to merge 57 commits intoCaviraOSS:mainfrom
russellbrenner:main

Conversation

@russellbrenner
Copy link

Summary

Adds Claude Code integration via hooks and a migration script for users coming from claude-mem.

  • SessionStart hook - queries OpenMemory for project-relevant context at session start
  • Stop hook - stores session summaries automatically
  • CLAUDE.md.example - template instructions for Claude to use the MCP tools effectively
  • import-claude-mem.js - migration script for claude-mem SQLite databases

Both hooks fail silently with 3-second timeouts when OpenMemory isn't running.

Disclosure

This PR was authored with assistance from Claude (Anthropic). The hooks and documentation were developed iteratively based on actual usage. Happy to adjust anything to fit the project's direction.

Files

hooks/
├── openmemory-session-start.sh  # Injects context at session start
├── openmemory-session-stop.sh   # Stores session summaries
├── README.md                     # Installation instructions
└── CLAUDE.md.example            # MCP tool usage guide for Claude

scripts/
└── import-claude-mem.js         # Migrate from claude-mem

Test plan

  • Tested hooks with local OpenMemory instance
  • Verified silent failure when Docker not running
  • Tested import script with real claude-mem database

🤖 Generated with Claude Code

russellbrenner and others added 2 commits January 14, 2026 00:16
- Fix openmemory-js Dockerfile: replace Bun with npm (no bun.lockb exists)
- Add NODE_OPTIONS for increased heap size during TypeScript compilation
- Restore dashboard app from git history (removed in Beta 1.3.0)
- Update docker-compose.yml to re-enable dashboard service

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add SessionStart hook to query project context at session start
- Add Stop hook to store session summaries
- Both hooks fail silently if OpenMemory/Docker unavailable
- Include CLAUDE.md.example with comprehensive MCP tool documentation
- Add import-claude-mem.js for migrating claude-mem databases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 13, 2026 14:22
Use jq to build JSON output instead of bash substring expression
that fails on some bash versions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Claude Code integration hooks and a comprehensive dashboard for OpenMemory, enabling automatic memory capture during development sessions and providing visual analytics for memory management.

Changes:

  • Added session start/stop hooks for automatic memory integration with Claude Code
  • Created a Next.js dashboard with memory analytics, chat interface, and system monitoring
  • Provided migration tooling for users coming from claude-mem
  • Switched Docker build from Bun to npm with increased Node.js heap size

Reviewed changes

Copilot reviewed 33 out of 36 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
scripts/import-claude-mem.js Migration script to import memories from claude-mem SQLite database
packages/openmemory-js/Dockerfile Changed build system from Bun to npm with heap size optimization
hooks/openmemory-session-stop.sh Bash script to capture session summaries at Claude Code session end
hooks/openmemory-session-start.sh Bash script to inject relevant context at Claude Code session start
hooks/README.md Installation and configuration guide for Claude Code hooks
hooks/CLAUDE.md.example Template documentation for Claude to use OpenMemory MCP tools
docker-compose.yml Removed obsolete version specification
dashboard/* Complete Next.js dashboard implementation with memory visualization and chat interface

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

russellbrenner and others added 2 commits January 14, 2026 12:31
- Add NODE_OPTIONS=--max-old-space-size=128 to Dockerfile production stage
- Document memory tuning in README for users needing larger heaps
- Default 128MB provides ~4x headroom over minimal Node.js heap

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous 128MB limit caused 96% memory pressure during normal
operations. Increased to 512MB to provide headroom for vector
operations and embedding storage.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@nullure
Copy link
Member

nullure commented Jan 15, 2026

Hi Russell, thank you for your contribution! This helps us a lot, but I don't understand why there is a neccesity for frontend files here

russellbrenner and others added 2 commits February 13, 2026 11:40
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@russellbrenner
Copy link
Author

@copilot open a new pull request to apply changes based on the comments in this thread

russellbrenner and others added 18 commits February 13, 2026 12:31
Fork cleanup: remove hardcoded CDN hostname from next.config.ts (now
env-based via NEXT_PUBLIC_CDN_HOSTNAME), add comprehensive security
scanning workflow with CodeQL, Gitleaks, and Trivy. Also includes
Dockerfile improvements and opm.js executable bit fix.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Merge all changes from upstream repository (CaviraOSS/OpenMemory) commit 30daf78:
- Fix unterminated f-strings in google_slides.py (lines 77, 91)
- Enhanced MCP integration with temporal fact support (contextual/factual/unified queries)
- Add temporal graph user_id scoping for multi-tenant support
- Improve Postgres and Valkey vector store implementations
- Update LangChain integration with better async/await handling
- Bump versions: openmemory-py 1.3.2, openmemory-js 1.3.3
- Database improvements including better query handling
- Enhanced documentation in docstrings

Files updated: 20 (10 Python, 10 TypeScript/JavaScript)
Total changes: +404 -168 lines

Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Fix incorrect parameter names when calling query_facts_at_time:
- Change 'obj' to 'subject_object' to match function signature
- Change 'at_time' to 'at' to match function signature

This fixes a bug introduced in the upstream code.

Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Fix CI: Add missing pytest dev dependencies to Python SDK
Merge upstream changes from CaviraOSS/OpenMemory (30daf78)
…ent plan

- Fixed authentication bypass vulnerability with clear warnings
- Fixed error message information leakage in all routes
- Added GitHub webhook signature verification
- Updated SECURITY.md with new security features
- Added GITHUB_WEBHOOK_SECRET to .env.example
- Created comprehensive IMPROVEMENT_PLAN.md with all findings

Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
- Import crypto at module level for best practices
- Require raw body for signature verification (no fallbacks)
- Add explicit error handling if raw body unavailable
- Improve variable naming for clarity (d -> rawBody)
- Ensure byte-for-byte signature accuracy

Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
- Created SECURITY_FIXES_SUMMARY.md with detailed findings
- Documented all vulnerabilities and fixes
- Added production deployment checklist
- Confirmed 0 CodeQL alerts
- TypeScript compilation successful

Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
…plan

Rewrite IMPROVEMENT_PLAN.md into a repo-grounded implementation roadmap with parallel execution lanes
Copilot AI and others added 15 commits February 13, 2026 07:19
Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
…omments

Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
Co-authored-by: russellbrenner <5236354+russellbrenner@users.noreply.github.com>
…vement

Execute next improvement-plan phase with minimal Phase 2 document metadata quick wins
A1.1: Fix noisy auth warnings
- Auth disabled warnings now log once at startup, not per-request
- Added auth_warning_logged flag to prevent log spam

B2.1: Remove duplicate index creation
- Removed duplicate openmemory_stats_type_idx in Postgres init
- Removed duplicate idx_edges_validity in SQLite init

Also updated IMPROVEMENT_PLAN.md with comprehensive Phase 0/1 review
findings including code quality assessment and remediation workstream.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Implements structured logging and metrics for background tasks (decay,
prune, reflect, user_summary). Operators can now monitor task health
via /dashboard/tasks endpoint showing run counts, success/failure rates,
durations, and recent errors.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Implements append-only audit logging for memory mutations. Tracks
create, update, delete, reinforce, and ingest actions with actor info,
timestamps, changes, and metadata. Query via /audit/logs, /audit/stats,
and /audit/resource/:type/:id endpoints.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Implements version history tracking for memories. Features:
- Auto-save version before content updates
- Line-based diff computation with change classification
- Version history, retrieval, comparison, and restore endpoints
- /memory/:id/versions, /version, /diff/*, /restore/:version APIs

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Copy link

@nate-mcneil nate-mcneil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is titled as Claude Code hooks but includes 96 changed files across the entire codebase -- hooks, dashboard, security hardening, auth middleware, config, CI workflows, and more. This should be broken into separate PRs. Reviewing the hooks and migration script (the stated scope) plus flagging issues in the rest.

Major concerns:

  1. PR scope: 17k+ lines across 96 files is unreviewable as a single unit. The hooks, security hardening, dashboard changes, and auth middleware are all independent concerns.

  2. Stop hook shell injection: In openmemory-session-stop.sh line 45, $project_name is interpolated directly into the JSON tags array without escaping. A directory named foo","injected would break the JSON or inject arbitrary tags. Use jq to build the entire payload.

  3. Stop hook transcript parsing is fragile: Line 29-30 pipes tail -50 of the transcript through jq with select(.type == "assistant"), but the transcript file is not necessarily newline-delimited JSON. If the format is a JSON array or changes between Claude versions, this silently produces nothing or garbage.

  4. Migration script has no idempotency: import-claude-mem.js has no deduplication. Running it twice imports everything twice. Should check for existing memories with matching original_id in metadata before inserting.

  5. Migration script has no rate limiting: It fires sequential fetch calls as fast as possible for potentially thousands of records. Should add a small delay or batch size to avoid overwhelming the server.

  6. Auth bypass on user_id checks: In memory.ts, the user_id authorization checks (lines 153, 226, 260) only enforce ownership if the caller provides a user_id. If omitted, the check is skipped entirely -- any unauthenticated caller can read/modify/delete any memory by simply not sending user_id. This is not new code but worth flagging since the PR adds auth hardening elsewhere.

\"content\": $escaped_summary,
\"user_id\": \"claude-session\",
\"tags\": [\"session\", \"project:$project_name\"]
}" > /dev/null 2>&1 || true # Ignore errors

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$project_name is interpolated raw into the JSON tags array. A directory with quotes or special characters in the name will break the JSON or inject arbitrary tags. Build the entire curl payload with jq instead of string interpolation.

# Extract recent assistant messages from transcript for summary
if [ -f "$transcript_path" ]; then
# Get last few assistant messages to summarise session
recent_content=$(tail -50 "$transcript_path" 2>/dev/null | \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes the transcript is newline-delimited JSON objects. If the transcript format is a JSON array or changes between Claude Code versions, this silently produces no summary. Worth documenting the expected format or adding a fallback.

}

try {
const response = await fetch(`${OPENMEMORY_URL}/memory/add`, {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No deduplication -- running this script twice imports everything twice. Consider checking for existing memories with matching metadata.original_id before inserting, or at minimum document that it's not idempotent.

response=$(curl -s --connect-timeout 2 --max-time "$TIMEOUT_SECS" \
-X POST "$OPENMEMORY_URL/memory/query" \
-H "Content-Type: application/json" \
-d "{\"query\": \"project $project_name\", \"k\": 5}" 2>/dev/null)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No API key / auth header is sent with the curl requests. If the user has OM_API_KEY configured (which this same PR encourages), both hooks will get 401s and silently fail. Should pass OM_API_KEY via x-api-key header when the env var is set.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 91 out of 96 changed files in this pull request and generated 14 comments.

Files not reviewed (1)
  • packages/openmemory-js/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

} {
const context = QueryAnalyzer.analyze(query)

let strategy: 'broad' | 'focused' | 'deep' | 'temporal' = 'focused'
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initial value of strategy is unused, since it is always overwritten.

Copilot uses AI. Check for mistakes.
const context = QueryAnalyzer.analyze(query)

let strategy: 'broad' | 'focused' | 'deep' | 'temporal' = 'focused'
let recommendedCount = 10
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initial value of recommendedCount is unused, since it is always overwritten.

Copilot uses AI. Check for mistakes.
const [messages, setMessages] = useState<ChatMessage[]>([])
const [input, setInput] = useState("")
const [busy, setBusy] = useState(false)
const [connecting, setConnecting] = useState(false)
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable setConnecting.

Suggested change
const [connecting, setConnecting] = useState(false)
const [connecting] = useState(false)

Copilot uses AI. Check for mistakes.
const [riskmems, setriskmems] = useState<memory[]>([])
const [loading, setloading] = useState(true)
const [error, seterror] = useState<string | null>(null)
const [dashstats, setdashstats] = useState<any>(null)
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable dashstats.

Suggested change
const [dashstats, setdashstats] = useState<any>(null)

Copilot uses AI. Check for mistakes.
const [qpsData, setQpsData] = useState<any[]>([])
const [healthMetrics, setHealthMetrics] = useState<any>({})
const [logs, setLogs] = useState<any[]>([])
const [topUsers, setTopUsers] = useState<any[]>([])
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable topUsers.

Suggested change
const [topUsers, setTopUsers] = useState<any[]>([])

Copilot uses AI. Check for mistakes.

if (contextSegments.length > 0) {
for (const seg of contextSegments) {
const sources = seg.sources.map(id => `[${id.slice(0, 8)}]`).join(' ')
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable sources.

Copilot uses AI. Check for mistakes.
const idealPercentage = 1 / sectors.length

let balance = 0
for (const [sector, count] of sectors) {
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable sector.

Copilot uses AI. Check for mistakes.
const connectivity = node ? node.linkedMemories.length / Math.max(1, allMemories.length) : 0

const tokens = TextProcessor.tokenize(memory.content)
const allTokens = new Set(allMemories.flatMap(m => TextProcessor.tokenize(m.content)))
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable allTokens.

Copilot uses AI. Check for mistakes.
// Set up environment before importing audit module
process.env.OM_EMBEDDINGS = "synthetic";

import { run_async, all_async, get_async } from "../src/core/db";
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused imports all_async, get_async.

Copilot uses AI. Check for mistakes.
// Set up environment before importing
process.env.OM_EMBEDDINGS = "synthetic";

import { run_async, all_async, q } from "../src/core/db";
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused imports all_async, q.

Copilot uses AI. Check for mistakes.
russellbrenner and others added 11 commits February 14, 2026 10:08
Word-level diff with automatic categorisation of changes into financial,
date, party, legal_term, and general categories. Severity calculation based
on change type and volume. Generates HTML redline markup with data attributes.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Extracts citations from text using pattern matching for legal (case law,
legislation), academic (author-date, footnotes), and URL references.
Stores citations with edges to source memories for reverse-lookup.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Schema-driven extraction for document types: agreement, contract, invoice,
legal_filing, correspondence. Validates with zod, supports merge with
existing metadata. Extracts parties, dates, amounts, jurisdiction, etc.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Segments documents into clauses with type detection (definition, obligation,
confidentiality, termination, etc.). Stores clause embeddings for similarity
search across documents. Detects various numbering formats.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
CRUD for document templates with typed variables (string, number, date,
boolean, select, list). Auto-extracts variables from {{var:type}} syntax.
Instantiation validates and substitutes variables, creating memory entries.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
C2: Add scripts/check-sector-parity.ts to verify TS/Python config sync
D7: Implement compliance rules engine with 7 rule types:
- required_clause: Ensure specific clauses are present
- prohibited_term: Flag forbidden terms with context
- required_field: Validate metadata field presence
- pattern_match: Custom regex matching (must/must-not)
- field_format: Validate field format with regex
- word_count: Enforce min/max word limits
- date_range: Validate dates within bounds

Includes rule sets for grouping rules, full CRUD API, and audit logging.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Created project-level CLAUDE.md for future Claude Code sessions with
build commands, architecture overview, and sector/scoring documentation.
Added comprehensive 48-hour code review identifying 2 critical bugs
and 5 improvement opportunities across new document intelligence features.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Critical fixes:
- Fix operator precedence bug in structured_extraction.ts:269
- Fix prohibited_term to report all matches in compliance.ts

High priority:
- Batch embedding calls in clause_similarity store_clauses()
- Add ReDoS protection for user-provided regex patterns

Medium priority:
- Standardise UUID generation on rid() across codebase
- Add version pruning to prevent unbounded growth

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Replace hardcoded 'memories' table references with the dynamic
memories_table variable to support PostgreSQL deployments where
the table is named "public"."openmemory_memories".

Fixed files:
- src/ops/dynamics.ts: 3 queries for salience retrieval and decay
- src/memory/decay.ts: 1 SELECT, 2 UPDATE queries for summary updates
- src/server/routes/system.ts: 1 SELECT for sector statistics

Discovered during integration testing against the test k3s deployment.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
AI-Generated: true
- audit.ts: Extend resource_type to include compliance_rule, rule_set, template
- clause_similarity.ts: Fix VectorStore method names (storeVector, searchSimilar)
- structured_extraction.ts: Fix TypeScript doc_type spread conflict
- embed.ts: Add embed_advanced() batch function for clause embeddings
- audit routes: Accept new resource types in validation
- templates.ts: Fix add_memory signature to match add_hsg_memory

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Add comprehensive analysis of Redis/Valkey caching layer requirements.
Conclusion: not needed at current scale, but architecture is ready.

Also add gitignore pattern for auto-generated claude-mem context files
in subdirectories while preserving root CLAUDE.md.

Co-Authored-By: Claude <noreply@anthropic.com>
AI-Generated: true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants