Create an agent once. Resume it from anywhere.

The TypeScript SDK for stateful agents. Identity and memory stay with the agent — not the process, the model, or the machine.

Get started npm install @letta-ai/letta-agent-sdk
deploy.ts · Monday cloud · agent-3f97…
import { LettaAgentClient }
  from "@letta-ai/letta-agent-sdk";
const client = new LettaAgentClient({
  backend: "cloud",
});
// Create the agent once...
const agentId = await client.createAgent({
  persona: "You are Nora, an analyst.",
});
// → "agent-3f97f111-…"
anywhere.ts · Thursday cloud · agent-3f97…
// ...then resume it, from anywhere.
await using session =
  client.resumeSession(agentId);
await session.send(
  "What changed since last week?");
for await (const msg of session.stream()) {
  if (msg.type === "assistant")
    process.stdout.write(msg.content);
}
// → streams Nora's Thursday brief

Same agent, different process. Nora already knows who she is, what changed since last week, and how you like your briefs.

Built by the team behind MemGPT, the paper that introduced memory management for LLM agents. Open source on GitHub.

Memory is part of the agent, not the app

Memory is a git repository the agent owns. It follows the agent everywhere it works, and the agent edits it as it learns.

create-quinn.ts cloud · agent-8c21…
const agentId = await client.createAgent({
  model: "anthropic/claude-opus-4-8",
  memory: [{
    label: "persona",
    value: "You are Quinn, an analyst.",
  }, {
    label: "team-context",
    value: "The team ships on Thursdays.",
  }],
});
agent-8c21d04a · memory (git)
├── system/
│   ├── persona.mdin context every turn
│   └── team-context.mdin context every turn
└── notes/
    └── competitors.mdread on demand

4d1c2ea  learned: launch moved to Sept— Quinn, 2h ago

This repository follows the agent, not your repo.

  • system/memory you set at creation is in the system prompt every turn; everything else stays out of context until the agent reads it.
  • dreamingbackground subagents consolidate lessons into memory without interrupting active work. trigger: "step-count" | "compaction-event" | "off", behavior: "reminder" | "auto-launch".
  • skillsinstall packaged instructions into the agent's own memory, versioned with the agent: letta skills install anthropics/skills/pdf.
  • stateless: truerun a one-off session that does not load or change the agent's memory.
Read how MemFS works Shared memory repositories Installing skills

One interface. Three backends.

One client, three backends. Swap one string — nothing else changes.

client.ts cloud · agent-3f97…
// Managed everything. State lives
// in Letta Cloud; tools in a sandbox.
const client = new LettaAgentClient({
  backend: "cloud",
  apiKey: process.env.LETTA_API_KEY,
});
client.ts local · agent-local-3f97…
// No account, no server to start —
// the SDK owns a local App Server.
// State stays on this machine.
const client = new LettaAgentClient({
  backend: "local",
});
client.ts remote · agent-3f97…
// letta server --backend local
//   --listen ws://127.0.0.1:4500
const client = new LettaAgentClient({
  backend: "remote",
  url: "http://127.0.0.1:4500",
  authToken:
    process.env.LETTA_APP_SERVER_TOKEN,
});
"cloud""local""remote"
Agent state livesLetta CloudCurrent machineDetermined by the App Server backend
Tools executeManaged sandbox, or a computer you connectCurrent machineApp Server machine
Account requiredLetta API keyNoneYour own auth token
Runtime you runNoneSDK-owned subprocess (Node 22.19+)App Server you operate (Node 22.19+)
Best forManaged everythingFully local state and executionA runtime under your control

No account required for the local backend. Your code doesn't change when you swap the backend string.

TypeScript and JavaScript today; Python applications use the App Server WebSocket protocol directly.

Deployment guide

Pick the computer. Keep the agent.

A computer is where the agent works — separate from who the agent is. Managed sandbox by default, or connect your own machine.

byom.ts cloud · agent-3f97…
// Managed sandbox by default,
// kept warm across reconnects —
// or bring your own machine:
await using session =
  client.resumeSession(agentId, {
    computer: { name: "work-laptop" },
    cwd: "/workspace/project",
  });

One agent, three places it can work today.

Computers and sandboxes MCP & client tools

Typed events in, render-ready rows out

Streaming, queueing, and optimistic updates — in the same client the browser uses. The accumulator turns the event stream into rows your UI renders.

transcript.ts cloud · agent-3f97…
import { createTranscriptAccumulator }
  from "@letta-ai/letta-agent-sdk";

const transcript =
  createTranscriptAccumulator();

await session.send(
  "Summarize yesterday's deploys.");

for await (const msg of session.stream()) {
  const rows = transcript.apply(msg);
  render(rows);
}
  • queuemessages sent mid-turn are queued by the runtime, not dropped.
  • resumea dropped connection ends the session, not the agent: resumeSession(conversationId), then reconcile with listMessages() or bootstrapState().
  • otidpass your own otid on send(text, { otid }) and the persisted message carries it back, so optimistic rows reconcile instead of re-rendering.
  • recoverPendingApprovals()approvals left pending on the runtime re-arrive in your new session's callback.
The stream contract Build the full React chat app Browser, React Native & Expo clients

Human approvals are part of the turn

Gate any tool call on your own UI. The turn waits for the human's Allow or Deny — and approvals left pending survive a dropped connection.

approvals.ts cloud · agent-3f97…
// inside createSession(agentId, { … }):
canUseTool: async (tool, args, ctx) => {
  // your approval UI:
  const ok = await askUser(tool, ctx);
  return ok
    ? { behavior: "allow" }
    : { behavior: "deny", interrupt: true };
},

Your UI shows the tool call and its diff; the turn waits for the human's Allow or Deny.

Permission modes and rules

Your first stateful agent is one npm install away

npm install @letta-ai/letta-agent-sdk

No account needed for the local backend. Cloud needs an API key. Node.js 22.19+ only if you run the runtime yourself.

Light
Dark