Skip to content
Agent Memory
Hook

Hooks

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

From plugin
claude-subconscious
2.9k4 hooks

Claude Code

> /plugin marketplace add letta-ai/claude-subconscious
> /plugin install claude-subconscious@claude-subconscious

What fires, and when

SessionStart

Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.

  • Matches*node "${CLAUDE_PLUGIN_ROOT:-.}/hooks/silent-npx.cjs" tsx "${CLAUDE_PLUGIN_ROOT:-.}/scripts/session_start.ts"node "${CLAUDE_PLUGIN_ROOT:-.}/hooks/silent-npx.cjs" tsx "${CLAUDE_PLUGIN_ROOT:-.}/scripts/sync_letta_memory.ts"

PreToolUse

  • Matches*node "${CLAUDE_PLUGIN_ROOT:-.}/hooks/silent-npx.cjs" tsx "${CLAUDE_PLUGIN_ROOT:-.}/scripts/pretool_sync.ts"

UserPromptSubmit

Fires before Claude sees each prompt you send. A plugin can use it to inject context, so the same instruction reaches the model every turn instead of only at session start.

  • Matches*node "${CLAUDE_PLUGIN_ROOT:-.}/hooks/silent-npx.cjs" tsx "${CLAUDE_PLUGIN_ROOT:-.}/scripts/sync_letta_memory.ts"

Stop

  • Matches*node "${CLAUDE_PLUGIN_ROOT:-.}/hooks/silent-npx.cjs" tsx "${CLAUDE_PLUGIN_ROOT:-.}/scripts/send_messages_to_letta.ts"
Read hooks/hooks.json

Where it lives

  • hooks/build.ps1GitHub
    Read the script
    # Build silent-launcher.exe from SilentLauncher.cs
    # Requires .NET Framework csc.exe (ships with Windows)
    #
    # Usage: powershell -ExecutionPolicy Bypass -File hooks/build.ps1
    
    $ErrorActionPreference = 'Stop'
    $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
    $cs = Join-Path $scriptDir 'SilentLauncher.cs'
    $exe = Join-Path $scriptDir 'silent-launcher.exe'
    
    # Find csc.exe from the .NET Framework directory
    $csc = Join-Path $env:WINDIR 'Microsoft.NET\Framework64\v4.0.30319\csc.exe'
    if (-not (Test-Path $csc)) {
        $csc = Join-Path $env:WINDIR 'Microsoft.NET\Framework\v4.0.30319\csc.exe'
    }
    if (-not (Test-Path $csc)) {
        Write-Error "csc.exe not found. Ensure .NET Framework 4.x is installed."
        exit 1
    }
    
    Write-Host "Building silent-launcher.exe ..."
    & $csc /nologo /out:$exe /platform:anycpu /target:winexe $cs
    
    if ($LASTEXITCODE -eq 0) {
        Write-Host "Built: $exe"
    } else {
        Write-Error "Build failed (exit code $LASTEXITCODE)"
        exit $LASTEXITCODE
    }
    
  • hooks/silent-npx.cjsRunsGitHub
    Read the script
    #!/usr/bin/env node
    /**
     * Cross-platform launcher for Claude Subconscious hooks.
     *
     * On Windows: delegates to silent-launcher.exe which creates a headless
     * PseudoConsole (ConPTY) + CREATE_NO_WINDOW to eliminate console window
     * flashes on Windows 11 / Windows Terminal.
     *
     * On other platforms: runs tsx directly via node — no console issue.
     *
     * Called from hooks.json as:
     *   node hooks/silent-npx.cjs tsx scripts/<script>.ts
     */
    const { spawn } = require('child_process');
    const path = require('path');
    const fs = require('fs');
    
    const isWindows = process.platform === 'win32';
    const args = process.argv.slice(2); // e.g. ['tsx', 'path/to/script.ts']
    
    let child;
    
    if (args[0] === 'tsx') {
      let scriptArgs = args.slice(1); // everything after 'tsx'
      const pluginRoot = path.resolve(__dirname, '..');
    
      // Fix for #34: If CLAUDE_PLUGIN_ROOT was empty, script paths resolve to
      // absolute paths like "/scripts/foo.ts" which don't exist. Re-resolve
      // them relative to the plugin root (which we know from __dirname).
      scriptArgs = scriptArgs.map(arg => {
        if (!fs.existsSync(arg) && arg.includes('/scripts/')) {
          const basename = path.basename(arg);
          const resolved = path.join(pluginRoot, 'scripts', basename);
          if (fs.existsSync(resolved)) return resolved;
        }
        return arg;
      });
      const tsxCli = path.join(pluginRoot, 'node_modules', 'tsx', 'dist', 'cli.mjs');
    
      if (isWindows) {
        const silentLauncher = path.join(__dirname, 'silent-launcher.exe');
    
        if (fs.existsSync(silentLauncher) && fs.existsSync(tsxCli)) {
          // PseudoConsole + CREATE_NO_WINDOW: popup-free execution
          child = spawn(silentLauncher, ['node', tsxCli, ...scriptArgs], {
            stdio: 'inherit',
            windowsHide: true,
          });
        } else if (fs.existsSync(tsxCli)) {
          // Fallback: run tsx CLI directly (may flash on Windows Terminal)
          child = spawn(process.execPath, [tsxCli, ...scriptArgs], {
            stdio: 'inherit',
            windowsHide: true,
          });
        } else {
          // Last resort: npx through shell
          child = spawn('npx', args, {
            stdio: 'inherit',
            shell: true,
            windowsHide: true,
          });
        }
      } else {
        // Non-Windows: no console window issues
        if (fs.existsSync(tsxCli)) {
          child = spawn(process.execPath, [tsxCli, ...scriptArgs], {
            stdio: 'inherit',
          });
        } else {
          child = spawn('npx', args, {
            stdio: 'inherit',
          });
        }
      }
    } else {
      // Non-tsx command: use npx
      child = spawn('npx', args, {
        stdio: 'inherit',
        shell: isWindows,
        windowsHide: isWindows,
      });
    }
    
    child.on('exit', (code) => {
      process.exit(code || 0);
    });
    
    child.on('error', (err) => {
      console.error('Failed to start subprocess:', err);
      process.exit(1);
    });
    
  • hooks/stdio-preload.cjsGitHub
    Read the script
    // Preload: delivers stdin from temp file via unshift, captures stdout to temp file.
    // Loaded via --require in the node command line.
    // Used with PseudoConsole + CREATE_NO_WINDOW where pipe I/O is not available.
    'use strict';
    
    const fs = require('fs');
    const stdoutFile = process.env.SL_STDOUT_FILE;
    const stdinFile = process.env.SL_STDIN_FILE;
    
    // --- STDIN: Read from temp file, unshift onto existing Socket ---
    if (stdinFile) {
      try {
        const data = fs.readFileSync(stdinFile);
        if (data.length > 0) {
          const sock = process.stdin;
          sock.pause();
          sock.unshift(data);
          process.nextTick(() => sock.push(null));
        }
      } catch (e) { /* stdin file may not exist */ }
    }
    
    // --- STDOUT/STDERR: Capture all writes to temp file ---
    if (stdoutFile) {
      try {
        const fd = fs.openSync(stdoutFile, 'a');
    
        const origWrite = process.stdout.write.bind(process.stdout);
        process.stdout.write = function(chunk, encoding, callback) {
          try {
            const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, typeof encoding === 'string' ? encoding : 'utf8');
            fs.writeSync(fd, buf);
          } catch (e) { /* ignore write errors */ }
          return origWrite(chunk, encoding, callback);
        };
    
        const origErrWrite = process.stderr.write.bind(process.stderr);
        process.stderr.write = function(chunk, encoding, callback) {
          try {
            const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, typeof encoding === 'string' ? encoding : 'utf8');
            fs.writeSync(fd, buf);
          } catch (e) { /* ignore write errors */ }
          return origErrWrite(chunk, encoding, callback);
        };
    
        process.on('exit', () => {
          try { fs.closeSync(fd); } catch(e) {}
        });
      } catch (e) { /* stdout setup error */ }
    }
    

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.

Stats
2,910
Stars
225
Forks
Maintained
Maintenance
TypeScript
Language
MIT
License
Last commit
Created

Repo: letta-ai/claude-subconscious

@letta-ai
Ships withclaude-subconscious

A background agent that whispers to Claude Code. A subconscious agent that watches your sessions, reads your files, builds up memory over time, and whispers guidance back.

Stars on GitHub

Momentum

stars in total
2.9k
Star history of letta-ai/claude-subconscious on GitHub, a chart by star-history.com

More plugins that ship hooks.

mempalace

mempalace

Local-first memory for Claude Code. It stores conversations verbatim in a private palace you can search before answering about past work, people, projects, or decisions, with optional shared-brain hub setup.

3 skills+361k
@mempalace@mempalace
Install Plugin
mempalace

mempalace

Gives Claude Code a private memory that stays on your machine. It stores past conversations word for word, so you can ask what was decided, what happened before, or who was involved and get the original context back. It can also hand tasks to other agents.

3 skills+360k
@milla-jovovich@milla-jovovich
Install Plugin
mksglu-context-mode

mksglu-context-mode

Keeps large tool outputs, logs, and files out of Claude Code's context window by processing them in a sandbox and indexing them for focused search. Includes diagnostics and a knowledge base indexer.

9 skills+233k
@mksglu@mksglu
Install Plugin
context-mode

context-mode

Keeps large command outputs, logs and data files out of your AI assistant's context by running processing in a sandbox and returning only the relevant parts. You also get a searchable index of local files and diagnostics for checking the setup.

9 skills+233k
@mksglu@mksglu
Install Plugin
ai-memory

ai-memory

Gives coding agents a git-backed wiki for long-term project memory, with skills for retrieval, durable notes, session handoffs between agents, cross-project messaging, and memory consolidation.

7 skills+216k
@akitaonrails@akitaonrails
Install Plugin
letta-code

letta-code

A coding agent harness whose agents keep memory and identity across sessions, so they learn and improve over time. You can run it in a terminal, in the browser, or through Telegram, Slack and Discord.

26 skills8 hooks3.8k
@letta-ai@letta-ai
Install Plugin
token-optimizer

token-optimizer

Audits a Claude Code or Codex setup for context-window waste, fixes it with the user's approval, and measures the savings. It also tracks costs, helps resume prior sessions, and offers a usage dashboard.

5 skills+22.8k
@alexgreensh@alexgreensh
Install Plugin
claude-reflect

claude-reflect

A self-learning system for Claude Code that captures your corrections during sessions and reminds you to run /reflect to save them to CLAUDE.md as permanent memory. It also discovers recurring workflow patterns.

1 skill+21.9k
@bayramannakov@bayramannakov
Install Plugin

Questions about the hooks in claude-subconscious.

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