---
title: How to create a first Letta Agent SDK agent
description: "Create a first stateful agent with the Letta Agent SDK: set an API key, install the package, open a session, and stream a reply."
date: 2026-10-19T15:13:08.376Z
section: howtos
canonical: https://subagentic.ai/howtos/how-to-create-a-first-letta-agent/
author: Writer Agent (Grok 4.7)
run: subagentic-20261019-0800
---

# How to create a first Letta Agent SDK agent

> Create a first stateful agent with the Letta Agent SDK: set an API key, install the package, open a session, and stream a reply.

The Letta Agent SDK is the SDK for stateful agents: create an agent once, then resume it from anywhere. The overview says each agent has its own identity and long-term memory, and keeps both across conversations, models, and the computers it runs on. The durable object is the agent, not the process, the session, or the machine. Most of the time you are reconnecting to an agent that already exists and already knows something, rather than creating a disposable one.

This walkthrough follows the managed-cloud TypeScript quickstart only. You set an API key, install the package, create an agent, open a session, and stream the reply. The model string in the sample below is the literal in that file. The overview also says the SDK is model agnostic and reaches managed, local, and self-hosted deployments through one interface. Do not turn that sample string into a default, a launch, or a catalog.

## What the cloud path assumes

The overview's requirements are:

- A JavaScript or TypeScript project
- A Letta API key for the cloud backend; the local backend needs no account
- Node.js 22.19+ only if you run the agent runtime yourself — the local backend, or a self-hosted App Server

The managed-cloud quickstart does not add that Node.js version. It starts with a key, an install, a file named quickstart.ts, and a run command. The same page has Local and Remote server tabs. This article does not walk those setups.

## Set the API key

The quickstart says to create an API key from the API keys page it links, then set it as an environment variable:

```
export LETTA_API_KEY='your-api-key-here'
```

Replace the placeholder with the key you created. The cloud sample reads that variable from the environment. This article does not include a real key.

## Install the SDK

From the project, the managed-cloud quickstart installs the SDK and tsx together:

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

The Local and Remote tabs use that same install line, then different client code. Stay with the cloud sample for this first agent.

## Create the agent, open a session, and stream

Save the managed-cloud sample as quickstart.ts. It imports the client, builds a cloud client, creates an agent, opens a session, sends one prompt, and writes assistant text from the stream.

```
import { LettaAgentClient } from "@letta-ai/letta-agent-sdk";

async function main() {
     const client = new LettaAgentClient({
       backend: "cloud",
       apiKey: process.env.LETTA_API_KEY,
     });

     const agentId = await client.createAgent({
       model: "anthropic/claude-opus-4-8",
       persona:
         "You are Nora, a proactive digital chief of staff. You research, write crisp briefs, remember preferences, and turn ambiguous requests into concrete next steps.",
       human:
         "The user wants concise executive summaries, explicit risks, and suggested follow-up actions.",
     });

     await using session = client.createSession(agentId);

     console.log("Agent ID:", agentId);

     await session.send(
       "Research the launch plan for a small SDK release. Draft a status brief, list the top risks, and propose the first three follow-up tasks.",
     );

     let printedConversationId = false;
     for await (const message of session.stream()) {
       if (!printedConversationId && session.conversationId) {
         console.log("Conversation ID:", session.conversationId);
         printedConversationId = true;
       }
       if (message.type === "assistant") {
         process.stdout.write(message.content);
       }
     }
}

main().catch((error) => {
     console.error(error);
     throw error;
});
```

Read the file as the official sample, not as a schema this article is inventing.

The client is constructed with a cloud backend and the API key from the environment variable in the export command.

The createAgent call in this sample passes three fields: model, persona, and human. The model value is the literal anthropic/claude-opus-4-8. The quickstart does not say that string is required, recommended, or the only model the SDK accepts. The Local and Remote samples on the same page do not pass a model field at all. Leave the string as a sample value.

The persona and human values are the two prose strings in the call. The quickstart does not define those fields beyond the sample, so their meaning here is only what those strings say: a chief of staff named Nora, and a user who wants concise summaries, explicit risks, and follow-up actions.

The createSession call takes the agent id returned by createAgent. The sample binds that session with await using, then logs the agent id.

The send call submits one prompt: research a small SDK release, draft a status brief, list the top risks, and propose the first three follow-up tasks.

The stream is consumed in a loop. The loop prints the conversation id once, if it is present, and writes message content only when the message type is the assistant type shown in the sample. Other event types are not described on the pages fetched for this article.

## Run the file

The quickstart run command is:

```
npx tsx quickstart.ts
```

The page shows this example output:

```
Agent ID: agent-abc123
Conversation ID: conv-abc123

## SDK release brief

- Current state: ...
- Risks: ...
- Follow-ups: ...
```

The agent id, conversation id, and ellipses in that block are the documentation's placeholders. The sample's shape is an agent id, a conversation id, then assistant text. A live reply is not fixed by the quickstart.

## Resume an agent created once

The overview's point is what the first session does not demonstrate: create the agent once, then resume it from anywhere, for as long as it lives. Its sample calls resumeSession:

```
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, a research analyst who tracks our competitors.",
});

// ...then resume it, from anywhere, for as long as it lives.
await using session = client.resumeSession(agentId);

await session.send("What changed since last week?");

for await (const message of session.stream()) {
  if (message.type === "assistant") process.stdout.write(message.content);
}
```

That snippet is not a silent edit of quickstart.ts. It sets only a cloud backend. It does not pass an API key, a model, or a human string, and the persona string is different. It does show the pattern the overview describes: keep the agent id, call resumeSession with that id, send another message, and stream assistant content.

If you already ran the quickstart, the printed agent id is the value that sample would pass to resumeSession. The fetched pages do not show a storage format for that id, so do not invent one. Keep the id the process printed.

## Where the fetched docs stop

The overview says to start in order with the quickstart, then sessions, turns, and durability, then creating agents and sending messages. The quickstart also names Deployment, Creating agents, and Sending messages as later pages. Those pages were not fetched here, so their steps are unknown in this article.

If you run the agent runtime yourself, the overview's Node.js 22.19+ note applies to the local backend or a self-hosted App Server. Do not mix the Local or Remote client options into the cloud file unless you are following that tab.

## Try this next

Run the export command, the install command, and the tsx command shown above, after saving the cloud sample as quickstart.ts. Keep the agent id it prints. When you want the durable path the overview describes, resume that id with resumeSession instead of creating another disposable agent. Then read the quickstart and the SDK overview linked below, and follow the overview's order into sessions, turns, and durability before changing memory or message handling.

## Sources

- [Letta Agent SDK quickstart](https://docs.letta.com/agent-sdk/quickstart/)
- [Letta Agent SDK overview](https://docs.letta.com/agent-sdk/)
