Letta REST API vs Letta Code SDK: 8 Key Differences in the Claude-Subconscious Plugin
The Letta REST API requires manual HTTP handling and polling for responses, while the Letta Code SDK provides a high-level session abstraction with real-time streaming, automatic authentication, and configurable client-side tool access.
The letta-ai/claude-subconscious repository implements dual integration patterns for connecting Claude Code with Letta agents. When deciding between the Letta REST API and Letta Code SDK, developers must consider differences in abstraction level, streaming capabilities, and tool permissions that fundamentally change how the plugin synchronizes conversation state.
Architectural Overview: Low-Level Control vs. Session Abstraction
Raw HTTP Implementation with the REST API
The REST API approach implements direct HTTP communication using Node’s native fetch to interact with Letta endpoints such as /conversations/ and /agents/. In scripts/conversation_utils.ts, the createConversation() function constructs URLs via buildLettaApiUrl() and manually assembles request headers including the Authorization: Bearer <API-KEY> credential.
This method requires the plugin to handle XML payload formatting, JSON response parsing, and HTTP error status codes without abstraction layers. The send_messages_to_letta.ts script writes temporary JSON files to disk and tracks message indices manually when preparing the <claude_code_session_update> payload for transmission.
High-Level Session Management with the Code SDK
The Code SDK approach leverages the optional @letta-ai/letta-code-sdk package to create a persistent session object. In scripts/send_worker_sdk.ts, the worker dynamically imports the SDK and invokes resumeSession() with a conversation ID and configuration options. The SDK encapsulates authentication by reading the LETTA_API_KEY environment variable internally, eliminating manual header management.
The session object exposes session.send() for transmitting messages and session.stream() for receiving real-time assistant responses, abstracting the underlying HTTP transport and payload serialization.
Key Implementation Differences
Authentication Patterns
REST API: Each request must explicitly include the bearer token in the request headers. The createConversation() function in scripts/conversation_utils.ts (lines 20-28) demonstrates this pattern by passing the apiKey parameter into the Authorization header for every fetch call.
Code SDK: Authentication is transparent. The SDK reads LETTA_API_KEY from environment variables during session initialization, as implemented in scripts/send_worker_sdk.ts (lines 40-46). Callers do not manage headers or credential injection.
Message Transport and Payload Handling
REST API: The plugin bears full responsibility for payload construction. In send_messages_to_letta.ts, the code manually formats XML envelopes containing the transcript updates, writes these to temporary files, and later parses the conversation history JSON to extract responses.
Code SDK: Message formatting happens automatically. The worker passes the raw XML string to session.send(), which handles serialization and transmission. The SDK manages conversation state and memory synchronization without requiring temporary file intermediates.
Response Retrieval: Polling vs. Streaming
REST API: Responses are retrieved via periodic polling. The pretool_sync.ts and sync_letta_memory.ts scripts implement fetchNewMessages() to query the conversation endpoint later, checking for new assistant messages to inject into CLAUDE.md. This creates latency between message generation and availability.
Code SDK: Responses stream in real-time. The send_worker_sdk.ts implementation uses for await (const msg of session.stream()) (lines 73-93) to process assistant chunks as they arrive, enabling immediate feedback without polling loops.
Tool Access and Capability Differences
Client-Side Tool Permissions
The REST API integration cannot access Letta’s client-side tools such as Read, Grep, Glob, or web_search. The plugin is restricted to text-only send/receive operations when using HTTP endpoints directly.
The Code SDK exposes configurable tool permissions through the LETTA_SDK_TOOLS environment variable. In scripts/send_worker_sdk.ts (lines 69-87), the worker configures allowedTools and disallowedTools arrays based on the requested mode:
read-only: EnablesRead,Grep,Glob,web_search, andfetch_webpagefull: Allows all client-side capabilities includingBash,Edit, andWriteoff: Disables all tools for text-only interaction
Dependency and Import Strategy
REST API: Zero external dependencies required. The implementation relies solely on Node.js built-in fetch, making it suitable for lightweight deployments where minimizing package size is critical.
Code SDK: Requires the optional @letta-ai/letta-code-sdk npm package. The plugin safeguards against missing dependencies by using dynamic imports in send_worker_sdk.ts, allowing the plugin to run in REST-only mode if the SDK is not installed.
Code Examples: REST API vs. SDK
Creating Conversations via REST
The following implementation from scripts/conversation_utils.ts demonstrates direct API communication for conversation initialization:
import { buildLettaApiUrl } from './letta_api_url.js';
export async function createConversation(
apiKey: string,
agentId: string,
log: LogFn = noopLog,
): Promise<string> {
const url = buildLettaApiUrl('/conversations/', { agent_id: agentId });
log(`Creating new conversation for agent ${agentId}`);
const response = await fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
});
if (!response.ok) {
const err = await response.text();
throw new Error(`Failed to create conversation: ${response.status} ${err}`);
}
const conversation: Conversation = await response.json();
log(`Created conversation: ${conversation.id}`);
return conversation.id;
}
This function corresponds to lines 20-28 in the source file and represents the typical pattern for REST-based agent configuration in agent_config.ts.
Streaming Messages via SDK
The background worker in scripts/send_worker_sdk.ts implements the SDK approach for live transcript updates:
import { resumeSession } from '@letta-ai/letta-code-sdk';
async function sendViaSdk(payload: SdkPayload): Promise<boolean> {
const sessionOptions: Record<string, unknown> = {
disallowedTools: ['AskUserQuestion', 'EnterPlanMode', 'ExitPlanMode'],
permissionMode: 'bypassPermissions',
cwd: payload.cwd,
skillSources: [],
systemInfoReminder: false,
sleeptime: { trigger: 'off' },
};
if (payload.sdkToolsMode === 'read-only') {
sessionOptions.allowedTools = ['Read', 'Grep', 'Glob', 'web_search', 'fetch_webpage'];
} else if (payload.sdkToolsMode === 'off') {
sessionOptions.disallowedTools = [
...sessionOptions.disallowedTools,
'Read',
'Grep',
'Glob',
'Bash',
'Edit',
'Write',
'Task',
];
}
const session = resumeSession(payload.conversationId, sessionOptions);
try {
await session.send(payload.message);
for await (const msg of session.stream()) {
if (msg.type === 'assistant') {
// Process streaming assistant chunks
} else if (msg.type === 'error') {
// Handle SDK error objects
return false;
}
}
return true;
} finally {
session.close();
}
}
This implementation (lines 40-78) shows how the SDK handles authentication, tool configuration, and real-time streaming without manual HTTP intervention.
When to Use Each Integration Method
Choose the REST API when:
- Implementing background synchronization tasks like
sync_letta_memory.tsorpretool_sync.ts - Minimizing external dependencies is required
- Performing administrative operations such as creating conversations or updating agent configurations via
agent_config.ts
Choose the Code SDK when:
- Sending live transcript updates from
send_messages_to_letta.tsto the Letta agent - Requiring real-time streaming responses instead of polling
- Enabling client-side tool access (Read, Grep, Bash) for the agent
- Simplifying authentication management in worker threads
Summary
- Communication Style: The REST API uses manual HTTP requests with
fetch, while the SDK provides aresumeSession()abstraction that hides network complexity. - Authentication: REST requires explicit
Authorizationheaders per request; the SDK readsLETTA_API_KEYautomatically from environment variables. - Response Handling: REST relies on periodic polling via
fetchNewMessages()in sync scripts; the SDK streams responses in real-time throughsession.stream(). - Tool Access: REST supports text-only interaction; the SDK enables configurable client-side tools via
LETTA_SDK_TOOLSenvironment settings. - Dependencies: REST requires no external packages; the SDK uses optional dynamic imports of
@letta-ai/letta-code-sdk. - Use Cases: REST is preferred for memory synchronization and conversation management; the SDK is optimized for live messaging with tool capabilities.
Frequently Asked Questions
Can I use both the REST API and Code SDK in the same plugin instance?
Yes. The letta-ai/claude-subconscious plugin employs both methods simultaneously according to their strengths. The REST API handles background synchronization tasks in sync_letta_memory.ts and pretool_sync.ts, while the Code SDK manages live transcript streaming via send_worker_sdk.ts. The dynamic import strategy ensures the plugin functions even if the SDK package is not installed.
Do I need to install the Letta Code SDK to use the plugin?
No. The @letta-ai/letta-code-sdk package is an optional dependency. The plugin defaults to REST API functionality for all operations if the SDK is absent. The send_worker_sdk.ts script uses dynamic imports to load the SDK only when available, falling back to REST-based alternatives or graceful degradation.
Which integration method supports real-time streaming of agent responses?
Only the Letta Code SDK supports real-time streaming. The session.stream() method in scripts/send_worker_sdk.ts (lines 73-93) yields assistant messages as they are generated. The REST API requires polling mechanisms like fetchNewMessages() to check for new content, introducing delays between message creation and retrieval.
How do I enable client-side tools like Read and Grep for the Letta agent?
Client-side tools require the Code SDK and the LETTA_SDK_TOOLS environment variable. Set this variable to read-only to enable safe tools (Read, Grep, Glob, web_search), full to allow all capabilities including Bash and Edit, or off to disable tools entirely. The REST API cannot access these client-side capabilities.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →