@letta-ai/letta-code 0.12.6 → 0.12.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.12.6",
3
+ "version": "0.12.8",
4
4
  "description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,169 @@
1
+ ---
2
+ name: defragmenting-memory
3
+ description: Defragments and cleans up agent memory blocks. Use when memory becomes messy, redundant, or poorly organized. Backs up memory, uses a subagent to clean it up, then restores the cleaned version.
4
+ ---
5
+
6
+ # Memory Defragmentation Skill
7
+
8
+ This skill helps you maintain clean, well-organized memory blocks by:
9
+ 1. Dumping current memory to local files and backing up the agent file
10
+ 2. Using the memory subagent to clean up the files
11
+ 3. Restoring the cleaned files back to memory
12
+
13
+ ## When to Use
14
+
15
+ - Memory blocks have redundant information
16
+ - Memory lacks structure (walls of text)
17
+ - Memory contains contradictions
18
+ - Memory has grown stale or outdated
19
+ - After major project milestones
20
+ - Every 50-100 conversation turns
21
+
22
+ ## Workflow
23
+
24
+ ### Step 1: Backup Memory to Files
25
+
26
+ ```bash
27
+ npx tsx <SKILL_DIR>/scripts/backup-memory.ts $LETTA_AGENT_ID .letta/backups/working
28
+ ```
29
+
30
+ This creates:
31
+ - `.letta/backups/<agent-id>/<timestamp>/` - Timestamped memory blocks backup
32
+ - `.letta/backups/working/` - Working directory with editable files
33
+ - Each memory block as a `.md` file: `persona.md`, `human.md`, `project.md`, etc.
34
+
35
+ ### Step 2: Spawn Memory Subagent to Clean Files
36
+
37
+ ```typescript
38
+ Task({
39
+ subagent_type: "memory",
40
+ description: "Clean up memory files",
41
+ prompt: `Edit the memory block files in .letta/backups/working/ to clean them up.
42
+
43
+ Focus on:
44
+ - Reorganize and consolidate redundant information
45
+ - Add clear structure with markdown headers
46
+ - Organize content with bullet points
47
+ - Resolve contradictions
48
+ - Improve scannability
49
+
50
+ IMPORTANT: When merging blocks, DELETE the redundant source files after consolidating their content (use Bash rm command). You have full bash access in the .letta/backups/working directory. Only delete files when: (1) you've merged their content into another block, or (2) the file contains only irrelevant/junk data with no project value.
51
+
52
+ Files to edit: persona.md, human.md, project.md
53
+ Do NOT edit: skills.md (auto-generated), loaded_skills.md (system-managed)
54
+
55
+ After editing, provide a report with before/after character counts and list any deleted files.`
56
+ })
57
+ ```
58
+
59
+ The memory subagent will:
60
+ - Read the files from `.letta/backups/working/`
61
+ - Edit them to reorganize and consolidate redundancy
62
+ - Merge related blocks together for better organization
63
+ - Add clear structure with markdown formatting
64
+ - Delete source files after merging their content into other blocks
65
+ - Provide a detailed report of changes (including what was merged where)
66
+
67
+ ### Step 3: Restore Cleaned Files to Memory
68
+
69
+ ```bash
70
+ npx tsx <SKILL_DIR>/scripts/restore-memory.ts $LETTA_AGENT_ID .letta/backups/working
71
+ ```
72
+
73
+ This will:
74
+ - Compare each file to current memory blocks
75
+ - Update only the blocks that changed
76
+ - Show before/after character counts
77
+ - Skip unchanged blocks
78
+
79
+ ## Example Complete Flow
80
+
81
+ ```typescript
82
+ // Step 1: Backup memory to files
83
+ Bash({
84
+ command: "npx tsx <SKILL_DIR>/scripts/backup-memory.ts $LETTA_AGENT_ID .letta/backups/working",
85
+ description: "Backup memory to files"
86
+ })
87
+
88
+ // Step 2: Clean up (subagent edits files and deletes merged ones)
89
+ Task({
90
+ subagent_type: "memory",
91
+ description: "Clean up memory files",
92
+ prompt: "Edit memory files in .letta/backups/working/ to reorganize and consolidate redundancy. Focus on persona.md, human.md, and project.md. Merge related blocks together and DELETE the source files after merging (use Bash rm command - you have full bash access). Add clear structure. Report what was merged and where, and which files were deleted."
93
+ })
94
+
95
+ // Step 3: Restore
96
+ Bash({
97
+ command: "npx tsx <SKILL_DIR>/scripts/restore-memory.ts $LETTA_AGENT_ID .letta/backups/working",
98
+ description: "Restore cleaned memory blocks"
99
+ })
100
+ ```
101
+
102
+ ## Rollback
103
+
104
+ If something goes wrong, restore from a previous backup:
105
+
106
+ ```bash
107
+ # Find the backup directory
108
+ ls -la .letta/backups/<agent-id>/
109
+
110
+ # Restore from specific timestamp
111
+ npx tsx <SKILL_DIR>/scripts/restore-memory.ts $LETTA_AGENT_ID .letta/backups/<agent-id>/<timestamp>
112
+ ```
113
+
114
+ ## Dry Run
115
+
116
+ Preview changes without applying them:
117
+
118
+ ```bash
119
+ npx tsx <SKILL_DIR>/scripts/restore-memory.ts $LETTA_AGENT_ID .letta/backups/working --dry-run
120
+ ```
121
+
122
+ ## What the Memory Subagent Does
123
+
124
+ The memory subagent focuses on cleaning up files. It:
125
+ - Reads files from `.letta/backups/working/`
126
+ - Edits files to improve structure and consolidate redundancy
127
+ - Merges related blocks together to reduce fragmentation
128
+ - Reorganizes information for better clarity and scannability
129
+ - Deletes source files after merging their content (using Bash `rm` command)
130
+ - Provides detailed before/after reports including merge operations
131
+ - Does NOT run backup scripts (main agent does this)
132
+ - Does NOT run restore scripts (main agent does this)
133
+
134
+ The memory subagent runs with `bypassPermissions` mode, giving it full Bash access to delete files after merging them. The focus is on consolidation and reorganization.
135
+
136
+ ## Tips
137
+
138
+ **What to clean up:**
139
+ - Duplicate information (consolidate into one well-organized section)
140
+ - Walls of text without structure (add headers and bullets)
141
+ - Contradictions (resolve by clarifying or choosing the better guidance)
142
+ - Speculation ("probably", "maybe" - make it concrete or remove)
143
+ - Transient details that won't matter in a week
144
+
145
+ **Reorganization Strategy:**
146
+ - Consolidate duplicate information into a single, well-structured section
147
+ - Merge related content that's scattered across multiple blocks
148
+ - Add clear headers and bullet points for scannability
149
+ - Group similar information together logically
150
+ - After merging blocks, DELETE the source files to avoid duplication
151
+
152
+ **When to DELETE a file:**
153
+ - After merging - You've consolidated its content into another block (common and encouraged)
154
+ - Junk data - File contains only irrelevant test/junk data with no project connection
155
+ - Empty/deprecated - File is just a notice with no unique information
156
+ - Don't delete - If file has unique information that hasn't been merged elsewhere
157
+
158
+ **What to preserve:**
159
+ - User preferences (sacred - never delete)
160
+ - Project conventions discovered through experience
161
+ - Important context for future sessions
162
+ - Learnings from past mistakes
163
+ - Any information that has unique value
164
+
165
+ **Good memory structure:**
166
+ - Use markdown headers (##, ###)
167
+ - Organize with bullet points
168
+ - Keep related information together
169
+ - Make it scannable at a glance
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * Backup Memory Blocks to Local Files
4
+ *
5
+ * Exports all memory blocks from an agent to local files for checkpointing and editing.
6
+ * Creates a timestamped backup directory with:
7
+ * - Individual .md files for each memory block
8
+ * - manifest.json with metadata
9
+ *
10
+ * This script is standalone and can be run outside the CLI process.
11
+ * It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
12
+ *
13
+ * Usage:
14
+ * npx tsx backup-memory.ts <agent-id> [backup-dir]
15
+ *
16
+ * Example:
17
+ * npx tsx backup-memory.ts agent-abc123
18
+ * npx tsx backup-memory.ts $LETTA_AGENT_ID .letta/backups/working
19
+ */
20
+
21
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
22
+ import { createRequire } from "node:module";
23
+ import { homedir } from "node:os";
24
+ import { join } from "node:path";
25
+
26
+ // Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
27
+ // (ES module imports don't respect NODE_PATH, but require does)
28
+ const require = createRequire(import.meta.url);
29
+ const Letta = require("@letta-ai/letta-client")
30
+ .default as typeof import("@letta-ai/letta-client").default;
31
+ type LettaClient = InstanceType<typeof Letta>;
32
+
33
+ export interface BackupManifest {
34
+ agent_id: string;
35
+ timestamp: string;
36
+ backup_path: string;
37
+ blocks: Array<{
38
+ id: string;
39
+ label: string;
40
+ filename: string;
41
+ limit: number;
42
+ value_length: number;
43
+ }>;
44
+ }
45
+
46
+ /**
47
+ * Get API key from env var or settings file
48
+ */
49
+ function getApiKey(): string {
50
+ if (process.env.LETTA_API_KEY) {
51
+ return process.env.LETTA_API_KEY;
52
+ }
53
+
54
+ const settingsPath = join(homedir(), ".letta", "settings.json");
55
+ try {
56
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
57
+ if (settings.env?.LETTA_API_KEY) {
58
+ return settings.env.LETTA_API_KEY;
59
+ }
60
+ } catch {
61
+ // Settings file doesn't exist or is invalid
62
+ }
63
+
64
+ throw new Error(
65
+ "No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Create a Letta client with auth from env/settings
71
+ */
72
+ function createClient(): LettaClient {
73
+ return new Letta({ apiKey: getApiKey() });
74
+ }
75
+
76
+ /**
77
+ * Backup memory blocks to local files
78
+ */
79
+ async function backupMemory(
80
+ agentId: string,
81
+ backupDir?: string,
82
+ ): Promise<string> {
83
+ const client = createClient();
84
+
85
+ // Create backup directory
86
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
87
+ const defaultBackupDir = join(
88
+ process.cwd(),
89
+ ".letta",
90
+ "backups",
91
+ agentId,
92
+ timestamp,
93
+ );
94
+ const backupPath = backupDir || defaultBackupDir;
95
+
96
+ mkdirSync(backupPath, { recursive: true });
97
+
98
+ console.log(`Backing up memory blocks for agent ${agentId}...`);
99
+ console.log(`Backup location: ${backupPath}`);
100
+
101
+ // Get all memory blocks
102
+ const blocksResponse = await client.agents.blocks.list(agentId);
103
+ const blocks = Array.isArray(blocksResponse)
104
+ ? blocksResponse
105
+ : (blocksResponse as { items?: unknown[] }).items ||
106
+ (blocksResponse as { blocks?: unknown[] }).blocks ||
107
+ [];
108
+
109
+ console.log(`Found ${blocks.length} memory blocks`);
110
+
111
+ // Export each block to a file
112
+ const manifest: BackupManifest = {
113
+ agent_id: agentId,
114
+ timestamp: new Date().toISOString(),
115
+ backup_path: backupPath,
116
+ blocks: [],
117
+ };
118
+
119
+ for (const block of blocks as Array<{
120
+ id: string;
121
+ label?: string;
122
+ value?: string;
123
+ limit?: number;
124
+ }>) {
125
+ const label = block.label || `block-${block.id}`;
126
+ const filename = `${label}.md`;
127
+ const filepath = join(backupPath, filename);
128
+
129
+ // Write block content to file
130
+ const content = block.value || "";
131
+ writeFileSync(filepath, content, "utf-8");
132
+
133
+ console.log(` ✓ ${label} -> ${filename} (${content.length} chars)`);
134
+
135
+ // Add to manifest
136
+ manifest.blocks.push({
137
+ id: block.id,
138
+ label,
139
+ filename,
140
+ limit: block.limit || 0,
141
+ value_length: content.length,
142
+ });
143
+ }
144
+
145
+ // Write manifest
146
+ const manifestPath = join(backupPath, "manifest.json");
147
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
148
+ console.log(` ✓ manifest.json`);
149
+
150
+ console.log(`\n✅ Backup complete: ${backupPath}`);
151
+ return backupPath;
152
+ }
153
+
154
+ // CLI Entry Point - check if this file is being run directly
155
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
156
+ if (isMainModule) {
157
+ const args = process.argv.slice(2);
158
+
159
+ if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
160
+ console.log(`
161
+ Usage: npx tsx backup-memory.ts <agent-id> [backup-dir]
162
+
163
+ Arguments:
164
+ agent-id Agent ID to backup (can use $LETTA_AGENT_ID)
165
+ backup-dir Optional custom backup directory
166
+ Default: .letta/backups/<agent-id>/<timestamp>
167
+
168
+ Examples:
169
+ npx tsx backup-memory.ts agent-abc123
170
+ npx tsx backup-memory.ts $LETTA_AGENT_ID
171
+ npx tsx backup-memory.ts agent-abc123 .letta/backups/working
172
+ `);
173
+ process.exit(0);
174
+ }
175
+
176
+ const agentId = args[0];
177
+ const backupDir = args[1];
178
+
179
+ if (!agentId) {
180
+ console.error("Error: agent-id is required");
181
+ process.exit(1);
182
+ }
183
+
184
+ backupMemory(agentId, backupDir)
185
+ .then((path) => {
186
+ // Output just the path for easy capture in scripts
187
+ console.log(path);
188
+ })
189
+ .catch((error) => {
190
+ console.error(
191
+ "Error backing up memory:",
192
+ error instanceof Error ? error.message : String(error),
193
+ );
194
+ process.exit(1);
195
+ });
196
+ }
197
+
198
+ export { backupMemory };