# How the Claude-Subconscious Plugin Handles Cleaning Up Legacy <letta> Content from CLAUDE.md

> Learn how the Claude-Subconscious plugin automatically cleans legacy <letta> content from CLAUDE.md. Prevent duplicate data with the cleanLettaFromClaudeMd utility. Explore the script for details.

- Repository: [Letta/claude-subconscious](https://github.com/letta-ai/claude-subconscious)
- Tags: how-to-guide
- Published: 2026-03-26

---

**The Claude-Subconscious plugin automatically purges stale `<letta>` memory blocks from [`CLAUDE.md`](https://github.com/letta-ai/claude-subconscious/blob/main/CLAUDE.md) using the `cleanLettaFromClaudeMd` utility in [`scripts/conversation_utils.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/scripts/conversation_utils.ts), preventing duplicate or obsolete data from persisting across sessions.**

When upgrading the **letta-ai/claude-subconscious** plugin, existing [`CLAUDE.md`](https://github.com/letta-ai/claude-subconscious/blob/main/CLAUDE.md) files may contain outdated `<letta>` sections from previous versions. To maintain data integrity, the plugin implements an aggressive cleanup routine that executes during session initialization and memory synchronization. This article explains the exact mechanism for cleaning up legacy `<letta>` content from CLAUDE.md based on the source code implementation.

## How Legacy Content Detection Works

The cleanup process begins by locating the target file and identifying specific marker patterns that denote plugin-generated content.

### Locating the Target CLAUDE.md File

The `cleanLettaFromClaudeMd` function first determines which directory to process. It checks the `LETTA_PROJECT` environment variable, falling back to the provided project directory:

```typescript
const base = process.env.LETTA_PROJECT || projectDir;
const claudeMdPath = path.join(base, CLAUDE_MD_PATH);

```

If the file does not exist at the resolved path, the function returns immediately without performing any filesystem operations.

### Pattern Matching for Legacy Sections

Legacy content is delimited by markers defined as `LETTA_SECTION_START` and `LETTA_SECTION_END` in [`scripts/conversation_utils.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/scripts/conversation_utils.ts). The code constructs a **multiline RegExp** that captures everything between these markers, including surrounding line breaks:

```typescript
const lettaPattern = `^${escapeRegex(LETTA_SECTION_START)}[\\s\\S]*?^${escapeRegex(LETTA_SECTION_END)}\\n*`;
const lettaRegex = new RegExp(lettaPattern, 'gm');

```

## The Step-by-Step Cleanup Algorithm

Once patterns are established, the algorithm executes a sequential removal process to ensure complete sanitization of the file.

### Removing Main <letta> Blocks

The primary cleanup targets the main legacy blocks. The function resets the regex index and performs a global replace:

```typescript
lettaRegex.lastIndex = 0;
let cleaned = content.replace(lettaRegex, '');

```

### Stripping Orphaned <letta_message> Tags

Older plugin versions occasionally left stray `<letta_message>` elements. These are purged using a secondary multiline pattern:

```typescript
const messagePattern = /^<letta_message>[\s\S]*?^<\/letta_message>\n*/gm;
cleaned = cleaned.replace(messagePattern, '');

```

### Eliminating Auto-Generated Boilerplate

The routine removes specific auto-generated comments and headers injected by previous plugin versions:

```typescript
cleaned = cleaned.replace(/<!-- Letta agent memory is automatically synced below -->\n*/g, '');
cleaned = cleaned.replace(/^# Project Context\n*/gm, '');

```

### Handling Empty File Cleanup

After stripping content, the function evaluates the remaining text. If the file contains only whitespace or is empty, it deletes the file entirely rather than leaving a zero-length document:

```typescript
if (cleaned.length === 0) {
  fs.unlinkSync(claudeMdPath);
} else {
  fs.writeFileSync(claudeMdPath, cleaned + '\n', 'utf-8');
}

```

## Invocation Points in the Session Lifecycle

The plugin triggers cleanup at critical junctures to guarantee a clean state before writing new memory data.

### Session Initialization Cleanup

In [`scripts/session_start.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/scripts/session_start.ts), the plugin invokes cleanup immediately after obtaining a conversation ID. It processes both the current working directory and the global `~/.claude` directory when they differ:

```typescript
cleanLettaFromClaudeMd(hookInput.cwd);
const homeDir = process.env.HOME || os.homedir();
if (homeDir !== hookInput.cwd) cleanLettaFromClaudeMd(homeDir);

```

### Memory Synchronization Cleanup

Before writing fresh memory blocks, [`scripts/sync_letta_memory.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/scripts/sync_letta_memory.ts) calls the same utility to ensure no legacy sections remain:

```typescript
cleanLettaFromClaudeMd(cwd);

```

This pre-write sanitization prevents the accumulation of duplicate memory sections across sync operations.

## Implementing Manual Cleanup

For scenarios requiring explicit cleanup outside the automated session flow, import the utility directly:

```typescript
import { cleanLettaFromClaudeMd } from '../scripts/conversation_utils';
import * as path from 'path';

const projectRoot = path.resolve(__dirname, '..');
cleanLettaFromClaudeMd(projectRoot);

```

Executing this code locates [`CLAUDE.md`](https://github.com/letta-ai/claude-subconscious/blob/main/CLAUDE.md) in the specified directory, removes all legacy markers, deletes the file if empty, or writes the cleaned content back to disk.

## Summary

- The **letta-ai/claude-subconscious** plugin uses **`cleanLettaFromClaudeMd`** in [`scripts/conversation_utils.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/scripts/conversation_utils.ts) to sanitize [`CLAUDE.md`](https://github.com/letta-ai/claude-subconscious/blob/main/CLAUDE.md) files.
- Detection relies on **multiline regular expressions** matching `LETTA_SECTION_START`/`END` markers and orphaned `<letta_message>` tags.
- The algorithm removes auto-generated boilerplate including HTML comments and "Project Context" headers.
- Cleanup executes during **session start** ([`session_start.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/session_start.ts)) and **memory sync** ([`sync_letta_memory.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/sync_letta_memory.ts)) to prevent data duplication.
- Empty files resulting from complete cleanup are automatically deleted via `fs.unlinkSync`.

## Frequently Asked Questions

### What triggers the cleanup of legacy <letta> content?

The cleanup routine triggers automatically during two specific events: when a new session initializes in [`scripts/session_start.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/scripts/session_start.ts) and before every memory synchronization in [`scripts/sync_letta_memory.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/scripts/sync_letta_memory.ts). These dual invocation points ensure that [`CLAUDE.md`](https://github.com/letta-ai/claude-subconscious/blob/main/CLAUDE.md) is always sanitized before new content is written.

### How does the plugin distinguish legacy content from user data?

The plugin identifies legacy content through strict marker-based pattern matching. It searches for text wrapped between `LETTA_SECTION_START` and `LETTA_SECTION_END` constants, orphaned `<letta_message>` XML tags, and specific auto-generated strings like the HTML comment `<!-- Letta agent memory is automatically synced below -->`. User content outside these markers remains untouched.

### What happens to CLAUDE.md if all content is removed?

If the cleanup process results in an empty string—meaning the file contained only plugin-generated sections—the function deletes [`CLAUDE.md`](https://github.com/letta-ai/claude-subconscious/blob/main/CLAUDE.md) entirely using `fs.unlinkSync`. This prevents the accumulation of zero-length files in the project directory.

### Can I run the cleanup manually outside of automated sessions?

Yes. You can import `cleanLettaFromClaudeMd` from [`scripts/conversation_utils.ts`](https://github.com/letta-ai/claude-subconscious/blob/main/scripts/conversation_utils.ts) and invoke it with any directory path. This is useful for manual maintenance or custom automation scripts that need to ensure [`CLAUDE.md`](https://github.com/letta-ai/claude-subconscious/blob/main/CLAUDE.md) integrity before specific operations.