Skip to main content
3ngram ships two shell scripts that integrate with Claude Code hooks to automate memory capture across your coding sessions. For end-of-session debriefs, use the /debrief prompt template.
Hook scripts are specific to Claude Code. Other MCP clients (Claude Desktop, Cursor, ChatGPT) don’t support hooks, use prompt templates instead.
If you use the 3ngram Telegram or Discord bot, pair hooks with Claude Code Channels to route bot nudges directly into your coding session.

Quick start

  1. Copy the hooks block from scripts/hooks/hooks.example.json into your Claude Code settings (~/.claude/settings.json or project .claude/settings.json):
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "bash /path/to/3ngram/scripts/hooks/3ngram-briefing.sh",
            "statusMessage": "3ngram: Loading session briefing..."
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "bash /path/to/3ngram/scripts/hooks/3ngram-capture.sh"
          }
        ]
      }
    ]
  }
}
  1. Replace /path/to/3ngram with the actual path to your 3ngram clone.
  2. Set two environment variables:
export ENGRAM_API_URL="https://api.3ngram.ai"  # or http://localhost:8000
export ENGRAM_API_KEY="your-api-key"
Generate an API key from the 3ngram dashboard (Settings > API Keys) or via POST /api/keys.

Hook reference

SessionStart: Briefing

Script: 3ngram-briefing.sh Fetches your open commitments, blockers, overdue items, stale work (past configurable staleness threshold), and recent decisions from the 3ngram REST API. Renders a token-budgeted briefing block injected into the session context. All four API calls run in parallel for speed. Falls back to a reminder message if the server is unreachable. Suppressed in secondary git worktrees to avoid duplicate briefings.

PostToolUse: Capture

Script: 3ngram-capture.sh Filters every tool-use event against rules in capture-filter.json. By default, only git commit commands are captured. Each captured event is persisted as a memory via the REST API (POST /api/memories). The script automatically:
  • Derives the project name from the git remote URL
  • Extracts conventional commit tags (feat, fix, etc.) for memory tagging
  • Classifies feat/refactor commits as decisions, everything else as context
  • Persists Claude Code plans (written to ~/.claude/plans/) as commitments so they surface in future briefings
  • Strips <private> tags from content before sending
  • Skips 3ngram’s own MCP tool calls to prevent circular capture

Optional: SessionEnd memory sync

The 3ngram plugin also bundles 3ngram-sync.sh, which performs bidirectional sync of Claude Code’s ~/.claude/projects/*/memory/ directory with 3ngram at session end. To add it manually:
"SessionEnd": [
  {
    "matcher": "",
    "hooks": [
      {
        "type": "command",
        "command": "bash /path/to/3ngram/scripts/hooks/3ngram-sync.sh --both",
        "statusMessage": "3ngram: Syncing memories..."
      }
    ]
  }
]
Requires ENGRAM_API_KEY (separate from the MCP token). Skips silently if the key is not set.

Environment variables

VariableRequiredDefaultDescription
ENGRAM_API_URLYeshttp://localhost:8000REST API endpoint
ENGRAM_API_KEYYes(none)API key for X-API-Key auth
ENGRAM_SCOPENo(none)Scope tag for multi-tenant setups
ENGRAM_HOOK_DEBUGNo0Set to 1 to dump raw payloads to /tmp/3ngram-hook-debug/
BRIEFING_FULL_COUNTNo5Number of items shown with full content in briefings
BRIEFING_MAX_TOKENSNo2000Token budget cap for briefing output

Capture filter rules

The file scripts/hooks/capture-filter.json controls which tool events get captured. Default config captures only git commits:
{
  "rules": [
    {
      "tool": "Bash",
      "command_pattern": "git commit",
      "capture": true,
      "topic_template": "commit: {project}",
      "content_fields": ["command", "stdout"]
    }
  ],
  "defaults": {
    "capture": false
  }
}
Each rule matches on:
  • tool: Tool name (e.g. Bash, Write)
  • command_pattern: Substring match against the command (Bash tool)
  • path_pattern: Substring match against the file path (Write tool)
  • capture: Whether to persist the event as a memory
  • topic_template: Memory topic, supports {project} and {filename} placeholders
  • content_fields: Which fields from the tool input/response to include (single-field rules use the raw value without a label prefix)
  • memory_type: Override memory type for matched events (default: context). Use commitment for items that should surface in briefings.
  • tags: JSON array of tags to apply (e.g. ["plan"]). Overrides the default tag extraction from commit messages.
Set defaults.capture to true to capture all events (noisy, not recommended).

Troubleshooting

Set ENGRAM_HOOK_DEBUG=1 to dump raw payloads to /tmp/3ngram-hook-debug/. Check capture-*.json for PostToolUse events. Disable debug mode after troubleshooting, especially on shared systems, as payloads may contain session content. Common issues:
  • “hook error” on every tool use: All scripts require jq. Install it with your package manager.
  • Briefing shows fallback message: API server unreachable, ENGRAM_API_KEY unset, or jq missing.