PromptHub
Back to Blog
Developer Tools Artificial Intelligence

Claude Subconscious: The Memory Hack Top Devs Are Using

B

Bright Coding

Author

14 min read 94 views
Claude Subconscious: The Memory Hack Top Devs Are Using

Claude Subconscious: The Memory Hack Top Devs Are Using

Every developer knows the pain. You spend three hours deep in flow state with Claude Code, architecting the perfect solution, refining edge cases, establishing patterns. Then life interrupts — a meeting, dinner, sleep. When you return? Gone. Every insight, every decision, every "we agreed to use Zod here" evaporated into the void. Claude greets you with the same blank stare as yesterday, and you're back to square one, repeating yourself like a broken record.

Sound familiar? You're not alone. The #1 complaint about AI coding assistants isn't capability — it's amnesia. These tools are savants with goldfish brains, brilliant in the moment, forgetful the next. But what if your AI pair programmer actually remembered? What if it studied your codebase while you slept, learned your quirks, and whispered insights before you even asked?

That's not science fiction. It's Claude Subconscious — a background agent that gives Claude Code a persistent memory layer, and it's about to change how you code forever.


What Is Claude Subconscious?

Claude Subconscious is an open-source plugin built on the Letta Code SDK that transforms Claude Code from a stateless chatbot into a stateful, learning pair programmer. Created by the team at Letta AI, it's a demo application showcasing what's possible when you combine persistent agent memory with modern coding tools.

Important Note: This is explicitly a demo application, not production software. For a fully supported coding agent with background subconscious capabilities, the Letta team recommends Letta Code, their production-ready open-source alternative.

The concept is elegantly simple yet technically profound. While Claude Code handles your immediate requests, a second Letta agent runs continuously in the background — watching session transcripts, reading your files, building structured memory over time, and injecting contextual guidance back into your workflow. It's not merely logging chat history; it's a cognitive architecture with eight distinct memory blocks, tool access, and the ability to learn and adapt.

What makes this trending now? The timing is perfect. As developers push AI coding assistants to handle larger projects, longer timeframes, and more complex architectures, the context window limitations and session boundaries have become critical bottlenecks. Claude Subconscious attacks this problem at the architectural level, using Letta's Conversations feature to maintain shared memory across multiple parallel sessions.

The result? An AI that doesn't just respond — it evolves with you.


Key Features That Make This Insane

Persistent Cross-Session Memory

The core innovation. Unlike Claude Code's native statelessness, the Subconscious agent maintains eight specialized memory blocks that persist indefinitely: core directives, active guidance, user preferences, project context, session patterns, pending items, self-improvement guidelines, and tool usage patterns. Each session feeds into this growing knowledge base.

Real Codebase Exploration

This isn't passive logging. The Subconscious agent actively reads your files using Read, Grep, and Glob tools while processing transcripts. It explores your codebase architecture, understands your patterns, and builds genuine comprehension — not just keyword matching.

Intelligent Guidance Injection

Before each prompt, the agent evaluates what it knows and whispers relevant context via stdout injection. No CLAUDE.md pollution, no manual documentation. The guidance appears naturally in Claude's context, timed precisely when useful.

Async Background Processing

The Stop hook uses a detached worker pattern — transcript processing happens in a background process via the Letta Code SDK, never blocking your workflow. Claude Code returns instantly; the Subconscious agent continues learning asynchronously.

Multi-Project Shared Brain

One agent serves multiple projects simultaneously. Conversation bookkeeping stays local per project, but the memory blocks are globally shared. Your learned preferences follow you everywhere, or isolate per-project using LETTA_AGENT_ID.

Configurable Tool Access

Via LETTA_SDK_TOOLS, control how much autonomy the Subconscious has: read-only for safe research, full for autonomous edits and sub-agent spawning, or off for memory-only observation.

Smart Model Fallbacks

The plugin auto-detects available models on your Letta server and intelligently falls through a priority list — from letta/auto through Claude Sonnet, GPT-4.1-mini, Gemini variants, and beyond. Never stuck with a broken configuration.


Use Cases Where This Absolutely Shines

1. Long-Running Architecture Projects

You're refactoring a monolith to microservices over three weeks. Without Subconscious, you re-explain the migration strategy every session. With it? The agent remembers your service boundaries, communication patterns, deployment sequence, and reminds you of decisions before you contradict them.

2. Deep Debugging Marathons

That intermittent race condition you've been chasing for days. Subconscious tracks your hypotheses tested, leads pursued, dead ends discovered. When you start repeating an approach, it whispers: "You've checked this lock pattern twice before — consider the connection pool instead."

3. Learning New Codebases

Joining a team with 200K lines of legacy code? The Subconscious agent explores files as you work, building a mental model. Session 20, it reminds you: "The auth middleware in src/utils/ handles this case — you found it three sessions ago."

4. Maintaining Coding Standards

Tired of reminding Claude to use your team's explicit return types, pnpm over npm, specific testing patterns? Subconscious learns from corrections and proactively injects your preferences. It becomes your automated style enforcer.

5. Cross-Project Pattern Recognition

Working across frontend and backend repos? The agent notices when you solve similar problems differently and flags inconsistencies. "You used Zod schemas in api/ but plain types in web/ — intentional divergence?"

6. Managing Technical Debt

The pending_items memory block tracks TODOs, follow-ups, and deferred decisions across sessions. Never lose that "we should cache this" insight buried in session #47's transcript.


Step-by-Step Installation & Setup Guide

Quick Install (Plugin Marketplace)

The fastest path — install directly within Claude Code:

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

Update later with:

/plugin marketplace update
/plugin update claude-subconscious@claude-subconscious

Install from Source

For development or customization:

# Clone the repository
git clone https://github.com/letta-ai/claude-subconscious.git
cd claude-subconscious

# Install dependencies
npm install

Enable the plugin from the cloned directory:

# Local to this project
/plugin enable .

# Or enable globally for all projects
/plugin enable --global .

Note: If enabling from a different directory, use the full path to the cloned repo.

Linux tmpfs Workaround

Some Linux distributions mount /tmp on a separate filesystem, causing EXDEV: cross-device link not permitted errors. This is a known Claude Code bug. Fix it:

# Create a local temp directory
mkdir -p ~/.claude/tmp

# Set TMPDIR for current session
export TMPDIR="$HOME/.claude/tmp"

# Make permanent by adding to your shell profile
echo 'export TMPDIR="$HOME/.claude/tmp"' >> ~/.bashrc  # or ~/.zshrc

Required Configuration

Get your API key from app.letta.com, then:

export LETTA_API_KEY="your-api-key"

That's it for zero-config setup. The plugin auto-imports a default Subconscious agent on first use.

Optional Environment Variables

Fine-tune behavior with these settings:

# Control injection mode: whisper (default), full, or off
export LETTA_MODE="whisper"

# Use a specific agent (for per-project isolation)
export LETTA_AGENT_ID="agent-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# Self-hosted Letta server
export LETTA_BASE_URL="http://localhost:8283"

# Override model selection
export LETTA_MODEL="anthropic/claude-sonnet-4-5"

# Large context window models
export LETTA_CONTEXT_WINDOW="1048576"  # 1M tokens

# Consolidate state to home directory
export LETTA_HOME="$HOME"

# Control Subconscious tool access: read-only (default), full, or off
export LETTA_SDK_TOOLS="read-only"

Add these to your shell profile or use direnv for per-project configuration.


REAL Code Examples from the Repository

Example 1: Understanding the Hook Architecture

The plugin leverages four Claude Code hooks for seamless integration. Here's how the SessionStart hook initializes everything:

// session_start.ts — Runs when Claude Code begins
// Purpose: Notify agent, create conversation, clean legacy state

export default async function sessionStartHook() {
  // Creates new Letta conversation or reuses existing for this session
  const conversation = await lettaClient.conversations.create({
    agent_id: subconsciousAgentId,
  });
  
  // Send structured session notification
  await lettaClient.messages.create(conversation.id, {
    role: "user",
    content: `[Session Start]\nProject: ${projectName}\nPath: ${projectPath}\nSession: ${sessionId}\nStarted: ${new Date().toISOString()}\n\nA new Claude Code session has begun. I'll be sending you updates as the session progresses.`
  });
  
  // Clean up legacy <letta> content from CLAUDE.md automatically
  await cleanupLegacyClaudeMd();
  
  // Persist session mapping for other hooks
  await saveSessionState({ sessionId, conversationId: conversation.id });
}

What's happening here? This hook establishes the bridge between Claude Code and the Letta agent. It creates a dedicated conversation thread, sends a structured notification with project metadata, and ensures no stale <letta> tags pollute your CLAUDE.md. The session state is saved so subsequent hooks know which conversation to use.

Example 2: Memory Injection Before Each Prompt

The UserPromptSubmit hook is where the magic happens — whispering guidance into Claude's ear:

// sync_letta_memory.ts — Runs before each user prompt
// Purpose: Fetch and inject memory + messages

export default async function syncMemoryHook() {
  // Retrieve current memory blocks with full relationship data
  const agent = await lettaClient.agents.retrieve(subconsciousAgentId, {
    include: "agent.blocks"  // Critical: Letta API excludes blocks by default
  });
  
  // Fetch recent messages from Subconscious
  const messages = await lettaClient.messages.list(
    currentConversationId,
    { limit: 10 }
  );
  
  // Format output based on LETTA_MODE
  if (process.env.LETTA_MODE === "full") {
    // First prompt: inject all memory blocks
    if (isFirstPrompt) {
      console.log(formatFullBlocks(agent.memory_blocks));
    } else {
      // Subsequent prompts: only changed blocks as diffs
      console.log(formatBlockDiffs(previousBlocks, agent.memory_blocks));
    }
  }
  
  // Always inject messages from Sub (whisper + full modes)
  for (const msg of messages.filter(m => m.role === "assistant")) {
    console.log(`<letta_message from="Subconscious" timestamp="${msg.created_at}">\n${msg.content}\n</letta_message>`);
  }
}

The critical insight: All injection happens via stdout — nothing touches disk. Claude Code captures this output and includes it in context. The ?include=agent.blocks parameter is essential; without it, the Letta API returns agent metadata without memory contents.

Example 3: Async Transcript Processing with SDK Tools

The Stop hook demonstrates sophisticated async architecture — here's the main hook and its background worker:

// send_messages_to_letta.ts — Runs after each Claude response
// Purpose: Parse transcript, spawn background worker, exit immediately

export default async function stopHook(transcriptJsonl: string) {
  // Parse the JSONL transcript format
  const entries = transcriptJsonl
    .split("\n")
    .filter(line => line.trim())
    .map(line => JSON.parse(line));
  
  // Extract structured data: user messages, assistant responses, 
  // thinking blocks, tool uses, and results
  const payload = {
    session_id: currentSessionId,
    project_path: process.cwd(),
    messages: extractMessages(entries),
    tool_uses: extractToolUses(entries),
    thinking_blocks: extractThinking(entries),
    timestamp: new Date().toISOString()
  };
  
  // Write to temp file for worker process
  const tempFile = path.join(os.tmpdir(), `letta-transcript-${Date.now()}.json`);
  await fs.writeFile(tempFile, JSON.stringify(payload));
  
  // Spawn detached background worker — exits immediately, never blocks
  const worker = spawn(process.execPath, [
    path.join(__dirname, "send_worker_sdk.ts"),
    tempFile,
    subconsciousAgentId,
    currentConversationId
  ], {
    detached: true,      // Independent process
    stdio: "ignore"      // No need to wait for output
  });
  
  worker.unref();  // Allow parent to exit without waiting
}

And the background worker that does the heavy lifting:

// send_worker_sdk.ts — Background process
// Purpose: Full SDK session with tool access for Subconscious

async function processTranscriptWithSdk(tempFilePath: string, agentId: string, conversationId: string) {
  // Open Letta Code SDK session — gives Sub client-side tools
  const sdk = new LettaCodeSDK({
    api_key: process.env.LETTA_API_KEY,
    base_url: process.env.LETTA_BASE_URL || "https://api.letta.com"
  });
  
  // Read the transcript payload
  const payload = JSON.parse(await fs.readFile(tempFilePath, "utf-8"));
  
  // Send to agent with full tool access — Sub can now Read, Grep, Glob, web_search
  const response = await sdk.sessions.sendMessage(conversationId, {
    role: "user",
    content: formatTranscriptForAgent(payload),
    // SDK tools enabled based on LETTA_SDK_TOOLS setting
    tool_context: getSdkToolsConfig()
  });
  
  // Agent processes transcript, explores codebase, updates memory
  // Response stream includes all tool calls and memory updates
  
  // Clean up on success
  await fs.unlink(tempFilePath);
  await updateSyncState({ lastProcessedIndex: payload.messages.length });
}

Why this architecture matters: The main hook completes in milliseconds. The background worker may take minutes to fully process a complex session with extensive codebase exploration. By using a detached process, Claude Code's responsiveness is never compromised. The SDK session gives the Subconscious agent genuine tool access — it's not just receiving text, it's actively investigating your code.


Advanced Usage & Best Practices

Optimize Memory Quality with Explicit Signals

The Subconscious learns from corrections, but you can accelerate training. When you disagree with Claude, explicitly state your preference: "Actually, I prefer explicit return types here." These statements get captured in transcripts and weighted heavily in user_preferences.

Use full Mode for Complex Projects

Default whisper mode is lightweight, but for deep architectural work, switch to full:

export LETTA_MODE="full"

This injects complete memory blocks on first prompt and diffs thereafter. Higher token usage, but maximum context awareness.

Isolate Agents Per Project with direnv

For clean separation between work and personal projects:

# .envrc in project root
export LETTA_AGENT_ID="agent-work-specific"
export LETTA_MODE="full"
export LETTA_SDK_TOOLS="full"  # More autonomy for trusted projects

Run direnv allow — now this project gets its own brain.

Monitor Background Worker Health

Check if async processing is working:

# Watch worker logs in real-time
tail -f /tmp/letta-claude-sync-$(id -u)/send_worker_sdk.log

If logs aren't updating, the worker may be crashing — check send_messages.log for spawn errors.

Choose Models Strategically

The default zai/glm-5 is free on Letta Cloud but limited. For serious work:

export LETTA_MODEL="anthropic/claude-sonnet-4-5"  # Best reasoning
# Or for budget-conscious:
export LETTA_MODEL="openai/gpt-4.1-mini"  # 1M context, cost-effective

Prune Stale Memory Blocks

Over months, memory can accumulate noise. Periodically review via app.letta.com and edit blocks directly. The self_improvement block even contains guidelines for the agent to optimize its own memory architecture.


Comparison with Alternatives

Feature Claude Subconscious Native CLAUDE.md Custom Prompts Letta Code
Persistence ✅ Automatic, structured ❌ Manual, static ❌ Per-session ✅ Automatic, advanced
Codebase Learning ✅ Active exploration ❌ None ❌ None ✅ Active + deeper
Cross-Session Memory ✅ Shared globally ❌ File-local ❌ None ✅ Multi-agent
Background Processing ✅ Async, non-blocking ❌ N/A ❌ N/A ✅ Integrated
Setup Complexity Medium (API key) Low Low Medium
Production Ready ❌ Demo only ✅ Yes ✅ Yes ✅ Yes
Tool Access for Memory Agent ✅ Read/Search/Edit ❌ N/A ❌ N/A ✅ Full suite
Cost Letta API usage Free Free Letta API usage

When to choose what:

  • CLAUDE.md: Quick projects, simple conventions, no persistence needed
  • Claude Subconscious: Learning the pattern, demo exploration, personal productivity hacking
  • Letta Code: Production work, team deployment, need full support and reliability

FAQ

Is Claude Subconscious production-ready?

No. It's explicitly a demo application built on the Letta Code SDK. For production use, migrate to Letta Code, which is fully open source and supported.

Does this modify my codebase or CLAUDE.md?

Never. All content injects via stdout into prompt context. The plugin actually cleans up legacy <letta> content from CLAUDE.md automatically.

How much does it cost?

You need a Letta API key. Usage depends on model choice — zai/glm-5 is free on Letta Cloud; other models incur standard provider costs. The background worker's tool usage adds token consumption.

Can I use my own custom agent?

Yes! Set LETTA_AGENT_ID to any Letta agent you've built. It will use your agent's existing memory architecture instead of the default Subconscious template.

What happens if the Letta API is down?

The plugin degrades gracefully. Hooks time out (5-10s) and Claude Code continues normally. No blocking failures. Check logs to diagnose.

Is my code sent to third parties?

Transcripts go to your configured Letta server (default: Letta Cloud). The Subconscious agent may search the web if configured. For sensitive code, self-host Letta with LETTA_BASE_URL.

How do I completely remove it?

/plugin uninstall claude-subconscious@claude-subconscious

Delete ~/.letta/claude-subconscious/ for agent state, and project .letta/claude/ directories for conversation bookkeeping.


Conclusion

Claude Subconscious exposes a truth we've all felt: the biggest limitation in AI coding isn't intelligence — it's continuity. Every session reset is a tiny death of context, a tax on productivity we pay silently, repeatedly. This plugin proves we don't have to.

The technical architecture is genuinely clever — async workers, structured memory blocks, stdout injection, SDK tool access. But the vision is what sticks: an AI that grows with you, that learns your quirks, that whispers "you've been here before" at exactly the right moment.

Is it perfect? No. It's a demo, with demo roughness. The Letta team is clear about that. But it's a glimpse of where we're headed — and for developers willing to tinker, it's usable today.

My recommendation? Install it. Run it for a week on a side project. Watch the guidance evolve from generic to eerily specific. Feel the difference when Claude greets you with "Continuing the auth refactor from Tuesday?" instead of "Hello! How can I help?"

Then decide: is this the future you want to code in?

→ Install Claude Subconscious from GitHub

→ Explore production-ready Letta Code


Found this breakdown useful? Star the repo, share with your team, and let me know what your Subconscious learns about you.

Comments (0)

Comments are moderated before appearing.

No comments yet. Be the first to share your thoughts!

All tools