Skip to content
Development
Hook

Hooks

What claude-mem-sync runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
claude-mem-sync
271 skill2 hooks

Claude Code

> /plugin marketplace add lopadova/claude-mem-sync
> /plugin install claude-mem-sync@claude-mem-sync

What fires, and when

Setup

  • Matches*bun "${CLAUDE_PLUGIN_ROOT}/scripts/setup.js"

PostToolUse

  • Matchesmcp__plugin_claude-mem_mcp-search__.*bun ${CLAUDE_PLUGIN_ROOT}/dist/hooks/post-tool-use.js
Read hooks/hooks.json

Where it lives

  • hooks/post-tool-use.tsGitHub
    Read the script
    /**
     * PostToolUse hook for Claude Code.
     *
     * Reads hook payload from stdin, extracts observation IDs from the tool
     * response, and logs each access to access.db so the eviction scorer
     * can reward frequently-used observations.
     *
     * Safety: wrapped entirely in try/catch — never throws, never blocks Claude,
     * never writes to stdout (stdout goes back to Claude Code).
     */
    
    import { openAccessDb, logAccess } from "../src/core/access-db";
    import { loadConfig, getEnabledProjects } from "../src/core/config";
    import { openMemDb, getObservationProjectMap } from "../src/core/mem-db";
    import { LOGS_DIR, DEFAULT_CLAUDE_MEM_DB } from "../src/core/constants";
    import { readAllStdin } from "../src/core/compat";
    import { mkdirSync, appendFileSync } from "fs";
    import { join } from "path";
    
    // ── Types ──────────────────────────────────────────────────────────────
    
    interface McpContentBlock {
      type: string;
      text?: string;
    }
    
    interface HookInput {
      session_id?: string;
      cwd?: string;
      tool_name?: string;
      tool_input?: Record<string, unknown>;
      tool_response?: string | McpContentBlock[];
    }
    
    // ── Helpers ────────────────────────────────────────────────────────────
    
    function logError(msg: string, data?: unknown): void {
      try {
        mkdirSync(LOGS_DIR, { recursive: true });
        const ts = new Date().toISOString();
        const line = `[${ts}] [HOOK-ERROR] ${msg}${data ? " " + JSON.stringify(data) : ""}\n`;
        appendFileSync(join(LOGS_DIR, "hook-errors.log"), line);
      } catch {
        // absolutely nothing — we must not fail
      }
    }
    
    /**
     * Extract observation IDs from the tool response text.
     *
     * Strategies (in order):
     *  1. JSON-parse the response and walk for `"id": <number>` fields
     *  2. Regex fallback for `"id": 123`, `#123`, `id=123` patterns
     */
    function extractObservationIds(response: string): number[] {
      const ids = new Set<number>();
    
      // Strategy 1: parse as JSON (response may be a JSON string or JSON object)
      try {
        const parsed = JSON.parse(response);
        walkForIds(parsed, ids);
      } catch {
        // not valid JSON — fall through to regex
      }
    
      // Strategy 2: regex patterns
      const patterns = [
        /"id"\s*:\s*(\d+)/g,
        /\bid[=:]\s*(\d+)/g,
        /#(\d+)\b/g,
      ];
      for (const pattern of patterns) {
        let match: RegExpExecArray | null;
        while ((match = pattern.exec(response)) !== null) {
          const n = Number(match[1]);
          if (n > 0 && Number.isInteger(n)) {
            ids.add(n);
          }
        }
      }
    
      return [...ids];
    }
    
    /** Recursively walk a parsed JSON value collecting numeric `id` fields. */
    function walkForIds(value: unknown, ids: Set<number>): void {
      if (value === null || value === undefined) return;
      if (Array.isArray(value)) {
        for (const item of value) walkForIds(item, ids);
        return;
      }
      if (typeof value === "object") {
        const obj = value as Record<string, unknown>;
        if (typeof obj.id === "number" && Number.isInteger(obj.id) && obj.id > 0) {
          ids.add(obj.id);
        }
        for (const key of Object.keys(obj)) {
          walkForIds(obj[key], ids);
        }
      }
    }
    
    /**
     * Extract the project name from the MCP tool input or response.
     * claude-mem tools accept a `project` parameter and observations include a
     * `project` field — use these directly instead of guessing from cwd.
     */
    function extractProjectFromInput(
      toolInput?: Record<string, unknown>,
      toolResponse?: string,
    ): string | null {
      // 1. Check tool_input.project (most reliable — explicitly passed by Claude)
      if (toolInput && typeof toolInput.project === "string" && toolInput.project) {
        return toolInput.project;
      }
    
      // 2. Check tool_response for a project field in the JSON payload
      if (toolResponse) {
        try {
          const parsed = JSON.parse(toolResponse);
          // Single observation response
          if (typeof parsed.project === "string" && parsed.project) {
            return parsed.project;
          }
          // Direct array of observations (e.g. get_observations returns [{...}])
          const items = Array.isArray(parsed)
            ? parsed
            : (parsed.observations ?? parsed.results ?? parsed.data);
          if (Array.isArray(items)) {
            for (const item of items) {
              if (typeof item?.project === "string" && item.project) {
                return item.project;
              }
            }
          }
        } catch {
          // not JSON — skip
        }
      }
    
      return null;
    }
    
    /**
     * Normalize tool_response to a plain string.
     * Claude Code passes MCP responses as an array of content blocks:
     *   [{ "type": "text", "text": "..." }]
     * We need to extract the text from these blocks.
     */
    function normalizeToolResponse(response: string | McpContentBlock[] | undefined): string | undefined {
      if (!response) return undefined;
      if (typeof response === "string") return response;
      if (Array.isArray(response)) {
        const texts = response
          .filter((block) => block.type === "text" && typeof block.text === "string")
          .map((block) => block.text!);
        return texts.length > 0 ? texts.join("\n") : undefined;
      }
      return undefined;
    }
    
    /**
     * Determine the project name from `cwd` by matching against enabled projects
     * in the config.  Heuristic: check if cwd path contains the project name or
     * the project's `memProject` value.
     */
    function resolveProject(cwd: string): string | null {
      try {
        const config = loadConfig();
        const enabled = getEnabledProjects(config);
        const normalizedCwd = cwd.replace(/\\/g, "/").toLowerCase();
    
        for (const name of enabled) {
          const project = config.projects[name];
          const memProject = project.memProject ?? name;
    
          if (
            normalizedCwd.includes(name.toLowerCase()) ||
            normalizedCwd.includes(memProject.toLowerCase())
          ) {
            return memProject;
          }
        }
    
        // Fallback: return the first enabled project's memProject if only one exists
        if (enabled.length === 1) {
          const name = enabled[0];
          return config.projects[name].memProject ?? name;
        }
    
        return null;
      } catch {
        return null;
      }
    }
    
    // ── Main ───────

Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.

@lopadova
Ships withclaude-mem-sync

Team memory sharing for claude-mem — sync AI memories across developers via git.

Stars on GitHub

Momentum

stars in total
27
Star history of lopadova/claude-mem-sync on GitHub, a chart by star-history.com

More plugins that ship hooks.

superpowers

superpowers

A development methodology for coding agents that makes the agent brainstorm before building, follow plans, run parallel work and finish branches in a disciplined way. You get fewer skipped steps and more consistent results from your coding assistant.

15 skills1 hook311k
@obra@obra
Install Plugin
ponytail

ponytail

A Claude Code plugin with skills for auditing a whole repo, reviewing a change, listing deferred shortcut comments, and showing measured savings and a quick command reference.

6 skills10 hooks188k
@dietrichgebert@dietrichgebert
Install Plugin
agent-skills

agent-skills

Walks a software change from a written spec through design, testing, code review, CI/CD, and release, applying the matching engineering skill at each stage. Useful for developers using Claude Code on full development workflows.

25 skills+3112k
@addyosmani@addyosmani
Install Plugin
planning-with-files

planning-with-files

Persistent file-based planning for AI coding agents on long-running, multi-step tasks. It keeps task_plan.md, findings.md and progress.md on disk, so work can resume after /clear or context compaction.

6 skills+228k
@othmanadi@othmanadi
Install Plugin
gsd-core

gsd-core

A spec-driven development workflow for Claude Code that guides a project through planning, phases, milestone audits and fixes. Includes skills to generate tests from UAT criteria and to audit completed work.

72 skills+311k
@open-gsd@open-gsd
Install Plugin
superpowers-zh

superpowers-zh

Chinese-language skill pack for Claude Code that adds workflow guidance for brainstorming, TDD, debugging, and code review, plus Chinese conventions for commits, documentation, and domestic Git platforms like Gitee and Coding.net.

21 skills1 hook8.5k
@jnmetacode@jnmetacode
Install Plugin
socraticode

socraticode

Gives Claude Code semantic search, dependency graph and architecture context over a codebase, so an AI assistant can explore and understand a project's code. Includes skills for indexing a project and managing its file watching.

2 skills+33.4k
@giancarloerra@giancarloerra
Install Plugin
cocoindex-code

cocoindex-code

A lightweight code search engine that uses AST-based semantic search with local embeddings and incremental indexing. It helps Claude Code users find code faster and more efficiently.

1 skill1 MCP+13k
@cocoindex-io@cocoindex-io
Install Plugin

Questions about the hooks in claude-mem-sync.

Which coding agents can use the hooks in claude-mem-sync?
The hooks in claude-mem-sync install in Claude Code and Cursor: each runs Claude Code hooks from .claude/settings.json, so copy the hooks there.