Letta Code SDK
Build stateful agents using Letta Code as a library
The Letta Code SDK provides a programmatic interface to Letta Code. Use the Letta Code SDK to build your own applications that build on Letta Code’s advanced coding agent harness.
Installation
Section titled “Installation”npm install @letta-ai/letta-code-sdkQuick start
Section titled “Quick start”One-shot prompt
Section titled “One-shot prompt”For simple queries, use prompt():
import { prompt } from "@letta-ai/letta-code-sdk";
const result = await prompt("What is 2 + 2?");console.log(result.result);Persistent agent with multi-turn conversations
Section titled “Persistent agent with multi-turn conversations”Create an agent to persist memory across sessions and application restarts:
import { createAgent, resumeSession } from "@letta-ai/letta-code-sdk";
// Create agent with custom configurationconst agentId = await createAgent({ persona: "You are a Python expert specialized in data science.",});
console.log("Agent ID:", agentId); // Save this for later!
// Resume session on agent's default conversationawait using session = resumeSession(agentId);
// Turn 1await session.send("What's the best way to load a CSV?");for await (const msg of session.stream()) { if (msg.type === "assistant") console.log(msg.content);}
// Turn 2 - agent remembers previous contextawait session.send("Show me an example with pandas");for await (const msg of session.stream()) { if (msg.type === "assistant") console.log(msg.content);}
// Later: Resume the same agent using the saved IDawait using laterSession = resumeSession(agentId);await laterSession.send("What were we discussing?");for await (const msg of laterSession.stream()) { if (msg.type === "assistant") console.log(msg.content);}The await using syntax (TypeScript 5.2+) automatically closes the session. For manual cleanup, use session.close().
Managing conversations
Section titled “Managing conversations”Start a new conversation on the same agent:
import { createSession } from "@letta-ai/letta-code-sdk";
// New conversationawait using session = createSession(agentId);
await session.send("Let's start a new topic");
for await (const msg of session.stream()) { if (msg.type === "assistant") console.log(msg.content);}Resume a specific conversation by ID:
import { resumeSession } from "@letta-ai/letta-code-sdk";
// Resume a conversation you saved earlierawait using session = resumeSession("conv-abc123");
await session.send("Continuing where we left off");
for await (const msg of session.stream()) { if (msg.type === "assistant") console.log(msg.content);}Concepts
Section titled “Concepts”- Agent (
agentId): A persistent entity with memory. - Conversation (
conversationId): A message thread within an agent. - Session: A single execution/connection.
- Default conversation: Always exists after
createAgent(); useresumeSession(agentId). - Default agent: Most recently used agent or the default Memo agent from Letta Code; use
createSession()orprompt(message)
Configuration
Section titled “Configuration”Agent creation options
Section titled “Agent creation options”Configure agents at creation time with memory blocks, system prompts, and initial context:
import { createAgent } from "@letta-ai/letta-code-sdk";
const agentId = await createAgent({ // Memory blocks define the agent's persistent context memory: [ { label: "persona", value: "You are a Python expert specialized in data science." }, { label: "rules", value: "Always include type hints and docstrings." }, ],
// Or use preset memory blocks memory: ["persona", "human"], // Valid presets: persona, human
// Convenience shortcuts for common presets persona: "You are a helpful coding assistant.", human: "User prefers TypeScript and functional programming.",});Valid memory presets:
persona- Agent’s identity and behaviorhuman- Information about the user
Custom memory blocks:
const agentId = await createAgent({ memory: [ { label: "project", value: "Building a REST API with Express and PostgreSQL..." }, { label: "context", value: "Migrating from MongoDB to PostgreSQL..." }, ],});Runtime session options
Section titled “Runtime session options”Configure behavior at session creation or resume time:
import { createAgent, resumeSession } from "@letta-ai/letta-code-sdk";
const agentId = await createAgent();
await using session = resumeSession(agentId, { // Update the agent's model (persists) model: "claude-sonnet-4-5",
// Working directory for file operations cwd: "/path/to/project",
// MemFS toggle for this run // true -> --memfs, false -> --no-memfs, undefined -> leave unchanged memfs: true,
// Skills/reminder controls skillSources: ["project", "global"], // [] disables all skills systemInfoReminder: false, // disable first-turn system info reminder
// Reflection settings (equivalent to /sleeptime) sleeptime: { trigger: "step-count", // "off" | "step-count" | "compaction-event" behavior: "reminder", // "reminder" | "auto-launch" stepCount: 8, },
// Restrict available tools allowedTools: ["Read", "Grep", "Glob"], disallowedTools: ["AskUserQuestion", "EnterPlanMode", "ExitPlanMode"],
// Permission handling permissionMode: "default", // "default" | "acceptEdits" | "plan" | "bypassPermissions"
// Custom permission callback canUseTool: async (toolName, toolInput) => { if ( toolName === "Bash" && typeof toolInput.command === "string" && toolInput.command.includes("rm") ) { return { behavior: "deny", message: "Destructive commands not allowed" }; } return { behavior: "allow" }; },});Interactive tools in non-interactive sessions
Section titled “Interactive tools in non-interactive sessions”When running without a UI (for example, server-side SDK sessions):
EnterPlanModecan be auto-allowed by default.AskUserQuestionandExitPlanModerequire runtime user input and are denied unless you provide acanUseToolcallback.
For bot-style deployments, you can either:
- Provide
canUseToolto handle these permission requests. - Block the tools explicitly via
disallowedTools(for example["AskUserQuestion", "EnterPlanMode", "ExitPlanMode"]).
System prompts
Section titled “System prompts”System prompts can be configured at agent creation time, or updated later when creating/resuming a session.
At agent creation (createAgent) you can use a custom string or a preset (optionally with append):
// Custom system promptconst agentId = await createAgent({ systemPrompt: "You are a Python expert. Always use type hints.",});
// Preset (with optional append)const agentId2 = await createAgent({ systemPrompt: { type: "preset", preset: "letta-claude", append: "Always respond in Spanish.", },});At session time (createSession / resumeSession) you can only set a preset (no custom strings / no append):
await using session = resumeSession(agentId, { systemPrompt: "letta-claude",});Note: Updating
modelorsystemPromptviacreateSession/resumeSessionupdates the agent in Letta Code (it persists), not a temporary per-session override.
Available presets:
letta-claude/default- Full coding assistant with memoryletta-codex- Optimized for OpenAI Codex modelsletta-gemini- Optimized for Google Gemini modelsclaude,codex,gemini- Minimal prompts without Letta features
Cleanup
Section titled “Cleanup”Sessions can be closed manually or automatically using await using (TypeScript 5.2+).
Automatic cleanup:
await using session = resumeSession(agentId);// Session closes automatically when the block exitsManual cleanup:
const session = resumeSession(agentId);try { // ... use session ...} finally { session.close();}API reference
Section titled “API reference”Core functions
Section titled “Core functions”| Function | Description |
|---|---|
createAgent(options?) | Create a new persistent agent |
createSession(agentId?, options?) | Start a new conversation (uses default agent if no ID provided) |
resumeSession(id, options?) | Resume session (pass agent-xxx for default conversation, or conv-xxx for specific conversation) |
prompt(message, agentId?) | One-shot query (uses default agent if no ID provided) |
Session interface
Section titled “Session interface”interface Session { send(message: string): Promise<void>; stream(): AsyncGenerator<SDKMessage>; close(): void;
readonly agentId: string; readonly conversationId: string | null; readonly sessionId: string;}CreateAgentOptions
Section titled “CreateAgentOptions”Options for createAgent() - these configure the persistent agent:
interface CreateAgentOptions { model?: string; embedding?: string;
// Memory configuration (choose one approach) memory?: Array<string | { label: string; value: string }>;
// Convenience shortcuts for common presets persona?: string; human?: string;
// System prompt (custom string or preset) systemPrompt?: string | SystemPromptPreset | { type: "preset"; preset: SystemPromptPreset; append?: string };
// Runtime/harness controls available at creation memfs?: boolean; skillSources?: SkillSource[]; systemInfoReminder?: boolean; sleeptime?: SleeptimeOptions;}CreateSessionOptions
Section titled “CreateSessionOptions”Options for createSession() and resumeSession() - these configure runtime behavior:
interface CreateSessionOptions { // Model configuration model?: string;
// System prompt preset (updates the agent) systemPrompt?: SystemPromptPreset;
// Tool restrictions allowedTools?: string[]; disallowedTools?: string[]; permissionMode?: "default" | "acceptEdits" | "plan" | "bypassPermissions"; canUseTool?: (toolName: string, toolInput: object) => Promise<CanUseToolResponse>;
// File system cwd?: string;
// Runtime/harness controls memfs?: boolean; // true => --memfs, false => --no-memfs skillSources?: SkillSource[]; // [] => --no-skills systemInfoReminder?: boolean; // false => --no-system-info-reminder sleeptime?: SleeptimeOptions;}Supporting types:
type SkillSource = "bundled" | "global" | "agent" | "project";
interface SleeptimeOptions { trigger?: "off" | "step-count" | "compaction-event"; behavior?: "reminder" | "auto-launch"; stepCount?: number;}Example apps
Section titled “Example apps”Just directly into code examples with demo app built on the Letta Code SDK: