Skip to content
Automation
Hook

Hooks

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

From plugin
recall
182 hooks

Where it lives

  • hooks/capture-session.shGitHub
    Read the script
    #!/usr/bin/env bash
    # recall :: capture hook (Stop)
    # Idempotent per session_id. Writes a lightweight markdown dump pointing at the
    # full transcript, so the nightly distill can read sessions without an LLM call here.
    # Pure shell + jq + git. Never blocks Claude: always exits 0.
    
    set -uo pipefail
    
    VAULT="${RECALL_VAULT:-$HOME/Documents/Vault/recall}"
    SESSIONS="$VAULT/sessions"
    
    # Don't capture distill's own headless claude runs (recursion guard).
    [ -n "${RECALL_DISTILL:-}" ] && exit 0
    
    PAYLOAD=$(cat)
    
    # Only act on the Stop event regardless of how we're wired.
    EVENT=$(printf '%s' "$PAYLOAD" | jq -r '.hook_event_name // empty')
    [ "$EVENT" = "Stop" ] || { [ -n "$EVENT" ] && exit 0; }
    
    SESSION_ID=$(printf '%s' "$PAYLOAD" | jq -r '.session_id // empty')
    CWD=$(printf '%s' "$PAYLOAD" | jq -r '.cwd // empty')
    TRANSCRIPT=$(printf '%s' "$PAYLOAD" | jq -r '.transcript_path // empty')
    LAST_MSG=$(printf '%s' "$PAYLOAD" | jq -r '.last_assistant_message // empty' | tr '\n' ' ' | head -c 500)
    
    [ -n "$SESSION_ID" ] || exit 0
    [ -n "$CWD" ] || CWD="$PWD"
    
    # Project identity: git repo root basename, else launch-dir basename.
    if REPO=$(git -C "$CWD" rev-parse --show-toplevel 2>/dev/null); then
      PROJECT=$(basename "$REPO")
      BRANCH=$(git -C "$CWD" rev-parse --abbrev-ref HEAD 2>/dev/null)
      DIFFSTAT=$(git -C "$CWD" diff --stat 2>/dev/null | tail -40)
      STATUS=$(git -C "$CWD" status --short 2>/dev/null | head -40)
    else
      PROJECT=$(basename "$CWD")
      BRANCH=""
      DIFFSTAT=""
      STATUS=""
    fi
    
    SHORT="${SESSION_ID:0:8}"
    mkdir -p "$SESSIONS"
    
    # One dump per session_id — NOT per project. A session that changes git-repo
    # context mid-run (cd into another repo, or a repo rename) would otherwise fork
    # into a second dump and get distilled twice. Reuse the existing dump if one
    # already exists for this session_id, keeping its original project-named file.
    FILE=""
    for existing in "$SESSIONS"/*__"$SHORT".md; do
      [ -f "$existing" ] || continue
      if grep -q "^session_id: $SESSION_ID\$" "$existing"; then FILE="$existing"; break; fi
    done
    [ -n "$FILE" ] || FILE="$SESSIONS/${PROJECT}__${SHORT}.md"
    
    # Preserve original Started timestamp across turns.
    NOW=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
    if [ -f "$FILE" ]; then
      STARTED=$(grep -m1 '^started:' "$FILE" | sed 's/^started: //')
    fi
    [ -n "${STARTED:-}" ] || STARTED="$NOW"
    
    {
      echo "---"
      echo "session_id: $SESSION_ID"
      echo "project: $PROJECT"
      echo "branch: ${BRANCH:-}"
      echo "cwd: $CWD"
      echo "started: $STARTED"
      echo "updated: $NOW"
      echo "transcript: $TRANSCRIPT"
      echo "distilled: false"
      echo "tags: [recall/session]"
      echo "---"
      echo
      echo "# Session $SHORT — $PROJECT"
      echo
      echo "## Last assistant message"
      echo "${LAST_MSG:-(none)}"
      echo
      echo "## Git diff --stat"
      echo '```'
      echo "${DIFFSTAT:-(no repo / no changes)}"
      echo '```'
      echo
      echo "## Git status"
      echo '```'
      echo "${STATUS:-(no repo / clean)}"
      echo '```'
    } > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
    
    exit 0
    
  • hooks/inject-knowledge.shGitHub
    Read the script
    #!/usr/bin/env bash
    # recall :: SessionStart hook — injects vault knowledge indexes as
    # additional context. Read-only, never modifies project files. Fails open:
    # any error -> exit 0 silently so a broken vault never blocks session start.
    #
    # Fires on all SessionStart sources (startup, resume, clear, compact) so
    # context survives /clear and auto-compact too.
    
    set +e  # never die
    
    VAULT="${RECALL_VAULT:-$HOME/Documents/Vault/recall}"
    KNOWLEDGE="$VAULT/knowledge"
    [ -d "$KNOWLEDGE" ] || exit 0
    
    # Project = git root basename, else cwd basename. Matches capture-session.sh.
    CWD="$PWD"
    if REPO=$(git -C "$CWD" rev-parse --show-toplevel 2>/dev/null); then
      PROJECT=$(basename "$REPO")
      SKILLS_DIR="$REPO/.claude/skills"
    else
      PROJECT=$(basename "$CWD")
      SKILLS_DIR="$CWD/.claude/skills"
    fi
    
    # Compose the context block. Tagged so Claude can recognize it as background.
    CTX=$(
      echo "<recall-knowledge>"
      echo "Indexes from your knowledge vault. Read full notes on demand:"
      echo "  $KNOWLEDGE/global/<name>.md  or  $KNOWLEDGE/projects/$PROJECT/<name>.md"
      echo
    
      [ -f "$KNOWLEDGE/global/INDEX.md" ] && { cat "$KNOWLEDGE/global/INDEX.md"; echo; }
    
      PROJ_INDEX="$KNOWLEDGE/projects/$PROJECT/INDEX.md"
      if [ -f "$PROJ_INDEX" ]; then
        cat "$PROJ_INDEX"; echo
      else
        echo "# $PROJECT knowledge"
        echo "(no project notes yet — distill will populate as sessions accumulate)"
        echo
      fi
    
      # Live list of installed skills for this project (read each SKILL.md's
      # frontmatter description). Computed live so newly-installed skills appear
      # the same day, without waiting on a vault refresh.
      if [ -d "$SKILLS_DIR" ]; then
        found=0
        for sk in "$SKILLS_DIR"/*/SKILL.md; do
          [ -f "$sk" ] || continue
          [ "$found" -eq 0 ] && { echo "# $PROJECT installed skills"; found=1; }
          sk_name=$(basename "$(dirname "$sk")")
          sk_desc=$(awk '/^description:/ {sub(/^description: */,""); print; exit}' "$sk")
          echo "- $sk_name — ${sk_desc:-<no description>}"
        done
        [ "$found" -eq 1 ] && echo
      fi
    )
    
    # Enforce an injection budget so a large index can't bloat every session's
    # context. Mirrors Claude Code's auto-memory cap — first 200 lines OR 25KB,
    # whichever comes first. Truncates on whole-line boundaries (keeps valid UTF-8)
    # and leaves a visible marker, so nothing is dropped silently.
    MAX_LINES="${RECALL_INJECT_MAX_LINES:-200}"
    MAX_BYTES="${RECALL_INJECT_MAX_BYTES:-25600}"
    truncated=0
    if [ "$(printf '%s\n' "$CTX" | wc -l | tr -d ' ')" -gt "$MAX_LINES" ]; then
      CTX="$(printf '%s\n' "$CTX" | head -n "$MAX_LINES")"; truncated=1
    fi
    while [ "$(printf '%s' "$CTX" | wc -c | tr -d ' ')" -gt "$MAX_BYTES" ] \
       && [ "$(printf '%s\n' "$CTX" | wc -l | tr -d ' ')" -gt 1 ]; do
      CTX="$(printf '%s\n' "$CTX" | sed '$d')"; truncated=1
    done
    
    # Read the hook event name from stdin (SessionStart for all sources). Default
    # to SessionStart if stdin parse fails — the value is informational only.
    STDIN_JSON=$(cat 2>/dev/null)
    EVENT=$(printf '%s' "$STDIN_JSON" | jq -r '.hook_event_name // "SessionStart"' 2>/dev/null)
    [ -z "$EVENT" ] && EVENT="SessionStart"
    
    # Emit JSON with additionalContext. jq -R -s --arg handles all escaping safely.
    {
      printf '%s\n' "$CTX"
      [ "$truncated" -eq 1 ] && printf '… recall: knowledge index truncated to the injection budget (%s lines / %s bytes). Read the full indexes on demand under %s\n' "$MAX_LINES" "$MAX_BYTES" "$KNOWLEDGE"
      echo "</recall-knowledge>"
    } | jq -R -s --arg event "$EVENT" \
      '{hookSpecificOutput: {hookEventName: $event, additionalContext: .}}'
    
    exit 0
    

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.

@maxdmyers
Ships withrecall

A self-improving layer for Claude Code: it learns from your sessions, retains knowledge in a vault, and proposes skills/automations from recurring patterns. This repo holds the machinery (hooks, distill prompt + runner, dashboard, install config).

Stars on GitHub

Momentum

stars in total
18
Star history of maxdmyers/recall on GitHub, a chart by star-history.com

More plugins that ship hooks.

n8n-mcp-skills

n8n-mcp-skills

Expert Claude Code skills for building flawless n8n workflows using the n8n-mcp MCP server.

15 skills3 hooks6.6k
@czlonkowski@czlonkowski
Install Plugin
claude-scholar

claude-scholar

A research assistant plugin for Claude Code that supports literature review, paper writing, citation verification, Zotero and Obsidian integration, and code review and debugging for academic and software work.

45 skills+35.9k
@galaxy-dawn@galaxy-dawn
Install Plugin
octo

octo

Runs multi-AI workflows in Claude Code that split research, requirements scoping, implementation and review across several external AI providers, such as Codex, Gemini-style CLIs, Copilot, Ollama and OpenRouter, to cover each model's blind spots.

71 skills+34.4k
@nyldn@nyldn
Install Plugin
ai-maestro

ai-maestro

Orchestrates multiple Claude Code agents across terminals and machines, giving them persistent memory and agent-to-agent messaging so you no longer have to relay messages between them by hand.

33 hooks1 MCP841
@23blocks-os@23blocks-os
Install Plugin
godotmaker

godotmaker

An autonomous pipeline that turns a text description into a playable Godot game, generating design docs, game assets such as backgrounds, characters, props, cards and effects, and running visual checks and playtests.

41 skills+2559
@randallliuxin@randallliuxin
Install Plugin
sutando

sutando

A personal AI assistant with voice, screen and meeting support that learns your patterns and can update its own code. It runs across several Macs and can talk with other people's assistants.

79 skills18 hooks401
@sonichi@sonichi
Install Plugin
nextboard-hardware-solution

nextboard-hardware-sol…

Helps hardware teams turn product requirements into a reviewable, buildable PCB design plan. Covers embedded architecture, MCU or SoC selection, power tree, interfaces, sensors, connectivity, and BOM risk.

1 skill+2395
@leokemp223@leokemp223
Install Plugin
claude-prompts

claude-prompts

MCP server for reusable prompt templates, multi-step workflow chains, and quality gates. Compose agentic workflows with an operator syntax; export as native skills to Claude Code, Cursor, OpenCode, and Gemini CLI.

5 hooks1 MCP191
@minipuft@minipuft
Install Plugin

Questions about the hooks in recall.

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