#!/usr/bin/env bun import { parseArgs } from "node:util"; import { APIError } from "@letta-ai/letta-client/core/error"; import type { AgentState } from "@letta-ai/letta-client/resources/agents/agents"; import type { Message } from "@letta-ai/letta-client/resources/agents/messages"; import { getResumeData, type ResumeData } from "./agent/check-approval"; import { getClient } from "./agent/client"; import { setAgentContext, setConversationId as setContextConversationId, } from "./agent/context"; import type { AgentProvenance } from "./agent/create"; import { getLettaCodeHeaders } from "./agent/http-headers"; import { ISOLATED_BLOCK_LABELS } from "./agent/memory"; import { resolveSkillSourcesSelection } from "./agent/skillSources"; import { LETTA_CLOUD_API_URL } from "./auth/oauth"; import { ConversationSelector } from "./cli/components/ConversationSelector"; import type { ApprovalRequest } from "./cli/helpers/stream"; import { ProfileSelectionInline } from "./cli/profile-selection"; import { runSubcommand } from "./cli/subcommands/router"; import { permissionMode } from "./permissions/mode"; import { settingsManager } from "./settings-manager"; import { startStartupAutoUpdateCheck } from "./startup-auto-update"; import { telemetry } from "./telemetry"; import { loadTools } from "./tools/manager"; import { markMilestone } from "./utils/timing"; // Stable empty array constants to prevent new references on every render // These are used as fallbacks when resumeData is null, avoiding the React // anti-pattern of creating new [] on every render which triggers useEffect re-runs const EMPTY_APPROVAL_ARRAY: ApprovalRequest[] = []; const EMPTY_MESSAGE_ARRAY: Message[] = []; function printHelp() { // Keep this plaintext (no colors) so output pipes cleanly const usage = ` Letta Code is a general purpose CLI for interacting with Letta agents USAGE # interactive TUI letta Resume default conversation (OG single-threaded experience) letta --new Create a new conversation (for concurrent sessions) letta --continue Resume last session (agent + conversation) directly letta --resume Open agent selector UI to pick agent/conversation letta --new-agent Create a new agent directly (skip profile selector) letta --agent Open a specific agent by ID # headless letta -p "..." One-off prompt in headless mode (no TTY UI) # maintenance letta update Manually check for updates and install if available letta memfs ... Memory filesystem subcommands (JSON-only) letta agents ... Agents subcommands (JSON-only) letta messages ... Messages subcommands (JSON-only) letta blocks ... Blocks subcommands (JSON-only) OPTIONS -h, --help Show this help and exit -v, --version Print version and exit --info Show current directory, skills, and pinned agents --continue Resume last session (agent + conversation) directly -r, --resume Open agent selector UI after loading --new Create new conversation (for concurrent sessions) --new-agent Create new agent directly (skip profile selection) --init-blocks Comma-separated memory blocks to initialize when using --new-agent (e.g., "persona,skills") --base-tools Comma-separated base tools to attach when using --new-agent (e.g., "memory,web_search,fetch_webpage") -a, --agent Use a specific agent ID -n, --name Resume agent by name (from pinned agents, case-insensitive) -m, --model Model ID or handle (e.g., "opus-4.5" or "anthropic/claude-opus-4-5") -s, --system System prompt ID or subagent name (applies to new or existing agent) --toolset Toolset mode: "auto", "codex", "default", or "gemini" (manual values override model-based auto-selection) -p, --prompt Headless prompt mode --output-format Output format for headless mode (text, json, stream-json) Default: text --input-format Input format for headless mode (stream-json) When set, reads JSON messages from stdin for bidirectional communication --include-partial-messages Emit stream_event wrappers for each chunk (stream-json only) --from-agent Inject agent-to-agent system reminder (headless mode) --skills Custom path to skills directory (default: .skills in current directory) --skill-sources Skill sources: all,bundled,global,agent,project (default: all) --no-skills Disable all skill sources --no-bundled-skills Disable bundled skills only --import Create agent from an AgentFile (.af) template Use @author/name to import from the agent registry --memfs Enable memory filesystem for this agent --no-memfs Disable memory filesystem for this agent --no-system-info-reminder Disable first-turn environment reminder (device/git/cwd context) --reflection-trigger Sleeptime trigger: off, step-count, compaction-event --reflection-behavior Sleeptime behavior: reminder, auto-launch --reflection-step-count Sleeptime step-count interval (positive integer) SUBCOMMANDS (JSON-only) letta memfs status --agent letta memfs diff --agent letta memfs resolve --agent --resolutions '' letta memfs backup --agent letta memfs backups --agent letta memfs restore --agent --from --force letta memfs export --agent --out letta agents list [--query | --name | --tags ] letta messages search --query [--all-agents] letta messages list [--agent ] letta blocks list --agent letta blocks copy --block-id [--label