letta/letta-api-client/SKILL.md
Build applications with the Letta API — a model-agnostic, stateful API for building persistent agents with memory and long-term learning. Covers SDK patterns for Python and TypeScript. Includes 24 working code examples.
npx skillsauth add letta-ai/skills letta-api-clientInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build applications on top of the Letta API — a model-agnostic, stateful API for building persistent agents with memory and long-term learning. The Letta API powers Letta Code and the Learning SDK. This skill covers the core patterns for creating agents, managing memory, building custom tools, and handling multi-user scenarios.
See getting-started.md for first-time setup and common onboarding issues.
Examples last tested with:
letta-client==1.7.1@letta-ai/[email protected]See client-setup.md for initialization patterns:
See memory-architecture.md for memory patterns:
See custom-tools.md for tool creation:
See client-side-tools.md for local tool execution:
type: "tool" responsesSee client-injection.md for server-side tool patterns:
client variable on Letta Cloudos.getenv()LETTA_AGENT_ID for self-referential toolsSee multi-user.md for scaling:
See streaming.md for real-time responses:
include_pingsConversations enable parallel sessions with shared memory:
See sleeptime.md for background memory processing:
enable_sleeptime=TrueSee agent-files.md for portability and file access:
.af filesSee tool-rules.md for constraining tool execution:
InitToolRule - Force a tool to run firstChildToolRule - Control which tools can followTerminalToolRule - End agent turn after toolpip install letta-client
from letta_client import Letta
# Cloud
client = Letta(api_key="LETTA_API_KEY")
# Self-hosted
client = Letta(base_url="http://localhost:8283")
npm install @letta-ai/letta-client
import { Letta } from "@letta-ai/letta-client";
// Cloud
const client = new Letta({ apiKey: process.env.LETTA_API_KEY });
// Self-hosted
const client = new Letta({ baseUrl: "http://localhost:8283" });
See the examples/ directory for runnable code:
Python:
01_basic_client.py - Client initialization02_create_agent.py - Agent creation with memory blocks03_custom_tool_simple.py - Basic custom tool04_custom_tool_secrets.py - Tool with environment variables05_send_message.py - Basic messaging06_send_message_stream.py - Streaming responses07_multi_user.py - Multi-user patterns08_archival_memory.py - Archival memory operations09_shared_blocks.py - Multi-agent shared memory10_conversations.py - Parallel sessions with conversations11_client_injection.py - Custom memory tools with injected client12_tool_rules.py - Constraining tool execution order13_client_side_tools.py - Execute tools locally (like Letta Code)TypeScript:
01_basic_client.ts - Client initialization02_create_agent.ts - Agent creation03_send_message.ts - Basic messaging04_send_message_stream.ts - Streaming05_nextjs_singleton.ts - Next.js pattern06_multi_user.ts - Multi-user patterns07_conversations.ts - Parallel sessions08_custom_tool.ts - Custom tools with secrets09_archival_memory.ts - Long-term storage10_shared_blocks.ts - Multi-agent shared memory11_client_injection.ts - Custom memory tools12_tool_rules.ts - Tool execution order13_client_side_tools.ts - Execute tools locally (like Letta Code)| Error | Cause | Fix |
|-------|-------|-----|
| 401 Unauthorized | Invalid or missing API key | Check LETTA_API_KEY env var |
| 422 Validation Error | Missing required field | Add model, embedding, or memory_blocks |
| Tool not found | Tool not attached to agent | client.agents.tools.attach(agent_id, tool_id) |
| os.getenv() returns None | Secret not configured | Add to agent via secrets parameter |
| 524 Timeout | Long operation without pings | Add include_pings=True to streaming |
| Agent not responding | Model issue or empty response | Check for assistant_message type in response |
| Memory block not updating | Looking at wrong agent | Verify agent_id matches |
| Import error in tool | Top-level import | Move imports inside function body |
os.getenv() for secrets - Don't pass sensitive data as function argumentsclient - Don't instantiate Letta() inside tools, use the pre-injected clientinclude_pings=True for long operations - Prevents timeout on Cloud.update() not .modify() - Method was renamedLETTA_AGENT_ID is always available - Use it in tools to reference the current agentinclude_base_tools=True - Not attached by defaultmemory_insert for shared blocks - Safest for concurrent writes (append-only)// Client initialization uses baseURL (not baseUrl)
const client = new Letta({ apiKey: "...", baseURL: "http://localhost:8283" });
// Block API: positional args changed
client.agents.blocks.attach(blockId, { agent_id }); // blockId is first
client.agents.blocks.retrieve(blockLabel, { agent_id }); // label is first
// Passages.create returns array
const passages = await client.agents.passages.create(agentId, { text: "..." });
const passage = passages[0];
// Content can be string | array - use type guard
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
// Conversations API returns streams by default
const stream = await client.conversations.messages.create(convId, { messages: [...] });
for await (const chunk of stream) { ... }
// Tool rule types
{ type: "run_first", tool_name: "..." } // InitToolRule
{ type: "constrain_child_tools", tool_name: "...", children: [...] } // ChildToolRule
{ type: "exit_loop", tool_name: "..." } // TerminalToolRule
# Client
client = Letta(api_key=os.getenv("LETTA_API_KEY"))
# Create agent
agent = client.agents.create(
model="anthropic/claude-sonnet-4-5-20250929",
embedding="openai/text-embedding-3-small",
memory_blocks=[{"label": "persona", "value": "..."}],
include_base_tools=True, # archival memory tools
enable_sleeptime=True, # background memory processing
)
# Send message
response = client.agents.messages.create(
agent_id=agent.id,
messages=[{"role": "user", "content": "Hello"}]
)
# Stream response
stream = client.agents.messages.stream(
agent_id=agent.id,
messages=[{"role": "user", "content": "Hello"}],
stream_tokens=True,
include_pings=True, # prevent timeout
)
# Create tool
tool = client.tools.create(source_code="def my_tool(x: str) -> str: ...")
client.agents.tools.attach(agent_id=agent.id, tool_id=tool.id)
# Memory blocks
client.agents.blocks.retrieve(agent_id=agent.id, block_label="persona")
client.agents.blocks.update(agent_id=agent.id, block_label="persona", value="...")
# Folders
folder = client.folders.create(name="docs")
client.folders.files.upload(file=f, folder_id=folder.id)
client.agents.folders.attach(agent_id=agent.id, folder_id=folder.id)
# Conversations (parallel sessions)
conv = client.conversations.create(agent_id=agent.id)
stream = client.conversations.messages.create(conv.id, messages=[...])
# Agent secrets (for tools)
client.agents.update(agent_id=agent.id, secrets={"API_KEY": "..."})
Platform:
Documentation:
SDKs:
pip install letta-clientnpm install @letta-ai/letta-clientExamples:
testing
Navigates archived ChatGPT or Claude-style conversation exports and a MemFS reference archive on demand. Use when recalling what a past assistant knew, searching old conversations, rendering specific chats, seeding reference memory from export sidecars, or mining historical context without doing a full import.
testing
Migrates deprecated Letta Filesystem folders/files to MemFS using markdown document corpora, chunking, local lexical search, and QMD semantic search via the memfs-search skill. Use when replacing folders.files.upload, working with PDFs or document QA, or emulating open_file, grep_file, and search_file behavior.
data-ai
Configures Letta agent compaction settings and custom summarization prompts. Use when a user asks to change an agent's compaction prompt, improve summaries after context eviction, tune sliding-window or all-message compaction, or design companion/coding-agent continuity summaries.
development
Semantic search over agent memory files. Use when you need to find conceptually related memory blocks, discover forgotten reference files, check what you already know before creating new memory, or search beyond exact keyword matching. Currently supports QMD (local, no API keys).