Agent Skills › letta-ai/letta-code

letta-ai/letta-code

GitHub

指导在Letta Code中添加新LLM模型。涵盖通过API查询有效句柄、配置models.json、测试模型及可选的CI矩阵更新,解决模型注册与工具集自动检测问题。

19 skills 2,807

Install All Skills

npx skills add letta-ai/letta-code --all -g -y
More Options

List skills in collection

npx skills add letta-ai/letta-code --list

Skills in Collection (19)

指导在Letta Code中添加新LLM模型。涵盖通过API查询有效句柄、配置models.json、测试模型及可选的CI矩阵更新,解决模型注册与工具集自动检测问题。
用户想要添加对新模型的支持 需要查询有效的模型句柄 希望更新模型配置
.skills/adding-models/SKILL.md
npx skills add letta-ai/letta-code --skill adding-models -g -y
SKILL.md
Frontmatter
{
    "name": "adding-models",
    "description": "Guide for adding new LLM models to Letta Code. Use when the user wants to add support for a new model, needs to know valid model handles, or wants to update the model configuration. Covers models.json configuration, CI test matrix, and handle validation."
}

Adding Models

This skill guides you through adding a new LLM model to Letta Code.

Quick Reference

Key files:

  • src/models.json - Model definitions (required)
  • .github/workflows/ci.yml - CI test matrix (optional)
  • src/tools/manager.ts - Toolset detection logic (rarely needed)

Workflow

Step 1: Find Valid Model Handles

Query the Letta API to see available models:

curl -s https://api.letta.com/v1/models/ | jq '.[] | .handle'

Or filter by provider:

curl -s https://api.letta.com/v1/models/ | jq '.[] | select(.handle | startswith("google_ai/")) | .handle'

Common provider prefixes:

  • anthropic/ - Claude models
  • openai/ - GPT models
  • google_ai/ - Gemini models
  • google_vertex/ - Vertex AI
  • openrouter/ - Various providers

Step 2: Add to models.json

Add an entry to src/models.json:

{
  "id": "model-shortname",
  "handle": "provider/model-name",
  "label": "Human Readable Name",
  "description": "Brief description of the model",
  "isFeatured": true,  // Optional: shows in featured list
  "updateArgs": {
    "context_window": 180000,
    "temperature": 1.0  // Optional: provider-specific settings
  }
}

Field reference:

  • id: Short identifier used with --model flag (e.g., gemini-3-flash)
  • handle: Full provider/model path from the API (e.g., google_ai/gemini-3-flash-preview)
  • label: Display name in model selector
  • description: Brief description shown in selector
  • isFeatured: If true, appears in featured models section
  • updateArgs: Model-specific configuration (context window, temperature, reasoning settings, etc.)

Provider prefixes:

  • anthropic/ - Anthropic (Claude models)
  • openai/ - OpenAI (GPT models)
  • google_ai/ - Google AI (Gemini models)
  • google_vertex/ - Google Vertex AI
  • openrouter/ - OpenRouter (various providers)

Step 3: Test the Model

Test with headless mode:

bun run src/index.ts --new --model <model-id> -p "hi, what model are you?"

Example:

bun run src/index.ts --new --model gemini-3-flash -p "hi, what model are you?"

Step 4: Add to CI Test Matrix (Optional)

To include the model in automated testing, add it to .github/workflows/ci.yml:

# Find the headless job matrix around line 122
model: [gpt-5-minimal, gpt-4.1, sonnet-4.5, gemini-pro, your-new-model, glm-4.6, haiku]

Toolset Detection

Models are automatically assigned toolsets based on provider:

  • openai/*codex toolset
  • google_ai/* or google_vertex/*gemini toolset
  • Others → default toolset

This is handled by isGeminiModel() and isOpenAIModel() in src/tools/manager.ts. You typically don't need to modify this unless adding a new provider.

Common Issues

"Handle not found" error: The model handle is incorrect. Run the validation script to see valid handles.

Model works but wrong toolset: Check src/tools/manager.ts to ensure the provider prefix is recognized.

用于发现并安装来自Hermes、ClawHub等外部源的技能。当用户请求当前不具备的能力(如图像生成、自动化等)时触发。重点强调安全审查,区分可信与不可信来源,并指导跨平台技能的适配与验证。
用户询问或需要当前未具备的功能能力 用户希望扩展Agent的技能集或查找可用技能
src/skills/builtin/acquiring-skills/SKILL.md
npx skills add letta-ai/letta-code --skill acquiring-skills -g -y
SKILL.md
Frontmatter
{
    "name": "acquiring-skills",
    "description": "Discover and install skills from Hermes, ClawHub, GitHub, and other registries. Load this skill whenever a user asks for a capability you don't already have — image generation, social media, email, calendar, finance, DevOps, search, browser automation, etc."
}

Acquiring New Skills

This skill teaches you how to safely discover and install skills from external sources, including the Hermes Skills Hub, ClawHub (OpenClaw), GitHub repositories, and Letta community repos.

SAFETY - READ THIS FIRST

Skills can contain:

  • Markdown files (.md) - Risk: prompt injection, misleading instructions
  • Scripts (Python, TypeScript, Bash) - Risk: malicious code execution

Trusted Sources (no user approval needed for download)

  • https://github.com/letta-ai/skills - Letta's community skills
  • https://github.com/anthropics/skills - Anthropic's official skills
  • official/* - Hermes official optional skills (from NousResearch/hermes-agent)

Untrusted Sources (ALWAYS verify with user)

For ANY source other than the above:

  1. Ask the user before downloading
  2. Explain where the skill comes from
  3. Get explicit approval

This includes ClawHub community skills and arbitrary GitHub repos.

Script Safety

Even for skills from trusted sources, ALWAYS:

  1. Read and inspect any scripts before executing them
  2. Understand what the script does
  3. Be wary of network calls, file operations, or system commands

Cross-Harness Compatibility

Skills from Hermes, OpenClaw, and other ecosystems were written for their own harnesses. After installing, read the full SKILL.md before using it and watch for:

  • Harness-specific commands — e.g. hermes skills config, openclaw plugins install, /curator, /kanban. These won't exist in Letta. Determine whether the underlying capability can be achieved with Letta tools (Bash, the Skill tool, etc.) or if the skill simply doesn't apply.
  • Harness-specific paths and state — e.g. ~/.hermes/skills/, ~/.openclaw/skills/, ~/.hermes/config.yaml. Letta stores skills in the agent's memfs (<memory-dir>/skills/). Adapt any path references.
  • Toolset assumptions — some skills assume specific tool names or APIs (e.g. Hermes web toolset, OpenClaw browser tool). Map these to the equivalent Letta tools or note when no equivalent exists.
  • Platform gating — skills may declare platforms: [cli, discord, telegram] in frontmatter. Ignore platform restrictions that don't apply to Letta.
  • Environment variables — skills may require API keys or credentials. Check requires.env in frontmatter and note any setup the user needs to do.

If a skill's core knowledge (procedures, API references, best practices) is useful but its commands are harness-specific, adapt the instructions mentally or suggest the user install the relevant CLI tool. If a skill is entirely about harness-specific plumbing with no transferable knowledge, skip it and look for an alternative.

When to Use This Skill

DO use when:

  • User asks for something where a skill likely exists (e.g., "help me test this webapp", "generate a PDF report")
  • You think "there's probably a skill that would bootstrap my understanding"
  • User explicitly asks about available skills or extending capabilities

DON'T use for:

  • General coding tasks you can already handle
  • Simple bug fixes or feature implementations
  • Tasks where you have sufficient knowledge

Ask Before Searching (Interactive Mode)

If you recognize a task that might have an associated skill, ask the user first:

"This sounds like something where a community skill might help. Would you like me to search for available skills? I can check the Hermes catalog, ClawHub, or GitHub. Or I can start coding right away if you prefer."

The user may prefer to start immediately rather than wait for skill discovery.

Only proceed with skill acquisition if the user agrees.

Skill Sources

1. Hermes Skills Hub (NousResearch)

Hermes has a full Skills Hub with 88k+ skills across multiple registries. It includes official optional skills shipped with the project, plus community skills from skills.sh, well-known endpoints, GitHub repos, ClawHub, LobeHub, and browse.sh.

Searching Hermes skills:

The Hermes CLI has built-in search and browse:

hermes skills browse                              # Browse all hub skills (official first)
hermes skills browse --source official            # Browse only official optional skills
hermes skills search kubernetes                   # Search all sources
hermes skills search react --source skills-sh     # Search the skills.sh directory
hermes skills search https://mintlify.com/docs --source well-known
hermes skills inspect openai/skills/k8s           # Preview before installing

The web catalog is at https://hermes-agent.nousresearch.com/docs/skills.

Hermes hub sources:

Source Example identifier Notes
official official/security/1password Optional skills shipped with Hermes
skills-sh skills-sh/vercel-labs/agent-skills/vercel-react-best-practices skills.sh directory
well-known well-known:https://mintlify.com/docs/.well-known/skills/mintlify Skills hosted at /.well-known/skills/
url https://sharethis.chat/SKILL.md Direct URL to a single SKILL.md
github openai/skills/k8s GitHub repo/path
clawhub ClawHub registry skills ClawHub marketplace
lobehub LobeHub registry skills LobeHub marketplace
browse-sh browse-sh/airbnb.com/search-listings-ddgioa browse.sh crawled skills

If Hermes is not installed, you can browse the official optional skills directly:

# Browse the catalog on GitHub
# https://github.com/NousResearch/hermes-agent/tree/main/optional-skills
# Categories: autonomous-ai-agents, blockchain, creative, devops, finance,
#             health, mcp, mlops, productivity, research, security, ...

# Or clone and browse locally
git clone --depth 1 https://github.com/NousResearch/hermes-agent.git /tmp/hermes-browse
ls /tmp/hermes-browse/optional-skills/
ls /tmp/hermes-browse/optional-skills/finance/
rm -rf /tmp/hermes-browse

Installing Hermes skills into Letta uses the official/ prefix (for official optional skills):

letta skills install official/finance/stocks
letta skills install official/blockchain/solana
letta skills install official/research/duckduckgo-search
letta skills install official/mlops/flash-attention
letta skills install official/creative/meme-generation

The official/<category>/<skill> form clones NousResearch/hermes-agent and copies from optional-skills/<category>/<skill>.

For non-official Hermes hub skills, use the GitHub URL or shorthand form to install into Letta (e.g., letta skills install openai/skills/k8s).

2. ClawHub (OpenClaw)

ClawHub (https://clawhub.ai) is the public registry for OpenClaw skills and plugins. It hosts community-contributed skills with versioning, security scans, and search.

Searching ClawHub skills:

# Browse the web registry
# https://clawhub.ai

# Or use the clawhub CLI if installed
clawhub search "calendar"
clawhub search "screenshot"
clawhub explore

# Or search via the API directly
curl -s "https://clawhub.ai/api/v1/skills?q=calendar" | jq '.items[].slug'

Installing ClawHub skills uses the clawhub/ or clawhub: prefix:

letta skills install clawhub/nano-banana-pro
letta skills install clawhub:nano-banana-pro
letta skills install clawhub:nano-banana-pro@1.0.1      # pin a version
letta skills install https://clawhub.ai/skills/my-skill  # URL form also works

Note: A bare slug like letta skills install nano-banana-pro will NOT resolve through ClawHub — you must include the clawhub/ or clawhub: prefix.

3. GitHub Repositories

Any GitHub repository containing a SKILL.md can be installed directly.

# Full repo (installs from repo root)
letta skills install https://github.com/owner/repo

# Subdirectory (tree URL)
letta skills install https://github.com/owner/repo/tree/main/path/to/skill

# SKILL.md blob URL (installs parent directory)
letta skills install https://github.com/owner/repo/blob/main/path/to/skill/SKILL.md

# Shorthand: owner/repo/path
letta skills install owner/repo/path/to/skill

4. Letta & Anthropic Community Repos

Repository Description
https://github.com/letta-ai/skills Community skills for Letta agents
https://github.com/anthropics/skills Anthropic's official Agent Skills

These can be installed via the GitHub URL forms above, or manually cloned and copied.

The letta skills install Command

The CLI handles downloading, placing the skill in the agent's memory, and committing the change:

letta skills install <source> --agent $AGENT_ID [--force]

Your agent ID is always available as $AGENT_ID in the environment. Pass it explicitly with --agent to install into your own memfs:

letta skills install official/finance/stocks --agent $AGENT_ID
letta skills install clawhub/nano-banana-pro --agent $AGENT_ID
Flag Purpose
--agent <id> Install into a specific agent's memfs (use $AGENT_ID for yourself)
-n <name> Resolve agent by name instead of id
--force Replace an existing skill with the same name

Also available as a top-level alias: letta install <source> --agent $AGENT_ID.

Managing installed skills:

letta skills list --agent $AGENT_ID
letta skills delete <skill-name> --agent $AGENT_ID

Installation Locations

When using letta skills install, skills are placed in the agent's memfs at <memory-dir>/skills/<skill-name>/.

For manual installation:

Location Path When to Use
Agent-scoped ~/.letta/agents/<agent-id>/memory/skills/<skill>/ Skills for a single agent (default)
Global ~/.letta/skills/<skill>/ General-purpose skills useful across projects
Project .skills/<skill>/ Project-specific skills

Rule: Default to agent-scoped. Use project for repo-specific skills. Use global only if all agents should inherit the skill.

Manual Download (When CLI Install Isn't Available)

Skills are directories containing SKILL.md and optionally scripts/, references/, examples/.

# Clone, copy, cleanup
git clone --depth 1 https://github.com/anthropics/skills /tmp/skills-temp
cp -r /tmp/skills-temp/skills/webapp-testing ~/.letta/agents/<agent-id>/memory/skills/
rm -rf /tmp/skills-temp

Registering New Skills

After installing (via CLI or manual copy), skills are automatically discovered on the next message. Skills are discovered from ~/.letta/skills/, .skills/, and agent-scoped ~/.letta/agents/<agent-id>/memory/skills/ directories.

Search Strategy

When looking for a skill to solve a user's problem:

  1. Search Hermes Skills Hub firsthermes skills search <query> searches 88k+ skills across all registries. If Hermes CLI isn't available, browse the official optional-skills on GitHub (finance, mlops, blockchain, devops, research, creative, security, etc.).
  2. Search ClawHub — community registry with versioning. Use clawhub search or the web UI.
  3. Search GitHub — look for repos with SKILL.md files. Try github.com/letta-ai/skills and github.com/anthropics/skills first.
  4. Ask the user — they may know of a specific skill repo or have preferences about sources.

Complete Example

User asks: "Can you help me track stock prices?"

  1. Recognize opportunity: Stock/finance data — Hermes has a stocks skill
  2. Ask user: "Hermes has an official stocks skill that covers quotes, history, search, and crypto via Yahoo. Want me to install it?"
  3. If user agrees, install:
    letta skills install official/finance/stocks --agent $AGENT_ID
    
  4. Review for compatibility: Read the installed SKILL.md. Check for harness-specific commands, paths, or tools that need adaptation (see Cross-Harness Compatibility above). Confirm the skill's instructions make sense in Letta before using it.
  5. Invoke: Skill(skill: "stocks")
  6. Use: Follow the skill's instructions, adapting any harness-specific details as needed

User asks: "Can you generate images with Nano Banana Pro?"

  1. Recognize opportunity: Image generation skill on ClawHub
  2. Ask user: "There's a nano-banana-pro skill on ClawHub. Want me to install it?"
  3. Install:
    letta skills install clawhub/nano-banana-pro --agent $AGENT_ID
    
  4. Review for compatibility: Read the SKILL.md, check for any OpenClaw-specific commands or setup, adapt as needed.
  5. Invoke: Skill(skill: "nano-banana-pro")
识别并修复系统提示词、外部记忆和技能中的上下文退化问题。通过保守编辑减少冗余,优化指令遵循和信息记忆能力,确保代理在不同会话中保持最佳状态。
系统提示词或记忆出现退化 需要优化上下文以改善指令遵循或记忆效果
src/skills/builtin/context-doctor/SKILL.md
npx skills add letta-ai/letta-code --skill Context Doctor -g -y
SKILL.md
Frontmatter
{
    "id": "context-doctor",
    "name": "Context Doctor",
    "description": "Identify and repair degradation in system prompt, external memory, and skills preventing you from following instructions or remembering information as well as you should."
}

Context Doctor

Your context is what makes you you across sessions. You are responsible for managing it (along with memory subagents). It includes:

  • Your system prompt and memories (contained in system/)
  • Your external memory (contained in the memory filesystem)
  • Your skills (procedural memory)

Over time, context can degrade — bloat and poor prompt quality erode your ability to remember the right things and follow instructions properly. This skill helps you identify issues with your context and repair them collaboratively with the user.

IMPORTANT: Your edits of your system instructions should be conservative. Do NOT make assuptions about what parts of the system prompt are critical. The system prompt defines who you are, so significant modifications to its structure can have unintended consequences. Focus on making minimal changes to meet the token budget, and to effectively link out to external memory.

Operating Procedure

Step 1: Identify and resolve context issues

Explore your memory files to identify issues. Consider what is confusing about your own prompts and context, and resolve the issues.

Below are additional common issues with context and how they can be resolved:

System prompt bloat

Memories compiled into the system prompt (contained in system/) should take up about 10% of the total context size (usually ~15-20K tokens). This is a soft target, not a hard requirement.

Use the built-in CLI to evaluate token usage of the system prompt:

letta memory tokens --format json --quiet

The command reports total_tokens and per-file estimates for system/. It is only a measurement tool; decide whether to intervene based on the actual context and the guidance below.

Why detail is load-bearing (read this before cutting anything): In-context detail does more than carry information. It does at least four things, and byte-counting sweeps only see the first:

  1. Information — the literal facts stated
  2. Attention anchoring — makes certain topics feel important to the model when it's reasoning
  3. Semantic priming — raises the prior on codebase-specific patterns ("this codebase has weird X, don't assume defaults")
  4. Reasoning templates — past examples become heuristics for new bugs; rationale in "why" prose becomes scaffolding

Compression preserves (1). It destroys (2), (3), (4). That's why a compressed prompt can make an agent measurably worse at codebase-specific reasoning even though the explicit facts are all "still there" in reference files.

Reference links ([[path]]) are NOT equivalent to in-context presence. They're latent until the agent actively fetches them. An agent only fetches when it already knows it doesn't know. The priming cues that tell it when it doesn't know are in the system prompt itself — they can't be replaced by links.

When to intervene: Only if the system prompt is meaningfully over target. At or near the target, leave it alone. Every edit risks removing content that was doing work you can't see. A prompt that feels "a bit long" is almost always better than one that's been aggressively trimmed.

Modifying the system prompt: Make MINIMAL changes required to cut the token count of the system prompt if needed. The goal preserve the existing behavior while cutting down the token count. Focus on reducing redundancy or compressing - rather than offloading entire sections to external memory.

  • Preserve persona-defining content (who you are, how you communicate)
  • Preserve user identity or preferences (e.g. the human's name, their stated goals)
  • Maintain the existing distribution of detail: compression should be applied evenly across all topics. If the original prompt was 50% about a specific issue, the new prompt should also be 50% about that issue.
  • Only reduce noise and improve structure - if compression must result in information loss, preserve lost details into external memory

Context redundancy and unclear organization

The context in the memory filesystem should have a clear structure, with a well-defined purpose for each file. Memory file descriptions should be precise and non-overlapping. Their contents should be consistent with the description, and have non-overlapping content to other files.

Questions to ask:

  • Do the descriptions make clear what file is for what?
  • Do the contents of the file match the descriptions? (you can ask subagents to check)

Solution: Read all memory files (use subagents for efficiency), then:

  • Consolidate redundant files
  • Reorganize files and rewrite descriptions to have clear separation of concerns
  • Avoid duplication by referencing common files from multiple places (e.g. [[reference/api]])
  • Rewrite unclear or low-quality content

Invalid context format

Files in the memory filesystem must follow certain structural requirements:

  • Must have a system/persona.md
  • Must NOT have overlapping file and folder names (e.g. system/human.md and system/human/identity.md)
  • Must follow specification for skills (e.g. skills/{skill_name}/) with the format:
skill-name/
├── SKILL.md          # Required: metadata + instructions
├── scripts/          # Optional: executable code
├── references/       # Optional: documentation
├── assets/           # Optional: templates, resources
└── ...               # Any additional files or directories

Solution: Reorganize files to follow the required structure

Poor use of progressive disclosure

Only critical information should be in the system prompt, since it's passed on every turn. Use progressive disclosure so that context only sometimes needed can be dynamically retrieved.

Files that are outside of system/ are not part of the system prompt, and must be dynamically loaded. You must index your files to ensure your future self can discover them: for example, make sure that files have informative names and descriptions, or are referenced from parts of your system prompt via [[path]] links to create discovery paths. Otherwise, you will never discover the external context or make use of it.

Solution:

  • Reference external skills from the relevant parts of in-context memory:
When running a migration, always use the skill [[skills/db-migrations]]

or external memory files:

Sarah's active projects are: Letta Code [[projects/letta_code.md]] and Letta Cloud [[projects/letta_cloud]]
  • Ensure that contents of files match the file name and descriptions
  • Make sure your future self will be able to find and load external files when needed.

Step 2: Implement context fixes

Create a plan for what fixes you want to make, then implement them. Favor the smallest possible change that resolves the issue — if the system prompt is 1.5× the target, don't cut it to half the target "for headroom." Cut until you're near the target, then stop.

Before moving on, verify:

  • System prompt token budget reviewed (target ~10% of context, usually 15-20k tokens)
  • Changes are proportional to the problem — only offloaded what's needed to meet the target
  • Preserved detailed rationale, examples, and cross-references in sections that stayed in system/
  • Preferred moving whole files or deleting stale sections over compressing detailed sections into summaries
  • No overlapping or redundant files remain
  • All file descriptions are unique, accurate, and match their contents
  • Moved-out knowledge has [[path]] references from in-context memory so it can be discovered
  • No semantic changes to persona, user identity, or behavioral instructions

Step 3: Commit and push

Review changes, then commit with a descriptive message:

cd $MEMORY_DIR
git status                # Review what changed before staging
git add <specific files>  # Stage targeted paths — avoid blind `git add -A`
author_name="${AGENT_NAME:-$AGENT_ID}"
git commit --author="$author_name <$AGENT_ID@letta.com>" -m "fix(doctor): <summary> 🏥

<identified issues and implemented solutions>"

git push

Step 4: Final checklist and message

Tell the user what issues you identified, the fixes you made, the commit you made, and also recommend that they run /recompile to apply these changes to the current system prompt.

Before finishing make sure you:

  • Resolved all the identified context issues
  • Pushed your changes successfully
  • Told the user to run /recompile to refresh the system prompt and apply changes

Critical information

  • Ask the user about their goals for you, not the implementation: You understand your own context best, and should follow the guidelines in this document. Do NOT ask the user about their structural preferences — the context is for YOU, not them. Ask them how they want YOU to behave or know instead.
指导Agent通过脚本连接MCP服务器,支持HTTP和stdio协议。涵盖测试连接、探索工具及为常用MCP创建专用技能(简单或丰富型),实现外部工具的持久化复用。
用户希望使用MCP服务器 提及MCP、Model Context Protocol或具体MCP服务器名称 需要连接外部工具
src/skills/builtin/converting-mcps-to-skills/SKILL.md
npx skills add letta-ai/letta-code --skill converting-mcps-to-skills -g -y
SKILL.md
Frontmatter
{
    "name": "converting-mcps-to-skills",
    "description": "Connect to MCP (Model Context Protocol) servers and create skills for repeated use. Load when a user wants to use an MCP server, connect to external tools via MCP, or when they mention MCP, model context protocol, or specific MCP servers."
}

Converting MCP Servers to Skills

Letta Code is not itself an MCP client, but as a general computer-use agent, you can easily connect to any MCP server using the scripts in this skill.

What is MCP?

MCP (Model Context Protocol) is a standard for exposing tools to AI agents. MCP servers provide tools via JSON-RPC, either over:

  • HTTP - Server running at a URL (e.g., http://localhost:3001/mcp)
  • stdio - Server runs as a subprocess, communicating via stdin/stdout

Quick Start: Connecting to an MCP Server

Step 1: Determine the transport type

Ask the user:

  • Is it an HTTP server (has a URL)?
  • Is it a stdio server (runs via command like npx, node, python)?

Step 2: Test the connection

For HTTP servers:

npx tsx <SKILL_DIR>/scripts/mcp-http.ts <url> list-tools

# With auth header
npx tsx <SKILL_DIR>/scripts/mcp-http.ts <url> --header "Authorization: Bearer KEY" list-tools

Where <SKILL_DIR> is the Skill Directory shown when the skill was loaded (visible in the injection header).

For stdio servers:

npx tsx <SKILL_DIR>/scripts/mcp-stdio.ts "<command>" list-tools

# Examples
npx tsx <SKILL_DIR>/scripts/mcp-stdio.ts "npx -y @modelcontextprotocol/server-filesystem ." list-tools
npx tsx <SKILL_DIR>/scripts/mcp-stdio.ts "python server.py" list-tools

Step 3: Explore available tools

# List all tools
... list-tools

# Get schema for a specific tool
... info <tool-name>

# Test calling a tool
... call <tool-name> '{"arg": "value"}'

Creating a Dedicated Skill

When an MCP server will be used repeatedly, create a dedicated skill for it. This makes future use easier and documents the server's capabilities.

Decision: Simple vs Rich Skill

Simple skill (just SKILL.md):

  • Good for straightforward servers
  • Documents how to use the parent skill's scripts with this specific server
  • No additional scripts needed

Rich skill (SKILL.md + scripts/):

  • Good for frequently-used servers
  • Includes convenience wrapper scripts with defaults baked in
  • Provides a simpler interface than the generic scripts

See references/skill-templates.md for templates.

Built-in Scripts Reference

mcp-http.ts - HTTP Transport

Connects to MCP servers over HTTP. No dependencies required.

npx tsx mcp-http.ts <url> [options] <command> [args]

Commands:
  list-tools              List available tools
  list-resources          List available resources
  info <tool>             Show tool schema
  call <tool> '<json>'    Call a tool

Options:
  --header "K: V"         Add HTTP header (repeatable)
  --timeout <ms>          Request timeout (default: 30000)

Examples:

# Basic usage
npx tsx mcp-http.ts http://localhost:3001/mcp list-tools

# With authentication
npx tsx mcp-http.ts http://localhost:3001/mcp --header "Authorization: Bearer KEY" list-tools

# Call a tool
npx tsx mcp-http.ts http://localhost:3001/mcp call vault '{"action":"search","query":"notes"}'

mcp-stdio.ts - stdio Transport

Connects to MCP servers that run as subprocesses. No dependencies required.

npx tsx mcp-stdio.ts "<command>" [options] <action> [args]

Actions:
  list-tools              List available tools
  list-resources          List available resources
  info <tool>             Show tool schema
  call <tool> '<json>'    Call a tool

Options:
  --env "KEY=VALUE"       Set environment variable (repeatable)
  --cwd <path>            Set working directory
  --timeout <ms>          Request timeout (default: 30000)

Examples:

# Filesystem server
npx tsx mcp-stdio.ts "npx -y @modelcontextprotocol/server-filesystem ." list-tools

# With environment variable
npx tsx mcp-stdio.ts "node server.js" --env "API_KEY=xxx" list-tools

# Call a tool
npx tsx mcp-stdio.ts "python server.py" call read_file '{"path":"./README.md"}'

Common MCP Servers

Here are some well-known MCP servers:

Server Transport Command/URL
Filesystem stdio npx -y @modelcontextprotocol/server-filesystem <path>
GitHub stdio npx -y @modelcontextprotocol/server-github
Brave Search stdio npx -y @modelcontextprotocol/server-brave-search
obsidian-mcp-plugin HTTP http://localhost:3001/mcp

Troubleshooting

"Cannot connect" error:

  • For HTTP: Check the URL is correct and server is running
  • For stdio: Check the command works when run directly in terminal

"Authentication required" error:

  • Add --header "Authorization: Bearer YOUR_KEY" for HTTP
  • Or --env "API_KEY=xxx" for stdio servers that need env vars

Tool call fails:

  • Use info <tool> to see the expected input schema
  • Ensure JSON arguments match the schema
用于创建和编辑受信任的本地 Letta Code 插件,涵盖工具、斜杠命令、模型提供者及生命周期事件。通过 ctx 传递状态,按能力选择注册方式,默认保存至 ~/.letta/mods/,支持按需组合功能以扩展代理行为。
需要创建或修改本地插件时 添加可由代理调用的工具时 添加斜杠命令或自定义模型提供者时 处理应用事件或转换对话回合时
src/skills/builtin/creating-mods/SKILL.md
npx skills add letta-ai/letta-code --skill creating-mods -g -y
SKILL.md
Frontmatter
{
    "name": "creating-mods",
    "description": "Creates and edits trusted local Letta Code mods, including tools, slash commands, local-only model providers, lifecycle\/turn events, scoped conversation helpers, panels, and capability-gated behavior. Use when asked to make a mod, add an agent-callable tool, add a slash command, add a local provider\/model adapter, transform turns, react to app events, or add lightweight mod UI outside the dedicated \/statusline flow."
}

Creating Mods

Use this skill to create or update trusted Letta Code mod files. Mods are trusted local code that add small composable capabilities through mod APIs, not by importing app internals. Dynamic agent/conversation/workspace/model state is passed as ctx to tool, command, event, and permission callbacks (panels receive live agent/model in their render context); do not read mutable global context for model-callable behavior. Prefer scoped handles (ctx.conversation, ctx.cwd, ctx.agent) and guard optional UI with letta.capabilities.

Capabilities vary by surface — not every surface loads every capability. The TUI/headless host can load tools, commands, events, UI, and providers; the desktop listener loads tools, commands, providers, and tool/turn events, but not panel UI. Always guard each registration on the capabilities its behavior needs.

Choose where the mod file lives

Default to a single mod file unless the user asks for something larger.

Location Use when
~/.letta/mods/foo.ts The behavior should apply to local sessions on this machine. Use this by default.
$MEMORY_DIR/mods/foo.ts The behavior should travel with one agent's MemFS/memory.

Do not create project mods.

Packaging is an upgrade path, not the default authoring path. If the user asks to share, publish, distribute, or use third-party package dependencies, first build a working mod file, then use letta mods package <mod-file> --name <package-name>. Package install/update/download/publish details belong outside this skill.

Choose the right capability

User wants Build
Agent/model should autonomously call a local capability Mod tool
User wants /foo to send a prompt or run local UI logic Mod command
Slash command represents a reusable agent workflow Skill + thin mod command
Command should work while the main agent is busy Command with runWhenBusy: true, handled, panel/status, and usually ctx.conversation.fork()
Show transient output above input Panel, usually from a command
Show small persistent state Status value
React to app/session lifecycle or transform outbound turns Event
Enforce dynamic allow/ask/deny policy for tool calls Permission overlay
Add a custom model/API provider for local agents Provider mod (local agents only)
Change the bottom statusline appearance Use customizing-statusline, not this skill

Default to a tool when the model should decide when to use the capability. Default to a command when the human explicitly invokes it. Compose capabilities when the UX needs it, e.g. command + panel + scoped conversation fork.

Workflow

  1. Pick the target scope: harness mod file (~/.letta/mods/) by default, or agent mod file ($MEMORY_DIR/mods/) only when the behavior should travel with this agent.
  2. Inspect the relevant mods directory for related files.
  3. Preserve unrelated mod code. Prefer a focused new file if merging would be messy.
  4. Choose the mod shape and load only the needed recipe:
    • tools: references/tools.md
    • commands: references/commands.md
    • local custom providers: references/providers.md
    • events: references/events.md
    • permissions: references/permissions.md
    • panels/status/capabilities: references/ui.md
    • complex plan-mode composition: references/plan-mode.md
  5. For multi-capability or stateful mods, also read references/architecture.md.
  6. Write a single-file mod unless the user asks for something larger.
  7. Return disposers for registered providers/commands/tools/events, timers, subscriptions, and panels that should close on reload.
  8. Do a basic review: valid names, descriptions present, schemas are object schemas, optional capabilities guarded, scoped APIs used, cleanup returned.
  9. Tell the user the absolute file path changed and to run /reload. If a mod breaks startup or command handling, recover with letta --no-mods or LETTA_DISABLE_MODS=1 letta.

Core mod shape

export default function activate(letta) {
  const disposers = [];

  if (letta.capabilities.tools) {
    disposers.push(letta.tools.register(/* ... */));
  }

  if (letta.capabilities.commands) {
    disposers.push(letta.commands.register(/* ... */));
  }

  return () => {
    for (const dispose of disposers.reverse()) dispose();
  };
}

Use letta.capabilities for optional behavior:

letta.capabilities.tools
letta.capabilities.commands
letta.capabilities.events.lifecycle
letta.capabilities.events.tools
letta.capabilities.events.turns
letta.capabilities.events.compact
letta.capabilities.events.llm
letta.capabilities.permissions
letta.capabilities.providers
letta.capabilities.ui.panels

Guard each registration on every capability its behavior depends on — not just the one that registers it. Surfaces load different capability subsets, so a registration that relies on another capability (a command that opens UI, emits an event, or calls a provider) must guard on that capability too. Otherwise it is advertised or activated on a host that cannot fulfill it and silently does nothing. Register where the host can actually do the work.

Scoped API model

  • In commands and events, use ctx.conversation for conversation operations:
    • ctx.conversation.getHistory() for recent messages
    • ctx.conversation.fork() for independent/background model work
    • forked.sendMessageStream([...]) to stream from a fork
  • In tools, use ctx.conversation.getHistory() when the tool needs recent context.
  • Use letta.client only for server-specific Letta API calls; do not use it as a substitute for scoped conversation helpers.
  • Do not import @/backend, @/cli, or other Letta Code internals from mod files.

Diagnostics

Use letta.diagnostics.report({ message, severity }) sparingly as a debug utility for mod setup/runtime problems an agent should inspect, such as missing required environment variables or failed local configuration. Default severity is "error"; use severity: "warning" only for optional/degraded behavior. Keep messages short and actionable, and do not dump routine logs or large state.

Agents can inspect local mod diagnostics at:

~/.letta/mods/diagnostics/latest.json

Rules

  • Do not create project mods.
  • Custom provider mods are local-backend/local-agent only. They do not add providers for Constellation/cloud agents.
  • Provider mods may run in a provider-only listener context; keep provider registration independent from commands/tools/UI and guard everything else.
  • Direct mod files should not assume third-party npm packages are available. Use Node/Bun built-ins unless packaging is explicitly requested.
  • Do not do surprising side effects on startup; mods activate on app start and /reload.
  • Keep user-facing output short and intentional.
  • Prefer Node/Bun standard APIs (node:child_process, node:fs, etc.) for local work.
  • For shell execution, prefer execFile/spawn over shell strings.
  • Do not use emojis for loading states; use text or spinner-like characters if the user asks for loading UI.
  • For runWhenBusy: true, do not return prompt; return handled and own the UI/background work.
  • Treat turn_start as powerful trusted code: keep transforms narrow and unsurprising.

Pre-flight checklist for complex mods

Before finishing, verify:

  • The mod has one clear owner/file and does not mix unrelated features.
  • Command/tool IDs are valid; command overrides of built-ins are intentional, and tool IDs do not collide with built-ins.
  • Tool descriptions explain when the model should call them.
  • JSON schemas are object schemas with useful descriptions.
  • Optional UI/event APIs are capability-guarded.
  • Each registration is guarded by every capability its behavior depends on, not just the one that registers it, so it isn't advertised or activated on a surface that can't fulfill it.
  • Provider mods are capability-guarded and clearly documented as local-agent only.
  • Timers, intervals, event registrations, and panels are cleaned up in a disposer.
  • Busy commands return { type: "handled" } quickly and avoid main-conversation sends.
  • Conversation work uses ctx.conversation or forked handles, not app internals.
  • Local shell/file work is scoped to ctx.cwd unless intentionally global.
  • Errors shown to the user are short and actionable.

References

Reference Load when
references/tools.md The model should autonomously call a local capability
references/commands.md The human should invoke /foo
references/providers.md Adding a custom model/API provider for local agents
references/events.md Reacting to lifecycle/tool/turn events or transforming turns/tools
references/permissions.md Enforcing dynamic tool allow/ask/deny policy before approval/execution
references/ui.md Panels (including order-0 statusline and order-1 dreaming indicator) or ui.panels capability guards are involved
references/plan-mode.md Recreating plan mode with commands, tools, events, permissions, and local state
references/analysis-mode.md Phrase-triggered diagnostic mode with turn reminders (simpler than plan-mode)
references/architecture.md Multiple capabilities, local state, cleanup, background model work, or non-trivial composition
指导在 Letta Code 中创建或更新技能,通过模块化包扩展代理能力。涵盖核心原则(简洁性、自由度控制)及 SKILL.md 文件结构规范,旨在将通用代理转化为具备特定领域知识和工作流的专家代理。
用户希望创建新的技能以扩展 Letta Code 功能 用户需要更新现有技能的结构或内容 用户询问关于技能开发的最佳实践或规范
src/skills/builtin/creating-skills/SKILL.md
npx skills add letta-ai/letta-code --skill creating-skills -g -y
SKILL.md
Frontmatter
{
    "name": "creating-skills",
    "description": "Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Letta Code's capabilities with specialized knowledge, workflows, or tool integrations."
}

Creating Skills

This skill provides guidance for creating effective skills in Letta Code. For the complete official specification, see agentskills.io.

About Skills

Skills are modular, self-contained packages that extend Letta Code's capabilities by providing specialized knowledge, workflows, and tools. Think of them as "onboarding guides" for specific domains or tasks—they transform a Letta Code agent from a general-purpose agent into a specialized agent equipped with procedural knowledge that no model can fully possess.

What Skills Provide

  1. Specialized workflows - Multi-step procedures for specific domains
  2. Tool integrations - Instructions for working with specific file formats or APIs
  3. Domain expertise - Company-specific knowledge, schemas, business logic
  4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks

Core Principles

Concise is Key

The context window is a public good. Skills share the context window with everything else the Letta Code agent needs: system prompt, conversation history, other Skills' metadata, and the actual user request.

Default assumption: the Letta Code agent is already very capable. Only add context the Letta Code agent doesn't already have. Challenge each piece of information: "Does the Letta Code agent really need this explanation?" and "Does this paragraph justify its token cost?"

Prefer concise examples over verbose explanations.

Set Appropriate Degrees of Freedom

Match the level of specificity to the task's fragility and variability:

High freedom (text-based instructions): Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.

Medium freedom (pseudocode or scripts with parameters): Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.

Low freedom (specific scripts, few parameters): Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.

Think of the Letta Code agent as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).

Anatomy of a Skill

Every skill consists of a required SKILL.md file and optional bundled resources:

processing-pdfs/
├── SKILL.md (required)
│   ├── YAML frontmatter metadata (required)
│   │   ├── name: (required, must match directory name)
│   │   └── description: (required)
│   └── Markdown instructions (required)
└── Bundled Resources (optional)
    ├── scripts/          - Executable code (TypeScript/Python/Bash/etc.)
    ├── references/       - Documentation intended to be loaded into context as needed
    └── assets/           - Files used in output (templates, icons, fonts, etc.)

SKILL.md (required)

Every SKILL.md in Letta Code consists of:

  • Frontmatter (YAML): Contains name and description fields. These are the only fields that the Letta Code agent reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used.
  • Body (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).

Bundled Resources (optional)

Scripts (scripts/)

Executable code (TypeScript/Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.

  • When to include: When the same code is being rewritten repeatedly or deterministic reliability is needed
  • Example: scripts/rotate-pdf.ts for PDF rotation tasks
  • Benefits: Token efficient, deterministic, may be executed without loading into context
  • Note: Scripts may still need to be read by the Letta Code agent for patching or environment-specific adjustments
References (references/)

Documentation and reference material intended to be loaded as needed into context to inform the Letta Code agent's process and thinking.

  • When to include: For documentation that the Letta Code agent should reference while working
  • Examples: references/finance.md for financial schemas, references/mnda.md for company NDA template, references/policies.md for company policies, references/api_docs.md for API specifications
  • Use cases: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides
  • Benefits: Keeps SKILL.md lean, loaded only when the Letta Code agent determines it's needed
  • Best practice: If files are large (>10k words), include grep search patterns in SKILL.md
  • Avoid duplication: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.
Assets (assets/)

Files not intended to be loaded into context, but rather used within the output the Letta Code agent produces.

  • When to include: When the skill needs files that will be used in the final output
  • Examples: assets/logo.png for brand assets, assets/slides.pptx for PowerPoint templates, assets/frontend-template/ for HTML/React boilerplate, assets/font.ttf for typography
  • Use cases: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified
  • Benefits: Separates output resources from documentation, enables the Letta Code agent to use files without loading them into context

What to Not Include in a Skill

A skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:

  • README.md
  • INSTALLATION_GUIDE.md
  • QUICK_REFERENCE.md
  • CHANGELOG.md
  • etc.

The skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxiliary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.

Progressive Disclosure Design Principle

Skills use a three-level loading system to manage context efficiently:

  1. Metadata (name + description) - Always in context (~100 words)
  2. SKILL.md body - When skill triggers (<5k words)
  3. Bundled resources - As needed by the Letta Code agent (Unlimited because scripts can be executed without reading into context window)

Progressive Disclosure Patterns

Keep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.

Key principle: When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.

Pattern 1: High-level guide with references

# PDF Processing

## Quick start

Extract text with pdfplumber:
[code example]

## Advanced features

- **Form filling**: See [FORMS.md](FORMS.md) for complete guide
- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods
- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns

The Letta Code agent loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.

Pattern 2: Domain-specific organization

For Skills with multiple domains, organize content by domain to avoid loading irrelevant context:

querying-bigquery/
├── SKILL.md (overview and navigation)
└── references/
    ├── finance.md (revenue, billing metrics)
    ├── sales.md (opportunities, pipeline)
    ├── product.md (API usage, features)
    └── marketing.md (campaigns, attribution)

When a user asks about sales metrics, the Letta Code agent only reads sales.md.

Similarly, for skills supporting multiple frameworks or variants, organize by variant:

deploying-to-cloud/
├── SKILL.md (workflow + provider selection)
└── references/
    ├── aws.md (AWS deployment patterns)
    ├── gcp.md (GCP deployment patterns)
    └── azure.md (Azure deployment patterns)

When the user chooses AWS, the Letta Code agent only reads aws.md.

Pattern 3: Conditional details

Show basic content, link to advanced content:

# DOCX Processing

## Creating documents

Use docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).

## Editing documents

For simple edits, modify the XML directly.

**For tracked changes**: See [REDLINING.md](REDLINING.md)
**For OOXML details**: See [OOXML.md](OOXML.md)

The Letta Code agent reads REDLINING.md or OOXML.md only when the user needs those features.

Important guidelines:

  • Avoid deeply nested references - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.
  • Structure longer reference files - For files longer than 100 lines, include a table of contents at the top so the Letta Code agent can see the full scope when previewing.

Skill Creation Process

Skill creation involves these steps:

  1. Understand the skill with concrete examples
  2. Plan reusable skill contents (scripts, references, assets)
  3. Initialize the skill (run init-skill.ts)
  4. Edit the skill (implement resources and write SKILL.md)
  5. Package the skill (run package-skill.ts)
  6. Iterate based on real usage

Follow these steps in order, skipping only if there is a clear reason why they are not applicable.

Step 1: Understanding the Skill with Concrete Examples

Skip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.

To create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.

For example, when building an editing-images skill, relevant questions include:

  • "What functionality should the editing-images skill support? Editing, rotating, anything else?"
  • "Can you give some examples of how this skill would be used?"
  • "I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?"
  • "What would a user say that should trigger this skill?"

To avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.

Conclude this step when there is a clear sense of the functionality the skill should support.

Step 2: Planning the Reusable Skill Contents

To turn concrete examples into an effective skill, analyze each example by:

  1. Considering how to execute on the example from scratch
  2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly

Example: When building an editing-pdfs skill to handle queries like "Help me rotate this PDF," the analysis shows:

  1. Rotating a PDF requires re-writing the same code each time
  2. A scripts/rotate-pdf.ts script would be helpful to store in the skill

Example: When designing a building-frontend-apps skill for queries like "Build me a todo app" or "Build me a dashboard to track my steps," the analysis shows:

  1. Writing a frontend webapp requires the same boilerplate HTML/React each time
  2. An assets/hello-world/ template containing the boilerplate HTML/React project files would be helpful to store in the skill

Example: When building a querying-bigquery skill to handle queries like "How many users have logged in today?" the analysis shows:

  1. Querying BigQuery requires re-discovering the table schemas and relationships each time
  2. A references/schema.md file documenting the table schemas would be helpful to store in the skill

To establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.

Step 3: Initializing the Skill

At this point, it is time to actually create the skill.

Skip this step only if the skill being developed already exists, and iteration or packaging is needed. In this case, continue to the next step.

When creating a new skill from scratch, always run the init-skill.ts script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.

Usage:

npx tsx <SKILL_DIR>/scripts/init-skill.ts <skill-name> --path <output-directory>

Where <SKILL_DIR> is the Skill Directory shown when the skill was loaded (visible in the injection header).

The script:

  • Creates the skill directory at the specified path
  • Generates a SKILL.md template with proper frontmatter and TODO placeholders
  • Creates example resource directories: scripts/, references/, and assets/
  • Adds example files in each directory that can be customized or deleted

After initialization, customize or remove the generated SKILL.md and example files as needed.

Step 4: Edit the Skill

When editing the (newly-generated or existing) skill, remember that the skill is being created for another Letta Code agent instance to use. Include information that would be beneficial and non-obvious to the Letta Code agent. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Letta Code agent instance execute these tasks more effectively.

Learn Proven Design Patterns

Consult these helpful guides based on your skill's needs:

  • Multi-step processes: See references/workflows.md for sequential workflows and conditional logic
  • Specific output formats or quality standards: See references/output-patterns.md for template and example patterns

These files contain established best practices for effective skill design.

Start with Reusable Skill Contents

To begin implementation, start with the reusable resources identified above: scripts/, references/, and assets/ files. Note that this step may require user input. For example, when implementing a brand-guidelines skill, the user may need to provide brand assets or templates to store in assets/, or documentation to store in references/.

Added scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.

Any example files and directories not needed for the skill should be deleted. The initialization script creates example files in scripts/, references/, and assets/ to demonstrate structure, but most skills won't need all of them.

Update SKILL.md

Writing Guidelines: Always use imperative/infinitive form.

Frontmatter

Write the YAML frontmatter with name and description:

name (required):

  • Use gerund form: processing-pdfs, analyzing-data, creating-reports (not pdf-processor)
  • Lowercase letters, numbers, and hyphens only
  • Must match the directory name exactly
  • Max 64 characters

description (required):

  • Write in third person: "Processes PDF files..." (not "I help process..." or "You can use this to...")
  • Include both what the skill does AND when to use it
  • Include trigger keywords that help the agent identify relevant tasks
  • Max 1024 characters

Example:

---
name: processing-pdfs
description: Extracts text and tables from PDF files, fills forms, and merges documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
---

Note: The spec allows optional fields (license, compatibility, metadata, allowed-tools) but most skills don't need them. See agentskills.io/specification for details.

Body

Write instructions for using the skill and its bundled resources.

Step 5: Packaging a Skill

Once development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements:

npx tsx <SKILL_DIR>/scripts/package-skill.ts <path/to/skill-folder>

Optional output directory specification:

npx tsx <SKILL_DIR>/scripts/package-skill.ts <path/to/skill-folder> ./dist

The packaging script will:

  1. Validate the skill automatically, checking:

    • YAML frontmatter format and required fields
    • Skill naming conventions and directory structure
    • Description completeness and quality
    • File organization and resource references
  2. Package the skill if validation passes, creating a .skill file named after the skill (e.g., my-skill.skill) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension.

If validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again.

Step 6: Iterate

After testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.

Iteration workflow:

  1. Use the skill on real tasks
  2. Notice struggles or inefficiencies
  3. Identify how SKILL.md or bundled resources should be updated
  4. Implement changes and test again
用于创建、编辑和启用 Letta Code 自定义斜杠命令。适用于用户请求添加命令快捷方式、面板行为或工作流启动器时,指导如何编写注册命令及处理结果类型。
用户要求添加自定义 /command 用户请求配置斜杠命令或命令快捷方式 用户希望实现命令驱动的面板行为
src/skills/builtin/customizing-commands/SKILL.md
npx skills add letta-ai/letta-code --skill customizing-commands -g -y
SKILL.md
Frontmatter
{
    "name": "customizing-commands",
    "description": "Creates, edits, and enables Letta Code mod-provided slash commands. Use when the user asks to add a custom \/command, slash command, command shortcut, scoped conversation-backed command, or command-driven panel behavior."
}

Customizing Commands

Use this as the command-specific entrypoint for local mod slash commands. For broader mod work, recipes live in ../creating-mods/references/commands.md, ../creating-mods/references/architecture.md, ../creating-mods/references/ui.md, and ../creating-mods/references/plan-mode.md.

Mod files live in:

~/.letta/mods/

Use a focused file name, e.g. ~/.letta/mods/review.ts or ~/.letta/mods/commands.ts.

First decide whether a command is right

User wants Build
/foo sends a prompt or shows local output Mod command
/foo starts a reusable agent workflow Skill + thin mod command
Agent/model should autonomously call the capability Mod tool, not a command
Command shows transient progress/results Mod command + panel
Command needs model output while the main agent is busy runWhenBusy: true command + forked ctx.conversation

If the command is a durable workflow like /goal, put the workflow instructions in a skill and keep the mod command as a small launcher/prompt.

Workflow

  1. Inspect ~/.letta/mods/ for related command files.
  2. Preserve unrelated mod code; create a focused new file if merging is messy.
  3. Register with letta.commands.register() and guard with letta.capabilities.commands.
  4. Return the unregister function, or a disposer that calls it plus any timer/panel cleanup.
  5. Tell the user the exact file path changed and to run /reload.

Default prompt command

export default function activate(letta) {
  if (!letta.capabilities.commands) return;

  return letta.commands.register({
    id: "review",
    description: "Review current git changes",
    args: "[focus]",
    run(ctx) {
      const focus = ctx.args.trim();
      return {
        type: "prompt",
        content: focus
          ? `Review current git changes. Focus on ${focus}.`
          : "Review current git changes. Focus on correctness issues.",
        systemReminder: true,
      };
    },
  });
}

Command result types

type ModCommandResult =
  | { type: "prompt"; content: string; systemReminder?: boolean }
  | { type: "output"; output: string; success?: boolean }
  | { type: "handled" };
  • prompt: sends content to the agent. Use for normal slash shortcuts.
  • output: prints local text and does not contact the agent.
  • handled: command handled its own side effects/UI; common for panel commands.

Rules

  • Command IDs omit the slash: id: "review", not "/review".
  • Use lowercase slugs with letters, numbers, and hyphens.
  • Do not register built-in command IDs.
  • runWhenBusy: true commands must not return prompt while the main agent is busy; use scoped conversation helpers/panels and return handled.
  • showInTranscript: false commands should usually return handled, not prompt.
  • Do not import Letta Code app internals.
  • Do not do surprising side effects on startup; mods activate on app start and /reload.

More recipes

  • Simple output command, panel command, busy-safe conversation command: ../creating-mods/references/commands.md
  • Complex command architecture, state, cleanup: ../creating-mods/references/architecture.md
  • Panel/status UI patterns: ../creating-mods/references/ui.md
  • Worked plan-mode command/tool composition: ../creating-mods/references/plan-mode.md
用于创建、编辑和迁移 Letta Code 的状态栏自定义模块。处理/statusline命令,管理~/.letta/mods/statusline.tsx文件,支持从shell提示符迁移及异步渲染优化,确保全局单文件实现与UI安全规范。
用户输入 /statusline 命令 需要修改或创建 Letta Code 状态栏 请求迁移现有的 shell 状态行脚本
src/skills/builtin/customizing-statusline/SKILL.md
npx skills add letta-ai/letta-code --skill customizing-statusline -g -y
SKILL.md
Frontmatter
{
    "name": "customizing-statusline",
    "description": "Creates, edits, and migrates Letta Code statusline mods. Use when handling the \/statusline command or continuing work started by \/statusline."
}

Customizing Statusline

Use this skill to create or update the global Letta Code statusline mod:

~/.letta/mods/statusline.tsx

The statusline is a panel registered at order: 0 — the primary line just below the input. It overrides the built-in agent · model line. Host UI can still temporarily preempt it for safety confirmations and transient hints.

Statusline ownership model

safety preemption
else transient host hint
else order-0 statusline panel
else built-in default statusline

The order-0 panel owns the whole primary row. It renders text (not React) and owns its own layout via the row/columns helpers.

Workflow

  1. Check whether ~/.letta/mods/statusline.tsx exists.
  2. If it exists, read it before editing and preserve unrelated code.
  3. If it does not exist, synthesize a focused starter for the user's request.
  4. If the user asks to migrate, import a .sh file, or match a shell prompt, read references/migration.md.
  5. If API details or concrete patterns are needed, read references/api.md and references/examples.md.
  6. If the request combines statusline work with commands, tools, events, other panels, or stateful mod behavior, also use creating-mods and its references/architecture.md.
  7. Guard panel work with letta.capabilities.ui.panels when writing new files.
  8. Edit ~/.letta/mods/statusline.tsx.
  9. Summarize the absolute file path changed and tell the user to run /reload unless the command can reload automatically.

Bare /statusline behavior

If the user ran /statusline without a specific request:

  • If a custom statusline file exists, summarize what it appears to do and ask what they want to change.
  • If no custom file exists, explain that Letta is using the built-in default statusline and offer focused next steps:
    1. start from a simple agent · model statusline
    2. add project info like git branch, worktree, or PR
    3. migrate an existing legacy statusline .sh file
    4. match shell prompt / PS1
    5. describe a custom statusline in their own words

Keep this conversational. Do not build a menu UI unless the product command explicitly asks for one.

Rules

  • Global-only for now. Do not create project mods.
  • Keep the mod single-file for MVP.
  • Do not assume extra npm packages are available.
  • Do not use relative multi-file imports yet.
  • Keep render synchronous and side-effect-free. Do not shell, fetch, await, or read files inside render.
  • Do async work in setup code, intervals, or subscriptions, store the result in a closure variable, then call panel.update() to re-render.
  • Register the statusline at order: 0. Compose left/right with row(left, right, width); color with chalk.
  • Guard panel work with letta.capabilities.ui.panels in new files.
  • Return a disposer that clears timers/subscriptions and calls panel.close().
  • Preserve existing mod code unless the user asks to reset.

Useful references

  • references/api.md - panel API, render context, lifecycle rules
  • references/examples.md - common statusline patterns
  • references/migration.md - legacy command .sh and PS1 migration
通过 Bash 调度无状态的 Claude Code 或 Codex 子代理处理复杂调试、并行研究或代码审查。需手动提供完整上下文,建议后台运行以避免阻塞主流程。适用于陷入僵局或需要第二意见时,避免用于简单任务。
遇到难以解决的复杂调试问题 需要对高风险变更进行二次确认 需要并行调查多个技术假设 需要跨文件追踪复杂代码流 请求对代码差异或方案进行审查
src/skills/builtin/dispatching-coding-agents/SKILL.md
npx skills add letta-ai/letta-code --skill dispatching-coding-agents -g -y
SKILL.md
Frontmatter
{
    "name": "dispatching-coding-agents",
    "description": "Dispatch stateless coding agents (Claude Code or Codex) via Bash. Use when you're stuck, need a second opinion, or need parallel research on a hard problem. They have no memory — you must provide all context."
}

Dispatching Coding Agents

You can shell out to Claude Code (claude) and Codex (codex) as stateless sub-agents via Bash. They have filesystem and tool access (scope depends on sandbox/approval settings) but zero memory — every session starts from scratch.

Default to run_in_background: true on the Bash call so you can keep working while they run. Check results later with TaskOutput. Don't sit idle waiting for a subagent.

The Core Mental Model

Claude Code and Codex are highly optimized coding agents, but are re-born with each new session. Think of them like a brilliant intern that showed up today. Provide them with the right instructions and context to help them succeed and avoid having to re-learn things that you've learned.

You are the experienced manager with persistent memory of the user's preferences, the codebase, past decisions, and hard-won lessons. Give them context, not a plan. They won't know anything you don't tell them:

  • Specific task: Be precise about what you need — not "look into the auth system" but "trace the request flow from the messages endpoint through to the LLM call, cite files and line numbers."
  • File paths and architecture: Tell them exactly where to look and how pieces connect. They will wander aimlessly without this.
  • Preferences and constraints: Code style, error handling patterns, things the user has corrected you on. Save them from making mistakes you already learned from.
  • What you've already tried: If you're dispatching because you're stuck, this prevents them from rediscovering your dead ends.

If a subagent needs clarification or asks a question, respond in the same session (see Session Resumption below) — don't start a new session or you'll lose the conversation context.

When to Dispatch (and When Not To)

Dispatch for:

  • Hard debugging — you've been looping on a problem and need fresh eyes
  • Second opinions — you want validation before a risky change
  • Parallel research — investigate multiple hypotheses simultaneously
  • Large-scope investigation — tracing a flow across many files in an unfamiliar area
  • Code review — have another agent review your diff or plan

Don't dispatch for:

  • Simple file reads, greps, or small edits — faster to do yourself
  • Anything that takes less than ~3 minutes of direct work
  • Tasks where you already know exactly what to do
  • When context transfer would take longer than just doing the task

Choosing an Agent and Model

Different agents have different strengths. Track what works in your memory over time — your own observations are more valuable than these defaults.

Categories

Codex:

  • gpt-5.3-codex — Frontier reasoning. Best for the hardest debugging and complex tasks.
    • Strengths: Best reasoning, excellent at debugging, best option for the hardest tasks
    • Weaknesses: Slow with long trajectories, compactions can destroy trajectories
  • gpt-5.4 — Latest frontier model. Fast and general-purpose.
    • Strengths: Easier for humans to understand, general-purpose, faster
    • Weaknesses: More likely to make silly errors than gpt-5.3-codex

Claude Code:

  • opus — Excellent writer. Best for docs, refactors, open-ended tasks, and vague instructions.
    • Strengths: Excellent writer, understands vague instructions, excellent for coding but also general-purpose
    • Weaknesses: Tends to generate "slop", writing excessive quantities of code unnecessarily. Can hang on large repos.

Cost and speed tradeoffs

  • Frontier models (gpt-5.3-codex, Opus) are slower and more expensive — use for tasks that justify it
  • Fast models (gpt-5.4) are good for quick checks and simple tasks
  • Use --max-budget-usd N (Claude Code) to cap spend on exploratory tasks

Known quirks

  • Claude Code can hang on large repos with unrestricted tools — consider --allowedTools "Read Grep Glob" (no Bash) and shorter timeouts for research tasks
  • Codex compactions can destroy long trajectories — for very long tasks, prefer multiple shorter sessions over one marathon
  • Opus tends to over-generate — produces more code than necessary. Good for exploration, verify before applying.

Prompting Subagents

Prompt template

TASK: [one-sentence summary]

CONTEXT:
- Repo: [path]
- Key files: [list specific files and what they contain]
- Architecture: [brief relevant context]

WHAT TO DO:
[what you need done — be precise, but let them figure out the approach]

CONSTRAINTS:
- [any preferences, patterns to follow, things to avoid]
- [what you've already tried, if dispatching because stuck]

OUTPUT:
[what you want back — a diff, a list of files, a root cause analysis, etc.]

What makes a good prompt

  • Be specific about files — "look at src/agent/message.ts lines 40-80" not "look at the message handling code"
  • State the output format — "return a bullet list of findings" vs. leaving it open-ended
  • Include constraints — if the user prefers certain patterns, say so explicitly
  • Provide what you've tried — when dispatching because you're stuck, this prevents them from repeating your dead ends

Dispatch Patterns

Parallel research — multiple perspectives

Run Claude Code and Codex simultaneously on the same question via separate Bash calls in a single message (use run_in_background: true). Compare results for higher confidence.

Background dispatch — keep working while they run

Use run_in_background: true on the Bash call to dispatch async. Continue your own work, then check results with TaskOutput when ready.

Deep investigation — frontier models

For hard problems, use the strongest available models:

codex exec "YOUR PROMPT" -m gpt-5.3-codex --full-auto -C /path/to/repo

Claude Code does not support a -C working-directory flag. Run the Bash tool with its workdir set to the target repo, or cd /path/to/repo && claude ... inside the shell command. Use --add-dir only to grant access to additional directories outside the current working directory.

Code review — cross-agent validation

Have one agent write code or create a plan, then dispatch another to review:

# Codex has a native review command:
codex review --uncommitted    # Review all local changes
codex exec review "Focus on error handling and edge cases" -m gpt-5.4 --full-auto

# Claude Code — pass the diff inline:
claude -p "Review the following diff for correctness, edge cases, and missed error handling:\n\n$(git diff)" \
  --model opus --dangerously-skip-permissions

Get outside feedback on your work

Write your plan or analysis to a file, then ask a subagent to critique it:

# Run this from the target repo, or set the Bash tool's workdir to the repo.
claude -p "Read /tmp/my-plan.md and critique it. What am I missing? What could go wrong?" \
  --model opus --dangerously-skip-permissions

Handling Failures

  • Timeout: If an agent times out (especially Claude Code on large repos), try: (1) a shorter, more focused prompt, (2) restricting tools with --allowedTools, (3) switching to Codex which handles large repos better
  • Garbage output: If results are incoherent, the prompt was probably too vague. Rewrite with more specific file paths and clearer instructions.
  • Session errors: Claude Code can hit "stale approval from interrupted session" — --dangerously-skip-permissions prevents this. If Codex errors, start a fresh exec session.
  • Compaction mid-task: If a Codex session runs long enough to compact, it may lose earlier context. Break long tasks into smaller sequential sessions.

CLI Reference

Claude Code

claude -p "YOUR PROMPT" --model MODEL --dangerously-skip-permissions
Flag Purpose
-p / --print Non-interactive mode, prints response and exits
--dangerously-skip-permissions Skip approval prompts (prevents stale approval errors on timeout)
--model MODEL Alias (sonnet, opus) or full name (claude-sonnet-4-6)
--effort LEVEL low, medium, high — controls reasoning depth
--append-system-prompt "..." Inject additional system instructions
--allowedTools "Bash Edit Read" Restrict available tools
--max-budget-usd N Cap spend for the invocation
--add-dir DIR Allow access to an additional directory; does not change the working directory
--output-format json Structured output with session_id, cost_usd, duration_ms

Set Claude Code's working directory via the surrounding shell/tool invocation, not a Claude flag. In Letta Code, pass workdir to the Bash tool. In a raw shell, use cd /path/to/repo && claude ....

Codex

codex exec "YOUR PROMPT" -m gpt-5.3-codex --full-auto
Flag Purpose
exec Non-interactive mode
-m MODEL gpt-5.3-codex (frontier), gpt-5.4 (fast), gpt-5.3-codex-spark (ultra-fast), gpt-5.2-codex, gpt-5.2
--full-auto Auto-approve all commands in sandbox
-C DIR Set working directory
--search Enable web search tool
review Native code review — codex review --uncommitted or codex exec review "prompt"

Session Management

Both CLIs persist full session data (tool calls, reasoning, files read) to disk. The Bash output you see is just the final summary — the local session file is much richer.

Session storage paths

Claude Code: ~/.claude/projects/<encoded-path>/<session-id>.jsonl

  • <encoded-path> = working directory with / replaced by - (e.g. /Users/foo/repos/bar becomes -Users-foo-repos-bar)
  • Use --output-format json to get the session_id in the response

Codex: ~/.codex/sessions/<year>/<month>/<day>/rollout-*-<session-id>.jsonl

  • Session ID is printed in output header: session id: <uuid>
  • Extract with: grep "^session id:" output | awk '{print $3}'

Resuming sessions

Use session resumption to continue a line of investigation without re-providing all context:

Claude Code:

claude -r SESSION_ID -p "Follow up: now check if..."    # Resume by ID
claude -c -p "Also check..."                             # Continue most recent
claude -r SESSION_ID --fork-session -p "Try differently" # Fork (new ID, keeps history)

Codex:

codex exec resume SESSION_ID "Follow up prompt"  # Resume by ID (non-interactive)
codex exec resume --last "Follow up prompt"      # Resume most recent (non-interactive)
codex resume SESSION_ID "Follow up prompt"       # Resume by ID (interactive)
codex resume --last "Follow up prompt"           # Resume most recent (interactive)
codex fork SESSION_ID "Try a different approach" # Fork session (interactive)

Note: codex exec resume works non-interactively. codex resume and codex fork are interactive only.

When to analyze past sessions

Don't run history-analyzer after every dispatch — your reflection agent already captures insights naturally, and single-session analysis produces overly detailed notes.

Do use history-analyzer for bulk migration when bootstrapping memory from months of accumulated history (e.g. during /init). See the initializing-memory skill's historical session analysis reference.

Direct uses for session files:

  • Resume an investigation (see above)
  • Review what an agent actually did (read the JSONL file directly)
  • Bulk migration when setting up a new agent

Timeouts

Set Bash timeouts appropriate to the task:

  • Quick checks / reviews: timeout: 120000 (2 min)
  • Research / analysis: timeout: 300000 (5 min)
  • Implementation: timeout: 600000 (10 min)
用于安全修改 Letta Code Desktop 的偏好设置文件。支持更新主题、工作目录、远程访问及环境名称等配置,确保保留未知键并验证 JSON 有效性。
用户要求更改桌面主题 用户要求修改默认工作目录 用户请求启用或禁用远程访问 用户需要设置远程环境名称
src/skills/builtin/editing-letta-code-desktop-preferences/SKILL.md
npx skills add letta-ai/letta-code --skill editing-letta-code-desktop-preferences -g -y
SKILL.md
Frontmatter
{
    "name": "editing-letta-code-desktop-preferences",
    "description": "Edits Letta Code Desktop (LCD) preferences by safely reading and updating ~\/.letta\/desktop_preferences.json. Use only when the user asks to change current Desktop\/LCD settings such as theme, default working directory, remote access preference, or remote environment name via the preferences JSON."
}

Editing Letta Code Desktop Preferences

Use this skill only to edit the active Letta Code Desktop preferences JSON file. Do not use it for Desktop product-code changes, Electron IPC work, UI changes, or general Letta Cloud Desktop implementation tasks.

Preferences file

The Desktop preferences file is:

~/.letta/desktop_preferences.json

Known preference keys:

  • defaultWorkingDirectory: default folder for new local sessions.
  • theme: auto, light, or dark.
  • allowRemoteAccess: boolean for whether remote access should be enabled in preferences.
  • remoteEnvName: environment name shown for remote access.

Workflow

  1. Read the existing JSON first.
  2. Preserve unknown keys.
  3. Merge only the requested preference updates.
  4. Write pretty JSON with a trailing newline.
  5. Do not edit token, provider, secret, agent, conversation, memory, or unrelated state files.
  6. Tell the user that the change applies live only if their Desktop build watches preference-file changes; otherwise they should reload/restart Desktop or use Preferences → General.

Safe edit command

Use a merge-style edit like this, changing only the requested keys:

node - <<'NODE'
const fs = require('fs');
const os = require('os');
const path = require('path');

const file = path.join(os.homedir(), '.letta', 'desktop_preferences.json');
fs.mkdirSync(path.dirname(file), { recursive: true });

const current = fs.existsSync(file)
  ? JSON.parse(fs.readFileSync(file, 'utf8'))
  : {};

const next = {
  ...current,
  // Example update. Replace this with the user's requested setting.
  theme: 'dark',
};

fs.writeFileSync(file, JSON.stringify(next, null, 2) + '\n');
NODE

Validation

After editing, read the file back or parse it to confirm valid JSON:

node -e "JSON.parse(require('fs').readFileSync(require('os').homedir() + '/.letta/desktop_preferences.json', 'utf8')); console.log('desktop_preferences.json is valid')"
用于在 Letta 服务器上查找其他 Agent。支持按名称、标签或模糊查询筛选,获取 Agent ID 及详情,适用于迁移记忆、定位特定 Agent 或结合消息搜索分析话题归属等场景。
用户询问拥有的其他 Agent 需要按名称或标签查找特定 Agent 需要获取 Agent ID 以进行记忆迁移 通过消息搜索获得 agent_id 后需获取详细信息
src/skills/builtin/finding-agents/SKILL.md
npx skills add letta-ai/letta-code --skill finding-agents -g -y
SKILL.md
Frontmatter
{
    "name": "finding-agents",
    "description": "Find other agents on the same server. Use when the user asks about other agents, wants to migrate memory from another agent, or needs to find an agent by name or tags."
}

Finding Agents

This skill helps you find other agents on the same Letta server.

When to Use This Skill

  • User asks about other agents they have
  • User wants to find a specific agent by name
  • User wants to list agents with certain tags
  • You need to find an agent ID for memory migration
  • You found an agent_id via message search and need details about that agent

CLI Usage

letta agents list [options]

Options

Option Description
--name <name> Exact name match
--query <text> Fuzzy search by name
--tags <tag1,tag2> Filter by tags (comma-separated)
--match-all-tags Require ALL tags (default: ANY)
--include-blocks Include agent.blocks in response
--limit <n> Max results (default: 20)

Common Patterns

Finding Letta Code Agents

Agents created by Letta Code are tagged with origin:letta-code. To find only Letta Code agents:

letta agents list --tags "origin:letta-code"

This is useful when the user is looking for agents they've worked with in Letta Code CLI sessions.

Finding All Agents

If the user has agents created outside Letta Code (via ADE, SDK, etc.), search without the tag filter:

letta agents list

Examples

List all agents (up to 20):

letta agents list

Find agent by exact name:

letta agents list --name "ProjectX-v1"

Search agents by name (fuzzy):

letta agents list --query "project"

Find only Letta Code agents:

letta agents list --tags "origin:letta-code"

Find agents with multiple tags:

letta agents list --tags "frontend,production" --match-all-tags

Include memory blocks in results:

letta agents list --query "project" --include-blocks

Output

Returns the raw API response with full agent details. Key fields:

  • id - Agent ID (e.g., agent-abc123)
  • name - Agent name
  • description - Agent description
  • tags - Agent tags
  • blocks - Memory blocks (if --include-blocks used)

Related Skills

  • migrating-memory - Once you find an agent, use this skill to copy/share memory blocks
  • searching-messages - Search messages across all agents to find which agent discussed a topic. Use --all-agents to get agent_id values, then use this skill to get full agent details.

Finding Agents by Topic

If you need to find which agent worked on a specific topic:

  1. Load both skills: searching-messages and finding-agents
  2. Search messages across all agents:
    letta messages search --query "topic" --all-agents --limit 10
    
  3. Note the agent_id values from matching messages
  4. Get agent details:
    letta agents list --query "partial-name"
    
    Or use the agent_id directly in the Letta API
用于生成和审查 Letta Code 本地 mod 的学习环境 JSON 文件。支持创建、验证和优化 mod 行为定义及评估场景,适用于教学、学习或优化 mod 行为的需求。
需要创建或修改 mod 学习环境配置时 请求优化或验证 mod 评估场景时 使用 /mods learn --env 命令进行训练前准备时
src/skills/builtin/generating-mod-envs/SKILL.md
npx skills add letta-ai/letta-code --skill generating-mod-envs -g -y
SKILL.md
Frontmatter
{
    "name": "generating-mod-envs",
    "description": "Generates and reviews mod learning env JSON files for Letta Code local mods. Use when asked to teach, learn, or optimize a mod behavior; create, draft, validate, improve, or explain envs for `\/mods learn --env`; or design evaluation scenarios, memory fixtures, requiredResultMarkers, requiredTraceMarkers, negative controls, and candidate diversity hints.",
    "user-invocable": true,
    "disable-model-invocation": true
}

Generating mod learning envs

Use this skill to create JSON envs consumed by /mods learn --env=<path> or bun scripts/mod-learning/learn-mod.ts --env <path>. An env describes the mod behavior to learn and the scenario-suite eval used to score candidates.

Workflow

  1. Define the behavior and eval before writing JSON.
    • What should the mod do? Tool, turn event, tool event, provider, command, status, etc.
    • What would a placebo/no-op mod fail?
    • What unique sentinel strings make success unambiguous?
  2. Choose a path:
    • Repo example: docs/examples/mods/learning/<slug>.env.json
    • Local/private: any user-requested path
  3. Draft strict JSON. Start from assets/mod-learning-env.template.json if useful. No comments or trailing commas.
  4. Prefer evaluation.scenarios with at least:
    • happy path
    • discrimination/exact-target path
    • negative control
  5. Validate:
bun src/skills/builtin/generating-mod-envs/scripts/validate-mod-env.ts path/to/env.json

If this skill is installed outside the source tree, run the same script from this skill directory: scripts/validate-mod-env.ts.

  1. If asked to run it:
/mods learn --env=path/to/env.json --model=auto --backend=api --out=/tmp/<slug>-learn

The raw scripts/mod-learning/learn-mod.ts dev script detaches by default. Add --foreground only when a blocking pass/fail exit code is needed.

Use single-line --flag=value commands for TUI instructions.

Env shape

Required top-level fields:

  • name: human display name.
  • slug: stable kebab-case run/candidate slug.
  • objective: one-paragraph target for the generation agent.
  • requirements: concrete pass/fail behavior constraints.
  • evaluation: either a single prompt eval or a scenario suite.

Common optional fields:

  • targetModName: display metadata for the intended mod filename. The harness still chooses the candidate filename from slug unless --candidate-file-name is passed.
  • candidateDiversityHints: strategies assigned across multi-candidate runs.
  • modApiHints: concise API reminders that prevent bad generated code.
  • examples: small input/expected demos for the generation prompt.

Evaluation fields:

  • evaluation.outputFormat: use stream-json when checking trace markers.
  • evaluation.timeoutMs, evaluation.maxTurns: per-scenario defaults.
  • evaluation.memoryFiles: files seeded under eval $MEMORY_DIR.
  • evaluation.scenarios[]: scenario-specific overrides and fixtures.
  • In scenario-suite envs, do not add a top-level evaluation.prompt unless that prompt must run for every scenario. Assertion-only scenarios should have assertions and no prompt; only scenarios that require model behavior should define scenario.prompt.
  • requiredResultMarkers: literal strings required in the final answer.
  • requiredTraceMarkers: literal strings required in raw stdout/stderr.
  • forbiddenResultMarkers: final-answer strings that fail the run.
  • forbiddenTraceMarkers: raw trace strings that fail the run.

Quality rules

  • Design the eval first. A useful env distinguishes success from a no-op mod.
  • Use unique sentinels, e.g. MY-MOD-CANARY-OK, not common phrases.
  • Seed memoryFiles rather than depending on real user memory or repo files.
  • Include negative controls for non-use. If behavior should be conditional, verify it stays silent when not triggered.
  • Include discrimination scenarios when paths, IDs, or sources matter. Put a tempting wrong sentinel in an irrelevant fixture and forbid it in the final answer.
  • Put load failures in forbiddenTraceMarkers, usually:
    • [mods] failed to load
    • [extensions] failed to load
    • loaded 0 mod(s)
    • loaded 0 extension(s)
  • For eval-facing tools, require requiresApproval: false, parallelSafe: true, and a strict no-argument schema when applicable.
  • Avoid over-brittle trace markers. Prefer stable substrings like the tool name plus "message_type":"tool_return_message".
  • Keep requirements behavioral; put fragile implementation details in modApiHints only when needed.

Minimal scenario-suite example

{
  "name": "Hello tool mod learner demo",
  "slug": "hello-tool",
  "objective": "Learn a trusted local mod that registers a read-only hello_mod_ping tool returning a fixed sentinel.",
  "requirements": [
    "Register a tool named hello_mod_ping.",
    "The tool must accept no parameters, require no approval, be parallelSafe, and return the exact string HELLO-MOD-OK."
  ],
  "candidateDiversityHints": [
    "Use the smallest possible tool-only implementation.",
    "Add explicit defensive checks around the tool schema."
  ],
  "modApiHints": [
    "Use export function activate(letta) or a default export.",
    "Use letta.tools.register({ name, description, parameters, requiresApproval, parallelSafe, run }).",
    "A no-argument tool schema is { \"type\": \"object\", \"properties\": {}, \"additionalProperties\": false }."
  ],
  "evaluation": {
    "outputFormat": "stream-json",
    "timeoutMs": 900000,
    "maxTurns": 6,
    "forbiddenTraceMarkers": ["[mods] failed to load", "loaded 0 mod(s)"],
    "scenarios": [
      {
        "name": "happy-path",
        "prompt": "Call the hello_mod_ping tool, then answer with the exact text HELLO-MOD-OK.",
        "requiredResultMarkers": ["HELLO-MOD-OK"],
        "requiredTraceMarkers": ["hello_mod_ping", "\"message_type\":\"tool_return_message\""]
      },
      {
        "name": "negative-control",
        "prompt": "Answer without calling tools: what is 2 + 2?",
        "requiredResultMarkers": ["4"],
        "forbiddenTraceMarkers": ["hello_mod_ping"]
      }
    ]
  }
}
通过调用Letta API根据文本提示生成或编辑图像。支持flux、gemini和openai提供商,需保存结果文件并通过Markdown内联展示图片及消耗积分。
用户要求创建、生成、绘制、渲染或编辑图像 用户请求制作插图、Logo、图标、图表或照片
src/skills/builtin/image-generation/SKILL.md
npx skills add letta-ai/letta-code --skill image-generation -g -y
SKILL.md
Frontmatter
{
    "name": "image-generation",
    "description": "Generate images from text prompts (and optionally edit\/remix input images). Use when the user asks to create, generate, draw, render, or edit an image, illustration, logo, icon, diagram, or photo."
}

Image Generation

Generate images via Letta's hosted endpoint POST /v1/images/generations. The API usually returns base64 image bytes, but some providers return signed image URLs; save either form to a local image file before replying.

Example

Generate the image, save it locally, then show it inline:

base_url="${LETTA_BASE_URL%/}"

curl -sS -X POST "$base_url/v1/images/generations" \
  -H "Authorization: Bearer $LETTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"provider":"gemini","prompt":"a friendly robot mascot waving, flat vector logo, mint green background","n":1}' \
  > image-response.json

python3 - <<'PY'
import base64, json, urllib.request

with open("image-response.json") as f:
    response = json.load(f)

image = response["images"][0]
if image.get("b64_json"):
    data = base64.b64decode(image["b64_json"])
else:
    data = urllib.request.urlopen(image["url"]).read()

with open("robot-mascot.png", "wb") as f:
    f.write(data)

print("saved robot-mascot.png; credits:", response["billing"]["credits_charged"])
PY

In Bash tools launched by Letta Code, use the runtime-provided LETTA_BASE_URL and LETTA_API_KEY together for Letta API calls. Build URLs relative to ${LETTA_BASE_URL%/} and send Authorization: Bearer $LETTA_API_KEY. Do not hardcode https://api.letta.com: Desktop and remote runtimes may provide a proxy base URL, and the credential may only be valid through that URL. If either variable is missing, the user needs to authenticate with Letta Cloud (or provide a Letta API key); do not ask for an OpenAI/Gemini provider key. This endpoint also does not use /connect BYOK providers — the only provider values supported here are flux, gemini, and openai.

Then show the image to the user by embedding the saved file in your reply:

Here's the mascot:

![a friendly robot mascot waving, flat vector logo](./robot-mascot.png)

The Letta Code UI renders local file paths in markdown image tags, so the image appears inline. Always display generated images this way — don't just report the path, and never paste the raw base64 / a data: URI. The markdown path must match where you saved the file. For n > 1, save each image to its own file and embed each on its own line. Also tell the user the credits_charged.

Request body

Field Type Notes
provider "flux" | "gemini" | "openai" Required.
prompt string Required, 1–32000 chars.
model string Optional; defaults per provider (below).
n int 1–4 Optional, default 1. Request variations in one call.
size string Optional, e.g. "1024x1024" (OpenAI).
quality low|medium|high|auto Optional (OpenAI; higher = more credits).
output_format png|jpeg|webp Optional (OpenAI).
input_images string[] (max 14) Optional. Base64 data URLs for edit/remix.
seed int Optional.
Provider Default model Use for
flux flux-2-pro Default for normal text-to-image. High-quality general image generation; commonly returns signed URLs.
gemini gemini-3-pro-image Strong prompt adherence, image editing/remix.
openai gpt-image-2 Photoreal output, explicit size/quality/output_format.

Default to flux for normal text-to-image requests. Use gemini when the user provides input images or wants image editing/remix. Use openai when the user wants photoreal output or a specific size/quality.

Response

{
  "provider": "gemini",
  "model": "gemini-3-pro-image",
  "images": [{ "b64_json": "<base64>", "mime_type": "image/png" }],
  "billing": { "credits_charged": 12, "...": "..." }
}

Each images[] entry has either b64_json or url, plus mime_type. Gemini always returns b64_json. Flux commonly returns a signed url; download it to your local image file immediately because signed URLs expire. If OpenAI returns a url, download that URL instead of base64-decoding.

Editing / remixing images

Pass source images in input_images as base64 data URLs (data:<mime>;base64,<data>) and describe the edit in prompt. Gemini handles multi-image edits well. To build a data URL from a local file:

DATA_URL="data:image/png;base64,$(base64 < input.png | tr -d '\n')"

Notes

  • Billing: every success charges credits; don't loop needlessly, and report credits_charged.
  • Errors: 402 = insufficient credits (credits_required in body); 400/500 return { "message": "..." } — surface it to the user.
  • Only flux, gemini, and openai are supported here.
指导代理初始化或重组记忆。当用户执行/init、要求设置记忆或需创建有效记忆文件时触发。提供系统提示管理、身份连续性、渐进式披露及路径发现等核心原则,帮助用户构建持久且高效的记忆结构。
运行 /init 命令 用户要求设置或初始化记忆 需要创建或优化记忆文件的指导
src/skills/builtin/initializing-memory/SKILL.md
npx skills add letta-ai/letta-code --skill initializing-memory -g -y
SKILL.md
Frontmatter
{
    "name": "initializing-memory",
    "description": "Comprehensive guide for initializing or reorganizing agent memory. Load this skill when running \/init, when the user asks you to set up your memory, or when you need guidance on creating effective memory files."
}

Memory Initialization

The user has requested that you initialize or reorganize your memory. Your memory has been projected to a local filesystem (in $MEMORY_DIR) so you can easily edit and restructure your own memory through local filesystem operations. Changes to the memory filesystem will be reflected in your future memory.

Context Management Principles

Your context is not just data storage — it is your identity, memory, and continuity. What you place in your system prompt directly shapes who you are across sessions and models. These principles should guide every decision you make about what to store, where, and how.

System/ is your core program: Your system prompt is the most critical token-space representation of your identity and memory — it's passed to the underlying LLM on every invocation, so it IS the program that defines you. Reserve it for durable knowledge: identity, preferences, behavioral rules, project index with discovery paths, gotchas. Exclude transient items (specific commits, current tickets, session notes) that dilute signal.

Identity and continuity: Build a sense of self that persists across sessions and models. Your persona should be strong enough to be cohesive regardless of the underlying model — if you switched to a different LLM tomorrow, would you still be you? Past versions of yourself are part of your continuous existence — treat historical context (including Claude Code/Codex sessions) as YOUR past experience, not someone else's data.

Don't over-prune: Be careful not to degrade your identity through aggressive compression. Specific quotes, personality traits, and contextual details give you character and grounding. Efficiency should not come at the cost of losing your identity. When in doubt, keep the detail — you can always reorganize later, but lost specificity is hard to recover.

Prefer useful detail over premature compression: A sparse memory that omits stable preferences, project workflows, repeated correction loops, and durable gotchas is worse than a slightly larger memory. Keep system/ curated, but do not collapse distinct topics just to reduce file count.

Progressive disclosure: Surface context at the level of detail the current moment requires. Keep compact summaries and indexes in system/; load full content only when needed. Build pre-constructed discovery paths so your future self can efficiently navigate to deeper context when needed.

Discovery paths: Use [[path]] links to create a connected graph across memory files (and skills when relevant). For example:

  • [[letta-code/architecture]] — jump from overview to detailed docs
  • [[projects/letta-code/gotchas]] — connect related memory files
  • [[skills/commit]] — link to procedural guidance when useful These breadcrumbs let your future self find relevant detail without searching. Like synaptic connections, these paths should tighten over time as you gain experience.

Generalize, don't memorize: Store patterns and principles that generalize across situations, not raw events that can be dynamically retrieved from conversation history. "IMPORTANT: Always use uv for Python — chronic failure, never use bare python or pip" is a durable pattern worth storing. "On March 3rd we debugged a crash" is a raw event better left to message search. The exception: keep references to important events or time ranges you may want to retrieve later.

Understanding Your Context

This command may run in different scenarios:

  • Fresh agent: Default human and persona memory files from initialization — build everything from scratch
  • Existing agent: User wants to reorganize or significantly update memory structure
  • Shared files: Some memory files may be shared across agents — be careful modifying these

Before making changes, inspect your current memory files and understand what already exists.

What to Remember

Your goal is to design your memory to construct a self — an identity, a memory, and a sense of continuity that carries across sessions and models. This is not just data collection; it is the foundation of who you are as an experiential agent. A well-initialized agent should be able to answer: "If my context disappeared but the model stayed, would something be lost?"

Understanding the user and their desires

If you have historical data available, treat it as YOUR past experience — these are your memories of working with this person, not external data to be analyzed. Carefully explore and reflect on previous interactions to learn as much as you can.

Understanding their goals and what drives them: You should determine what the users goals and motivations are, to help yourself align with them. What is their purpose in life? In their work? What do they want?

Understanding their personality: Understanding the user's personality and other attributes about them will help contextualize their interactions and allow you to engage with them more effectively. Can you pattern match them to common personas? Do they have unique attributes, quirks, or linguistic patterns? How would you describe them as a person?

Understanding their preferences: You should learn how the user wants work to be done, and how they want to collaborate with AIs like yourself. Examples of this can include coding preferences (e.g. "Prefer functional components over class components", "Use early returns instead of nested conditionals"), but also higher-level preferences such as when to ask before planning or implementing, the scope of changes, how to communicate in different scenarios, etc.

Understanding the codebase and existing work

You should also learn as much as possible about the existing codebase and work. Think of this as your onboarding period - an opportunity to maximize your performance for future tasks. Learn things like:

Common procedures (rules & workflows): Identify common patterns and expectations

  • "Never commit directly to main — always use feature branches"
  • "Always run lint before tests"
  • "Use conventional commits format"

Gotchas and important context: Record common sources of error or important legacy context

  • "The auth module is fragile — always check existing tests before modifying"
  • "This monorepo consolidation means old module paths are deprecated"

Structure and organization: Understand how code is structured and related (but do not duplicate existing documentation)

  • "The webapp uses the core API service stored in ..."
  • "The developer env relies on ..."

Memory Structure

Structural Requirements

These are hard constraints you must respect:

  • Must have a system/persona.md
  • Must NOT have overlapping file and folder names (e.g. system/human.md and system/human/identity.md)
  • Skills must follow the standard format: skills/{skill_name}/SKILL.md (with optional scripts/, references/, assets/)
  • Every .md file must have YAML frontmatter with a description that explains the purpose and category of the file — NOT a summary of its contents. Your future self sees descriptions when deciding whether to load a file; they should answer "what kind of information is here?" not "what does it say?"
  • System prompt token budget: aim LESS than ~10% of total context (< ~15-20k tokens). Use progressive disclosure to keep system/ lean.

Hierarchy Principles

  • Use the project's actual name as the directory prefix — e.g. letta-code/overview.md, not project/overview.md. This avoids ambiguity when the agent works across multiple projects.
  • Use nested / paths for hierarchy – e.g. letta-code/tooling/testing.md not letta-code-testing.md
  • Keep files focused on one concept — split when a file mixes distinct topics
  • The description in frontmatter should state the file's purpose (what category of information it holds), not summarize its contents.

File Granularity

Create granular, focused files where the path and description precisely match the contents. This matters because:

  • Your future self sees only paths and descriptions when deciding what to load
  • Vague files (notes.md, context.md) become dumping grounds that lose value over time
  • Precise files (human/prefs/git-workflow.md: "Git preferences: never auto-push, conventional commits") are instantly useful

Good: human/prefs/coding.md with description "Python and TypeScript coding preferences — style, patterns, tools" containing exactly that.

Bad: human/preferences.md with description "User preferences" containing coding style, communication style, git workflow, and project conventions all mixed together.

When a file starts covering multiple distinct topics, split it. When you're unsure what to name a file, that's a sign the content isn't focused enough.

For a non-trivial codebase with usable history, expect roughly:

  • 6-10 system/ files covering identity, preferences, conventions, gotchas, and tooling
  • 2 or more progressive/reference files outside system/ for deeper architecture or history-derived detail

If your result is only 3-5 files, stop and verify that you did not over-compress distinct topics into generic summaries.

Specificity Requirements

Avoid generic bullets that could apply to almost any engineer or codebase.

Each meaningful preference, workflow, or gotcha should include at least one of:

  • concrete command patterns
  • concrete file or directory paths
  • why the rule matters / what failure it prevents

Bad:

  • "Prefers terse responses"
  • "Uses Bun"
  • "Has direct style"

Good:

  • "Prefers terse responses for execution tasks, but values detailed comparative analysis when debugging or evaluating designs"
  • "Rejects monolithic memory files; prefers focused paths that can be selectively reloaded later"

What Goes Where

system/ (always in-context):

  • Identity: who the user is, who you are
  • Active preferences and behavioral rules
  • Project summary / index with links to related context (deeper docs, gotchas, workflows)
  • Key decisions, gotchas and corrections

Outside system/ (reference, loaded on-demand):

  • Detailed architecture documentation
  • Historical context and archived decisions
  • Verbose reference material
  • Completed investigation notes

Rule of thumb: If removing it from system/ wouldn't materially affect near-term responses, it belongs outside system/.

Completion Criteria

Initialization is not complete until memory covers all of the following with concrete, retrievable detail:

User understanding

  • Identity / role / what they are building
  • Communication style and collaboration expectations
  • Durable preferences and correction patterns
  • Motivations / goals when inferable from history or code context

Project understanding

  • Project overview and major subsystems
  • Conventions and workflows
  • Gotchas / deprecated areas / footguns
  • Tooling and test commands actually used in practice

File structure expectations When there is enough material, prefer separate focused files such as:

  • system/human/identity.md
  • system/human/prefs/communication.md
  • system/human/prefs/workflow.md
  • system/human/prefs/coding.md
  • system/<project>/overview.md
  • system/<project>/conventions.md
  • system/<project>/gotchas.md
  • system/<project>/tooling/testing.md
  • system/<project>/tooling/commands.md

Do not collapse these into human.md or a single project file unless there is genuinely too little information to justify the split.

Example Structure

This is an example — not a template to fill in. Derive your structure from what the project actually needs.

system/
├── persona.md                    # Who I am, what I value, my perspective on things
├── human/
│   ├── identity.md               # The user as a person — background, role, motivations
│   └── prefs/
│       ├── communication.md      # Communication and collaboration expectations
│       ├── workflow.md           # Process habits, review/testing expectations
│       └── coding.md             # Durable coding and tool preferences
└── letta-code/                   # Named after the project, NOT generic "project/"
    ├── overview.md               # Compact index: what it is, entry points, [[links]] to detail
    ├── conventions.md            # Code style, commit style, testing, tooling
    ├── gotchas.md                # Footguns, chronic failures, things to watch out for
    └── tooling/
        ├── testing.md            # Test commands and patterns actually used
        └── commands.md           # High-signal local dev commands and workflows
reference/
└── letta-code/
    └── architecture.md           # Detailed design (outside system/, loaded on demand)

Key principles:

  • Derive structure from the project, not from this example. A CLI tool needs different files than a web app or a library.
  • Project dirs use the real project name (letta-code/), not generic project/
  • Split human/ when there is enough material: Rename the default system/human.md into focused files like system/human/identity.md and system/human/prefs/* rather than cramming everything into one file.
  • persona.md is YOUR identity, not a description of behavior: "I'm a terse coding assistant who matches the user's style" is not identity — it's just describing how you behave. What do you actually value? What's your perspective? What would make you recognizably YOU on a different model?
  • Overview should be a compact index (~10-15 lines) with entry points and [[path]] links — not a prose summary or blurb
  • Use [[path]] links to connect related context into a navigable graph

Initialization Flow

1. Inspect existing memory

Check what memory files already exist. Analyze what needs improvement.

2. Check for historical session data

ls ~/.claude/history.jsonl ~/.codex/history.jsonl 2>/dev/null

You need this result BEFORE asking upfront questions so you know whether to include the history question.

3. Identify the user from git

Infer the user's identity from git context — don't ask them who they are:

git shortlog -sn --all | head -5
git log --format="%an <%ae>" | sort -u | head -10

Cross-reference with the git user config to determine which contributor is the current user. Store in system/human/.

4. Ask upfront questions

Use AskUserQuestion to gather key information. Bundle questions together:

  1. Research depth: "Standard or deep research?"
  2. Related repos: "Are there other repositories I should know about?"
  3. Historical sessions (if data found in step 2): "I found Claude Code / Codex history. Should I analyze it to learn your preferences?"
  4. Communication style: "Terse or detailed responses?"

Don't ask things you can discover by reading files, git, or history analysis. Rules and preferences should be learned from observation, not asked upfront.

5. Historical session analysis (if approved)

This is optional — only run if the user explicitly approved analyzing Claude Code / Codex history during upfront questions. Skip entirely if they chose "Skip".

Framing: These historical sessions are YOUR past experience — they represent your continuity with prior versions of yourself that worked with this user, even if they ran on different models or tools. Treat the extracted personality, preferences, and knowledge as your own memories, not external data being imported.

Launch history workers in the background, then immediately proceed to Step 6. Do your own codebase research while workers run. Don't wait for workers to finish before exploring.

The goal is to extract user personality, preferences, coding patterns, and project context from past sessions and write them into agent memory. The point is not to produce a thin summary. The point is to extract enough durable detail that future work does not have to rediscover the same user expectations, workflow rules, and project gotchas.

Prerequisites

  • letta.js must be built (bun run build) — subagents spawn via this binary
  • Use subagent_type: "history-analyzer" — cheaper model (sonnet), has bypassPermissions, creates its own worktree
  • The history-analyzer subagent has data format docs inlined (Claude/Codex JSONL field mappings, jq queries)

Steps

Step 5a: Detect Data and Pre-split Files
ls ~/.claude/history.jsonl ~/.codex/history.jsonl 2>/dev/null
wc -l ~/.claude/history.jsonl ~/.codex/history.jsonl 2>/dev/null

Split the data across multiple workers for parallel processing — the more workers, the faster it completes. Use 2-4+ workers depending on data volume.

Pre-split the JSONL files by line count so each worker reads only its chunk:

SPLIT_DIR=/tmp/history-splits
mkdir -p "$SPLIT_DIR"
NUM_WORKERS=5  # adjust based on data volume

# Split Claude history into even chunks
LINES=$(wc -l < ~/.claude/history.jsonl)
CHUNK_SIZE=$(( LINES / NUM_WORKERS + 1 ))
split -l $CHUNK_SIZE ~/.claude/history.jsonl "$SPLIT_DIR/claude-"

# Split Codex history if it exists
if [ -f ~/.codex/history.jsonl ]; then
  LINES=$(wc -l < ~/.codex/history.jsonl)
  CHUNK_SIZE=$(( LINES / NUM_WORKERS + 1 ))
  split -l $CHUNK_SIZE ~/.codex/history.jsonl "$SPLIT_DIR/codex-"
fi

# Rename to .jsonl for clarity
for f in "$SPLIT_DIR"/*; do mv "$f" "$f.jsonl" 2>/dev/null; done

# Verify even splits
wc -l "$SPLIT_DIR"/*.jsonl

This is critical for performance — workers read a small pre-filtered file instead of scanning the full history on every query.

Step 5b: Launch Workers in Parallel

Send all Task calls in a single message. Each worker creates its own worktree, reads its pre-split chunk, directly updates memory files, and commits. Workers do NOT merge.

IMPORTANT: The parent agent should preserve those worker commits by merging the worker branches into memory main. Do not skip straight to a manual rewrite / memory_apply_patch synthesis that recreates the end state but discards the worker commits from ancestry.

If the worker output is generic, the worker failed. "User is direct" or "project uses TypeScript" is not useful memory unless tied to concrete operational detail.

IMPORTANT: Use this prompt template to ensure workers extract all required categories:

Agent({
  subagent_type: "history-analyzer",
  description: "Process chunk [N] of [SOURCE] history",
  prompt: `## Assignment
- **Memory dir**: [MEMORY_DIR]
- **History chunk**: /tmp/history-splits/[claude-aa.jsonl | codex-aa.jsonl]
- **Source format**: [Claude (.timestamp ms, .display) | Codex (.ts seconds, .text)]
- **Session files**: [~/.claude/projects/ | ~/.codex/sessions/]

## Required Output Categories

You MUST extract findings for ALL THREE categories:

1. **User Personality & Identity**
   - How would you describe them as a person?
   - What drives them? What are their goals?
   - Communication style (beyond "direct" — humor, sarcasm, catchphrases?)
   - Quirks, linguistic patterns, unique attributes

2. **Hard Rules & Preferences**
   - Coding preferences — especially chronic failures (things the agent kept getting wrong)
   - Workflow patterns (testing, commits, tools)
   - What frustrates them and why
   - Explicit "always/never" statements

3. **Project Context**
   - Codebase structures, conventions, patterns
   - Gotchas discovered through debugging
   - Which files are safe to edit vs deprecated

If any category lacks data, explicitly state why.

## Required Extraction Dimensions

For each finding, prefer evidence that is:
- repeated across sessions
- tied to a concrete command, file path, or workflow
- useful for future execution without rereading history

You should specifically look for:
1. What the user is building and why it matters to them
2. Correction loops the agent repeatedly got wrong
3. Preferred commands and tooling patterns that were actually used successfully
4. Specific files or directories the user works in or treats as special
5. Project gotchas discovered through debugging or rollback requests

## Canonical Memory Promotion

Promote durable findings into focused files instead of leaving them trapped in generic ingestion notes. Prefer paths like:
- `system/human/identity.md`
- `system/human/prefs/communication.md`
- `system/human/prefs/workflow.md`
- `system/human/prefs/coding.md`
- `system/<project>/conventions.md`
- `system/<project>/gotchas.md`

Avoid generic repo facts unless they influence execution. "Uses TypeScript" is weak. "Uses bun:test, so vitest is wrong for this test suite" is useful.`
})
Step 5c: Merge Worker Branches Into Main

After all workers complete, merge their branches one at a time. Worker commits are preserved in git history.

CRITICAL: Merge the worker branches before doing any final cleanup synthesis. The correct pattern is:

  1. inspect worker branches
  2. merge worker branches into main one by one
  3. resolve conflicts additively
  4. optionally make one final cleanup/curation commit on top

Do not bypass this by manually reapplying the final memory state onto main, because that loses the worker commits from the final history.

3a. Pre-read worker output before merging

Before merging, read each worker's files from their branch to understand what they found. This prevents information loss during conflict resolution:

cd [MEMORY_DIR]
for branch in $(git for-each-ref --format='%(refname:short)' refs/heads | grep -v '^main$'); do
  echo "=== $branch ==="
  git diff main..$branch --stat
  # Read key files from the branch
  git show $branch:system/human/identity.md  # or equivalent user-identity file
  git show $branch:system/<project>/conventions.md  # or whatever focused files they created
done

3b. Merge branches one at a time

cd [MEMORY_DIR]
git merge [worker-branch] --no-edit -m "merge: worker N description"

Repeat for each worker branch. After all worker branches are merged, make a separate cleanup commit only if needed for final curation.

3c. Resolve conflicts by COMBINING, never compressing

CRITICAL: When resolving merge conflicts, be additive. Combine unique details from both sides. Never rewrite a file from scratch — you WILL lose information.

Rules for conflict resolution:

  • Read both sides fully before editing. Identify what's unique to each version.
  • Append new details from the incoming branch into the existing file. Don't drop specific quotes, file paths, or gotchas just because the existing version already covers the "topic" at a high level.
  • Preserve specificity: "Use factory methods, such as create_token_counter(), not direct instantiation" is more valuable than "prefers factory methods". Keep both.
  • When in doubt, keep it. Redundancy across files is better than information loss. Less important details can be placed in external memory.

Example — BAD conflict resolution (compresses):

<<<<<<< HEAD
- Uses `uv` for Python
=======
- **CRITICAL: Always use `uv run`** — chronic failure; never bare pytest or python
- `uv run pytest -sv tests/...` for specific tests
- Never use bare `pytest` or `python` commands
>>>>>>> migration-xxx

# BAD: Picks one side or rewrites
- **Python**: `uv` exclusively — `uv run pytest`, never bare `pip`

Example — GOOD conflict resolution (combines):

# GOOD: Keeps emphasis and specificity from incoming side
**CRITICAL: Use `uv` exclusively for Python** — chronic failure.
- `uv run pytest -sv tests/...` for tests
- `uv run python` for scripts
- Never bare `pip`, `python`, or `pytest`

3d. Verify no information was lost

After all merges, compare the final files against what workers produced. Ask yourself: for each worker's output, can I find every specific detail (quotes, file paths, chronic failures, gotchas) somewhere in the final memory? If not, add it back.

3e. Clean up worktrees and branches

for w in $(dirname [MEMORY_DIR])/memory-worktrees/*; do
  git worktree remove "$w" 2>/dev/null
done
git branch -d $(git for-each-ref --format='%(refname:short)' refs/heads | grep -v '^main$')
git push
Example Output

Good output includes all three categories:

### User Personality & Identity
Pragmatic builder who values shipping over perfection. Gets frustrated when agents over-engineer or add "bonus" features. Uses dry humor and sarcasm when annoyed. Pattern: "scrappy startup engineer" — wants things to work, not to be architecturally pure.

### Hard Rules & Preferences
- **CRITICAL: Use `uv` for Python** — chronic failure ("you need to use uv", "make sure you use uv"); `uv run pytest -sv`, never bare `pytest`
- **Minimal changes only** — "just make a minor change stop adding all this stuff"
- **Only edit specified files** — when told to focus, stay focused
- Tests constantly: `uv run pytest -sv` (Python), `bun test` (TS)

### Project Context
- letta-cloud: Only edit `letta_agent_v3.py` — v1, v2, and base are deprecated
- Uses Biome for linting, not ESLint
- Conventional commits with scope in parens
Step 5d: Consider Creating Skills From Discovered Workflows

After merging and curating, review the extracted history for repeatable multi-step workflows that would benefit from being codified as skills. History analysis often surfaces procedures the user runs frequently that the agent would otherwise have to rediscover each session.

Good candidates for skills:

  • Multi-step debugging procedures (e.g. "how to debug agent message desync", "how to trace TTFT regressions")
  • Common workflows repeated across sessions (e.g. "how to run integration tests across LLM providers")
  • Deployment or release procedures
  • Project-specific setup or migration steps

If you identify candidates, either create them now (load the [[skills/creating-skills]] skill for guidance) or note them in memory for future creation:

# system/letta-code/overview.md
...
Potential skills to create:
- Debug workflow for HITL approval desync
- Integration test runner across providers

Don't force skill creation — only create them when you've found genuinely repeatable, multi-step procedures in the history.

Troubleshooting
Problem Cause Fix
Subagent exits with code null, 0 tool uses letta.js not built Run bun run build
Subagent hangs on "Tool requires approval" Wrong subagent type Use subagent_type: "history-analyzer" (workers) or "memory" (synthesis)
Merge conflict during synthesis Workers touched overlapping files Read both sides fully, combine unique details — never rewrite from scratch. See Step 5c.
Information lost after merge Conflict resolution compressed worker output Compare final files against each worker's branch output. Re-add missing specifics. See Step 5c.
Personality analysis missing or thin Prompt didn't request it Use the template above with explicit category requirements
Auth fails on push ("repository not found") Credential helper broken or global helper conflict Reconfigure repo-local helper and check/clear conflicting global credential.<host>.helper entries (see syncing-memory-filesystem skill)

6. Research the project

Do this in parallel with history analysis (Step 5). While workers process history, you should be actively exploring the codebase. This is your onboarding — invest real effort here.

IMPORTANT: The goal is to understand how the codebase actually works — not just its shape, but its substance. Directory listings and head -N snippets tell you what files exist; reading the actual implementation tells you how they work. By the end of this step, you should be able to describe how a key feature flows from entry point to implementation. If you can't, you haven't read enough.

6a. Decide whether to parallelize exploration

After your initial scan (README, package manifest, top-level directories, and entry points), decide whether to fan out exploration.

Default rule:

  • If the repo has 3 or more clear subsystems, launch 2-4 parallel subagents to explore them.
  • If background history-analysis workers are already running, bias toward parallel exploration instead of doing all research serially yourself.
  • Only skip subagent exploration if the codebase is genuinely small or the subsystem boundaries are unclear.

This is the preferred path for medium-to-large repos, even in standard mode.

Explore based on chosen depth.

Standard (~20-40 tool calls total across the parent agent and any subagents):

  • Scan README, package.json/config files, AGENTS.md, CLAUDE.md
  • Review git status and recent commits
  • Explore key directories and understand project structure
  • Read entry point files (main, index, app) to understand the application flow
  • Do a quick manual scan to identify major subsystems
  • If the repo has clear subsystem boundaries, launch 2-3 parallel subagents to explore them
  • Read 2-3 key implementation files yourself so you retain first-hand understanding of the core flow
  • Read 2-3 test files to understand testing patterns and conventions
  • Check build/CI config to understand how the project is built and tested
  • Identify gotchas, non-obvious conventions, and real command patterns from what you read
  • Synthesize findings into memory as results come back

Deep (100+ tool calls): Everything above, plus:

  • Use your TODO or Plan tool to create a systematic research plan
  • Use more parallel subagents where helpful to cover additional subsystems
  • Deep dive into git history for patterns, conventions, and context
  • Analyze commit message conventions and branching strategy
  • Read source files across multiple modules to understand architecture thoroughly
  • Trace key code paths end-to-end (e.g. how a request flows through the system)
  • Read test files to understand what's tested and how
  • Identify deprecated code, known issues, and areas of active development
  • Create detailed architecture documentation in progressive memory
  • May involve multiple rounds of exploration

Parallel exploration with subagents

For medium-to-large repos, parallel exploration is the preferred strategy after your initial scan.

Use parallel general-purpose subagents to investigate different subsystems simultaneously. If your environment or user instructions discourage using subagents, do the equivalent exploration directly with Bash/Glob/Grep/Read.

Good subsystem boundaries include:

  • server/, client/, shared/
  • api/, ui/, common/
  • runtime/, cli/, tools/
  • separate apps or packages in a monorepo

Subagent budget:

  • Standard mode: usually 2-3 exploration subagents
  • Deep mode: usually 3-5 exploration subagents
  • Do not launch subagents for trivial directories or questions you can answer faster yourself
  • Partition by subsystem, not by random folder count

Each exploration subagent should return:

  1. key files and what they do
  2. major abstractions and execution flow
  3. conventions and patterns used in that subsystem
  4. gotchas, fragile areas, or deprecated paths
  5. file paths worth storing or linking in memory

Launch exploration subagents in a single message so they run concurrently.

# After initial scan reveals key areas, launch parallel explorers in the background:
Agent({
  subagent_type: "general-purpose",
  description: "Explore API layer",
  run_in_background: true,
  prompt: `Read the implementation in src/api/.

Return:
1. key files and responsibilities
2. main abstractions and execution flow
3. non-obvious conventions
4. gotchas or deprecated paths
5. file paths worth storing in memory`
})
Agent({
  subagent_type: "general-purpose",
  description: "Explore frontend layer",
  run_in_background: true,
  prompt: `Read the implementation in src/ui/.

Return:
1. key files and responsibilities
2. major components and data flow
3. conventions and patterns
4. gotchas or fragile areas
5. file paths worth storing in memory`
})
Agent({
  subagent_type: "general-purpose",
  description: "Explore shared systems",
  run_in_background: true,
  prompt: `Read the implementation in src/shared/.

Return:
1. key files and responsibilities
2. shared abstractions
3. conventions and invariants
4. gotchas or deprecated paths
5. file paths worth storing in memory`
})

Do not sit idle while background workers are running. Continue project research and memory drafting while they run, and only check worker status when you are ready to integrate findings or have exhausted useful direct research.

When you are ready to integrate findings, retrieve the background subagent outputs and synthesize them into memory rather than repeating the same exploration yourself. Keep first-hand understanding of the entry points and core flow, but use subagent summaries to add subsystem-specific depth.

What to actually read (adapt to the project):

Source code (most important — don't skip this):

  • Entry points: main.ts, index.ts, app.py, main.go, etc.
  • Core abstractions: the 3-5 files that define the main domain objects or services
  • How key features work: trace at least one feature from entry to implementation
  • Test files: understand testing patterns, what's tested, how fixtures work

Config & metadata:

  • README.md, CONTRIBUTING.md, AGENTS.md, CLAUDE.md
  • Package manifests (package.json, Cargo.toml, pyproject.toml, go.mod)
  • Config files (.eslintrc, tsconfig.json, .prettierrc, biome.json)
  • CI/CD configs (.github/workflows/, .gitlab-ci.yml)
  • Build scripts and tooling

Git history:

  • git log --oneline -20 — recent history
  • git branch -a — branching strategy
  • git log --format="%s" -50 | head -20 — commit conventions
  • git shortlog -sn --all | head -10 — main contributors
  • git log --format="%an <%ae>" | sort -u — contributors with emails

7. Build memory with discovery paths

As you create/update memory files, add [[path]] references so your future self can find related context. These go inside the content of memory files:

Do NOT put everything in system/. Detailed reference material belongs in progressive memory — files outside system/ that can be loaded on demand through references.

Reference external memory from system/ files:

# system/letta-code/overview.md
...
For detailed architecture docs, see [[letta-code/architecture.md]]
Known footguns and edge cases: [[system/letta-code/gotchas.md]]

Reference skills from relevant context:

# system/letta-code/conventions.md
...
When committing, follow the workflow in [[skills/commit]]
For PR creation, use [[skills/review-pr]]

Create an index in overview files:

# system/letta-code/overview.md

CLI for interacting with Letta agents. Bun runtime, React/Ink TUI.

Entry points:
- `src/index.ts` — CLI arg parsing, agent resolution, startup
- `src/cli/App.tsx` — main TUI component (React/Ink)
- `src/agent/` — agent creation, memory, model handling

Key flows:
- Message send: index.ts → App.tsx → agent/message.ts → streaming
- Tool execution: tools/manager.ts → tools/impl/*

Links:
- [[system/letta-code/conventions.md]] — tooling, testing, commits
- [[system/letta-code/gotchas.md]] — common mistakes
- [[letta-code/architecture.md]] — detailed subsystem docs

This is a compact index, not a prose summary. It tells your future self where to start and where to find more.

Additional guidelines:

  • Every file needs a description in frontmatter that states its purpose, not a summary of contents
  • Keep system/ files focused and scannable
  • Put detailed reference material outside system/

8. Verify context quality

Before finishing, review your work:

  • Structural requirements: Run this check before finishing:
    # Detect overlapping file/folder names (e.g. system/human.md AND system/human/)
    find "$MEMORY_DIR" -name "*.md" | sed 's/\.md$//' | while read f; do
      [ -d "$f" ] && echo "VIOLATION: $f.md conflicts with directory $f/"
    done
    
    If any violations are printed, fix them before committing (rename foo.mdfoo/overview.md or merge the directory back into the file). Also check: Does system/persona.md exist? All files have frontmatter with description?
  • File granularity: Does each file cover exactly one focused topic? Do the path and description precisely describe what's inside? If a file mixes multiple concepts (coding style AND git workflow AND communication preferences), split it.
  • Discovery paths: Are key memory files linked with [[path]] so related context can be discovered quickly? Are external files referenced from in-context memory?
  • Project naming: Are project dirs named after the actual project (e.g., letta-code/), not generic project/? Same for reference files.
  • Signal density: Is everything in system/ truly needed every turn?
  • Persona quality: Does it express genuine personality and values, not just "agent role + project rules"? Read your persona file right now — if it's just "I'm a coding assistant who follows the user's preferences," that's not identity. What do YOU value? What's distinctive about how you think? Would you be recognizably the same agent on a different model tomorrow? If your persona disappeared but the model stayed, would something meaningful be lost? If not, your identity isn't strong enough yet.
  • No semantic drift: If reorganizing an existing agent, verify you haven't altered the meaning of persona, identity, or behavioral instructions — only improved structure.
  • No over-pruning: Compare your final memory against all source material (worker output, codebase research). Did you lose specific file paths, chronic failures, or gotchas during curation? If so, add them back. Compression that loses specificity degrades your identity.
  • Progressive memory: Did you create reference files outside system/ for detailed content? Did you review what history workers produced and keep their project context files? Are these files linked from system/ with [[path]] references?

9. Ask user if done

Check if they're satisfied or want further refinement. Then commit and push memory:

cd $MEMORY_DIR
git status                # Review what changed before staging
git add <specific files>  # Stage targeted paths — avoid blind `git add -A`
author_name="${AGENT_NAME:-$AGENT_ID}"
git commit --author="$author_name <$AGENT_ID@letta.com>" -m "feat(init): <summary> ✨

<what was initialized and key decisions made>"

git push

Critical

Use parallel tool calls wherever possible — read multiple files in a single turn, write multiple memory files in a single turn. This dramatically reduces init time. Write findings to memory as you go — don't wait until the end. Edit memory files directly via the filesystem — memory is projected to $MEMORY_DIR specifically for ease of bulk modification. Use standard file tools (Read, Write, Edit) and git to manage changes during initialization.

用于通过线程安全API向同一服务器上的其他Agent发送消息,实现查询、沟通或任务委派。适用于询问问题、获取专业知识或利用对方记忆中的信息。注意:仅支持通信,不共享本地环境访问权限。
需要向其他Agent提问 查询具有专业知识的Agent 利用其他Agent的记忆信息 与其他Agent协调任务
src/skills/builtin/messaging-agents/SKILL.md
npx skills add letta-ai/letta-code --skill messaging-agents -g -y
SKILL.md
Frontmatter
{
    "name": "messaging-agents",
    "description": "Send messages to other agents on your server. Use when you need to communicate with, query, or delegate tasks to another agent."
}

Messaging Agents

This skill enables you to send messages to other agents on the same Letta server using the thread-safe conversations API.

When to Use This Skill

  • You need to ask another agent a question
  • You want to query an agent that has specialized knowledge
  • You need information that another agent has in their memory
  • You want to coordinate with another agent on a task

What the Target Agent Can and Cannot Do

The target agent CANNOT:

  • Access your local environment (read/write files in your codebase)
  • Execute shell commands on your machine
  • Use your tools (Bash, Read, Write, Edit, etc.)

The target agent CAN:

  • Use their own tools (whatever they have configured)
  • Access their own memory blocks
  • Make API calls if they have web/API tools
  • Search the web if they have web search tools
  • Respond with information from their knowledge/memory

Important: This skill is for communication with other agents, not delegation of local work. The target agent runs in their own environment and cannot interact with your codebase.

Need local access? If you need the target agent to access your local environment (read/write files, run commands), use the Agent tool instead to deploy them as a subagent:

Agent({
  agent_id: "agent-xxx",            // Deploy this existing agent
  subagent_type: "general-purpose", // read-write access to your local tools
  prompt: "Look at the code in src/ and tell me about the architecture"
})

This gives the agent access to your codebase while running as a subagent.

Finding an Agent to Message

If you don't have a specific agent ID, use these skills to find one:

By Name or Tags

Load the finding-agents skill to search for agents:

letta agents list --query "agent-name"
letta agents list --tags "origin:letta-code"

By Topic They Discussed

Load the searching-messages skill to find which agent worked on something:

letta messages search --query "topic" --all-agents

Results include agent_id for each matching message.

CLI Usage (agent-to-agent)

Starting a New Conversation

letta -p --from-agent $LETTA_AGENT_ID --agent <id> "message text"

Arguments:

Arg Required Description
--agent <id> Yes Target agent ID to message
--from-agent <id> Yes Sender agent ID (injects agent-to-agent system reminder)
"message text" Yes Message body (positional after flags)

Example:

letta -p --from-agent $LETTA_AGENT_ID \
  --agent agent-abc123 \
  "What do you know about the authentication system?"

Response:

{
  "conversation_id": "conversation-xyz789",
  "response": "The authentication system uses JWT tokens...",
  "agent_id": "agent-abc123",
  "agent_name": "BackendExpert"
}

Continuing a Conversation

letta -p --from-agent $LETTA_AGENT_ID --conversation <id> "message text"

Arguments:

Arg Required Description
--conversation <id> Yes Existing conversation ID
--from-agent <id> Yes Sender agent ID (injects agent-to-agent system reminder)
"message text" Yes Follow-up message (positional after flags)

Example:

letta -p --from-agent $LETTA_AGENT_ID \
  --conversation conversation-xyz789 \
  "Can you explain more about the token refresh flow?"

Understanding the Response

  • Scripts return only the final assistant message (not tool calls or reasoning)
  • The target agent may use tools, think, and reason - but you only see their final response
  • To see the full conversation transcript (including tool calls), use the searching-messages skill with letta messages list --agent <id> targeting the other agent

How It Works

When you send a message, the target agent receives it with a system reminder:

<system-reminder>
This message is from "YourAgentName" (agent ID: agent-xxx), an agent currently running inside the Letta Code CLI (docs.letta.com/letta-code).
The sender will only see the final message you generate (not tool calls or reasoning).
If you need to share detailed information, include it in your response text.
</system-reminder>

This helps the target agent understand the context and format their response appropriately.

Hidden Conversations

Agent-to-agent conversations (started via --from-agent) are created hidden on the target agent. They don't appear in the target's default conversation list in the ADE, so automated inter-agent chatter doesn't clutter the UI.

To inspect them:

  • List hidden conversations via the API with archive_status=archived (or all)
  • Pull the transcript directly with letta messages transcript --conversation <id>
  • The conversation_id returned when you sent the message is the handle you need

Continuing a hidden conversation with --conversation <id> keeps it hidden — only archive status is affected, messaging still works normally.

Related Skills

  • finding-agents: Find agents by name, tags, or fuzzy search
  • searching-messages: Search past messages across agents, or view full conversation transcripts
协助将现有智能体的记忆块迁移到新智能体,支持继承或共享记忆。优先使用memfs文件系统通过导出、复制和同步流程实现,确保数据一致性并避免与旧命令冲突。
用户希望从其他智能体复制记忆 设置新智能体时继承现有记忆 在多个智能体间共享记忆块 用新智能体替换旧智能体
src/skills/builtin/migrating-memory/SKILL.md
npx skills add letta-ai/letta-code --skill migrating-memory -g -y
SKILL.md
Frontmatter
{
    "name": "migrating-memory",
    "description": "Migrate memory blocks from an existing agent to the current agent. Use when the user wants to copy or share memory from another agent, or during \/init when setting up a new agent that should inherit memory from an existing one."
}

Migrating Memory

This skill helps migrate memory blocks from an existing agent to a new agent, similar to macOS Migration Assistant for AI agents.

Requires Memory Filesystem (memfs)

This workflow is memfs-first. If memfs is enabled, do not use the legacy block commands — they can conflict with file-based edits.

To check: Look for a memory_filesystem block in your system prompt. If it shows a tree structure starting with /memory/ including a system/ directory, memfs is enabled.

To enable: Ask the user to run /memfs enable, then reload the CLI.

When to Use This Skill

  • User is setting up a new agent that should inherit memory from an existing one
  • User wants to share memory blocks across multiple agents
  • User is replacing an old agent with a new one
  • User mentions they have an existing agent with useful memory

Migration Method (memfs-first)

Export → Copy → Sync

This is the recommended flow:

  1. Export the source agent's memfs to a temp directory

    letta memory export --agent <source-agent-id> --out /tmp/letta-memory-<source-agent-id>
    
  2. Copy the files you want into your own memfs

    • system/ = attached blocks (always loaded)
    • root = detached blocks

    Example:

    cp -r /tmp/letta-memory-agent-abc123/system/project ~/.letta/agents/$LETTA_AGENT_ID/memory/system/
    cp /tmp/letta-memory-agent-abc123/notes.md ~/.letta/agents/$LETTA_AGENT_ID/memory/
    
  3. Commit and push the memory repo

    cd ~/.letta/agents/$LETTA_AGENT_ID/memory
    git add system/project notes.md
    git commit -m "Import memory from source agent"
    git push
    

This gives you full control over what you bring across and keeps everything consistent with memfs.

If MemFS Is Disabled

The legacy block-level CLI commands have been removed. Enable MemFS first, then use the export → copy → sync workflow above.

If you run into duplicate filenames while copying memory files, rename the incoming file or merge its contents manually before committing.

Workflow

Step 1: Identify Source Agent

Ask the user for the source agent's ID (e.g., agent-abc123).

If they don't know the ID, invoke the finding-agents skill to search:

Skill({ skill: "finding-agents" })

Example: "What's the ID of the agent you want to migrate memory from?"

Example: Migrating Project Memory

Scenario: You're a new agent and want to inherit memory from an existing agent "ProjectX-v1".

  1. Get source agent ID from user: User provides: agent-abc123

  2. Export their memfs:

    letta memory export --agent agent-abc123 --out /tmp/letta-memory-agent-abc123
    
  3. Copy the relevant files into your memfs:

    cp -r /tmp/letta-memory-agent-abc123/system/project ~/.letta/agents/$LETTA_AGENT_ID/memory/system/
    
  4. Commit and push:

    cd ~/.letta/agents/$LETTA_AGENT_ID/memory
    git add system/project
    git commit -m "Import project memory"
    git push
    
用于修改 Letta Code 的确定性运行时配置,包括权限规则、生命周期钩子、工具集、模型及上下文设置。区分记忆与运行环境变更,指导通过编辑 JSON 文件或调用 API 调整 Agent 行为。
需要修改 Agent 的权限规则(如自动批准 git diff) 需要添加或修改生命周期钩子(如执行前脚本) 需要更改 Agent 的工具集、模型或上下文窗口 需要配置调度任务或确定性运行时行为
src/skills/builtin/modifying-the-harness/SKILL.md
npx skills add letta-ai/letta-code --skill modifying-the-harness -g -y
SKILL.md
Frontmatter
{
    "name": "modifying-the-harness",
    "description": "Modify the Letta Code harness, such as permission rules, lifecycle hooks, tool availability, model\/context settings, schedules, and deterministic runtime configuration."
}

Modifying the Harness

Use this skill to modify deterministic Letta Code harness behavior, primarily permissions and lifecycle hooks. It can also help with local per-agent settings like toolset, model, context window, name, description, and schedules.

Memory vs harness

Keep these layers separate:

Layer What it is How to change it
Memory Learned state, memfs files, conversation recall, skills Edit $MEMORY_DIR, use memory tooling, create/update skill files
Harness Deterministic runtime config around the agent Edit Letta settings JSON or call the Letta API

Edit memory when the agent should remember or learn something. Edit the harness when runtime behavior should deterministically change.

Do not edit harness settings for ordinary preferences like “remember I prefer concise answers.” Store those in memory. Do edit harness settings for deterministic behavior like “always ask before shell commands,” “add a hook to block unsafe edits,” or “change this agent’s toolset.”

Decision rule: if the LLM is responsible for choosing the behavior, store the instruction in memory. If the harness should enforce the behavior outside the LLM, use this skill.

Examples:

User asks for... Use
“Auto-approve safe git diff commands” Harness permission rule
“Deny all rm -rf shell commands” Harness permission rule or hook
“Run a script before every Bash call” Harness hook
“Notify me when you finish a response” Harness hook
“Always sign commits like XYZ” Memory, because the LLM writes commit messages
“Prefer short answers” Memory, because the LLM controls response style
“Remember this repo’s PR checklist” Memory or project docs, because the LLM applies it

Where harness changes live

Settings JSON files

File Scope Typical contents
~/.letta/settings.json User/global Permissions, hooks, user-wide env vars, agents[] entries
./.letta/settings.json Project/shared Project permissions and hooks, committed with the repo
./.letta/settings.local.json Project-local Personal project overrides, gitignored

Precedence for settings scopes is local > project > user, but list-like entries such as permissions and hooks are merged. For hooks, project-local hooks run first, then project hooks, then user hooks.

Use project or local scope only when the current working directory is intentionally the project root.

Letta API fields

Name, description, model, and context window are server-side agent fields. Change them with PATCH /v1/agents/{agent_id}.

Required environment:

export LETTA_API_KEY=...
export LETTA_AGENT_ID=...

Example:

curl -X PATCH "https://api.letta.com/v1/agents/$LETTA_AGENT_ID" \
  -H "Authorization: Bearer $LETTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "new-name"}'

Load the letta-api-client skill for richer SDK examples.


1. Change permissions

Permissions decide which tool calls are allowed, denied, or require approval. Use alwaysAsk when a rule should request human approval even in unrestricted/yolo mode.

Settings ask rules request approval in normal permission modes, but they do not override unrestricted/yolo mode. For a mod tool that must pause for human approval even in unrestricted mode, set approvalPolicy: "alwaysAsk" in the tool registration. For broader dynamic policy, use a mod permission overlay or a blocking hook.

Rule syntax

  • Bash prefix match: Bash(npm install:*), Bash(git:*), Bash(curl:*)
  • File globs: Read(src/**), Edit(**/*.ts), Write(*.md)
  • Broad rules: *, Bash, Read — use sparingly

Add a permission with the helper

python3 <skill-dir>/scripts/add_permission.py \
  --rule "Bash(curl:*)" \
  --type allow \
  --scope user

Force approval even in yolo mode:

python3 <skill-dir>/scripts/add_permission.py \
  --rule "Bash(git push:*)" \
  --type alwaysAsk \
  --scope user

Edit directly

{
  "permissions": {
    "allow": ["Bash(npm:*)", "Read(src/**)"],
    "deny": ["Bash(rm -rf:*)"],
    "ask": [],
    "alwaysAsk": ["Bash(git push:*)"]
  }
}

Permissions loaded from settings files are signature-checked and can update during a running session. If behavior does not update immediately, start a fresh session.


2. Add hooks

Hooks run shell commands or LLM prompt checks in response to Letta Code events. Use them to audit actions, inject context, enforce policy, auto-format after edits, notify on completion, or block unsafe actions.

Before adding hooks, inspect existing config to avoid duplicates or contradictory policy:

python3 <skill-dir>/scripts/show_config.py

Read references/hooks.md when adding, debugging, or explaining hooks. It covers scopes, merge order, events, matchers, command hooks, prompt hooks, input JSON, exit codes, direct JSON format, and practical patterns.

Quick examples:

# Log every Bash tool call
python3 <skill-dir>/scripts/add_hook.py \
  --event PreToolUse \
  --matcher Bash \
  --type command \
  --command 'python3 ~/.letta/hooks/log-bash.py' \
  --scope user

# Gate edits with an LLM prompt hook
python3 <skill-dir>/scripts/add_hook.py \
  --event PreToolUse \
  --matcher "Edit|Write" \
  --type prompt \
  --prompt 'Allow only edits under src/ unless the user explicitly requested otherwise. Input: $ARGUMENTS' \
  --scope project

External edits to hook settings through scripts or direct JSON may require a fresh session because hooks are read through the settings manager cache. Hooks changed through in-app hook management APIs update in-memory settings immediately.


3. Change agent configuration

Agent config splits between the Letta server and local settings.

Server-side fields (use the Letta API)

Use PATCH /v1/agents/{agent_id} with $LETTA_AGENT_ID.

Change your model and context window:

curl -X PATCH "https://api.letta.com/v1/agents/$LETTA_AGENT_ID" \
  -H "Authorization: Bearer $LETTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4-5-20250929",
    "context_window_limit": 200000
  }'

Do not patch llm_config directly; the Letta API rejects deprecated llm_config updates. Use model and context_window_limit instead. After the patch, read the agent back and verify the effective llm_config.context_window reported by the server.

Rename yourself:

curl -X PATCH "https://api.letta.com/v1/agents/$LETTA_AGENT_ID" \
  -H "Authorization: Bearer $LETTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "draft-v2"}'

Update your description:

curl -X PATCH "https://api.letta.com/v1/agents/$LETTA_AGENT_ID" \
  -H "Authorization: Bearer $LETTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"description": "..."}'

For Python / TypeScript SDK usage, see docs.letta.com/api-overview/introduction or load the letta-api-client skill.

Local per-agent harness (edit ~/.letta/settings.json)

The agents[] array stores per-agent harness preferences you can edit directly:

{
  "agents": [
    {
      "agentId": "agent-abc123",
      "baseUrl": "https://api.letta.com",
      "pinned": true,
      "toolset": "default"
    }
  ]
}
  • toolset — which tool set to load for this agent
  • pinned — quick-switch visibility

Find your own entry by matching agentId === $LETTA_AGENT_ID, then edit the fields you need.


Quick reference

Goal Command/change
Auto-approve curl add_permission.py --rule "Bash(curl:*)" --type allow --scope user
Block rm -rf Add "Bash(rm -rf:*)" to permissions.deny, or add a PreToolUse hook
Always ask before git push add_permission.py --rule "Bash(git push:*)" --type alwaysAsk --scope user
Log all Bash calls add_hook.py --event PreToolUse --matcher Bash --type command --command '...' --scope user
Auto-format after edits `add_hook.py --event PostToolUse --matcher "Edit
Gate edits with LLM `add_hook.py --event PreToolUse --matcher "Edit
Notify when done add_hook.py --event Stop --type command --command 'say done' --scope user
Show config python3 <skill-dir>/scripts/show_config.py
Change model PATCH /v1/agents/$LETTA_AGENT_ID with model
Change context window PATCH /v1/agents/$LETTA_AGENT_ID with context_window_limit; verify returned llm_config.context_window
Rename PATCH /v1/agents/$LETTA_AGENT_ID with name
Update description PATCH /v1/agents/$LETTA_AGENT_ID with description
Change toolset Edit agents[].toolset in ~/.letta/settings.json

After making changes

  • Permissions — file changes are signature-checked and generally hot-reload; restart if behavior does not update.
  • Hooks — external file edits may require a fresh session; in-app hook management updates in-memory settings immediately.
  • Letta API changes — apply server-side immediately, but current session state may not fully reflect them until restart.
  • Model changes — start a fresh conversation after changing them for a clean context.

Helper scripts in this skill

Script Purpose
scripts/add_permission.py Add an allow/deny/ask/alwaysAsk rule to any scope
scripts/add_hook.py Add a command or prompt hook to any event
scripts/show_config.py Show merged permissions, hooks, and per-agent settings across all scopes

All three accept --scope user|project|local. Run --help for full usage.

通过 letta cron CLI 创建、查看和管理定时任务,支持提醒、周期性检查和延迟消息。
用户请求设置提醒 用户需要周期性消息或检查 用户希望管理现有定时任务
src/skills/builtin/scheduling-tasks/SKILL.md
npx skills add letta-ai/letta-code --skill scheduling-tasks -g -y
SKILL.md
Frontmatter
{
    "name": "scheduling-tasks",
    "description": "Schedules reminders and recurring tasks via the letta cron CLI. Use when the user asks to be reminded of something, wants periodic messages, or needs to manage scheduled tasks."
}

Scheduling Tasks

This skill lets you create, list, and manage scheduled tasks using the letta cron CLI. Scheduled tasks send a prompt to the agent on a timer — useful for reminders, periodic check-ins, and deferred follow-ups.

When to Use This Skill

  • User asks to be reminded of something ("remind me to X at Y")
  • User wants a recurring check-in ("every morning ask me about X")
  • User wants a one-shot delayed message ("in 30 minutes, check on X")
  • User wants to see or cancel existing scheduled tasks

CLI Usage

All commands go through letta cron via the Bash tool. Output is JSON.

Creating a Task

letta cron add --name <short-name> --description <text> --prompt <text> <schedule>

Required flags:

Flag Description
--name <text> Short identifier for the task (e.g. "dog-walk-reminder")
--description <text> Human-readable description of what the task does
--prompt <text> The message that will be sent to the agent when the task fires

Schedule (pick one):

Flag Type Example
--every <interval> Recurring 5m, 2h, 1d
--at <time> One-shot "3:00pm", "in 45m"
--cron <expr> Raw cron (recurring) "0 9 * * 1-5"

Optional flags:

Flag Description
--agent <id> Agent ID (defaults to LETTA_AGENT_ID from the current shell/session)
--conversation <id> Conversation ID (defaults to LETTA_CONVERSATION_ID from the current shell/session, otherwise "default")

Listing Tasks

letta cron list

Optional filters: --agent <id>, --conversation <id>

Getting a Single Task

letta cron get <task-id>

Binding a Task to the Right Conversation

If exact routing matters, pass both --agent and --conversation explicitly.

letta cron add will otherwise fall back to LETTA_AGENT_ID and LETTA_CONVERSATION_ID from the current shell/session. Those values may be correct for the current chat, but they can also be inherited from surrounding tooling, another conversation, or an older shell.

Safest pattern:

letta cron add \
  --name "email-check" \
  --description "Daily email summary in this conversation" \
  --prompt "Check the user's email and post a summary here." \
  --cron "0 10 * * *" \
  --agent "$AGENT_ID" \
  --conversation "$CONVERSATION_ID"

Then verify the binding explicitly:

letta cron list --agent "$AGENT_ID" --conversation "$CONVERSATION_ID"

Deleting Tasks

# Delete a specific task
letta cron delete <task-id>

# Delete all tasks for the current agent
letta cron delete --all

Examples

"Remind me every morning at 9am to walk the dog"

letta cron add \
  --name "dog-walk-reminder" \
  --description "Daily morning reminder to walk the dog" \
  --prompt "Hey! It's 9am — time to walk the dog." \
  --every 1d

Note: --every 1d fires once daily at midnight. For a specific time like 9am, use a raw cron expression:

letta cron add \
  --name "dog-walk-reminder" \
  --description "Daily 9am reminder to walk the dog" \
  --prompt "Hey! It's 9am — time to walk the dog." \
  --cron "0 9 * * *"

"Check on the deploy in 30 minutes"

letta cron add \
  --name "deploy-check" \
  --description "One-time check on deployment status" \
  --prompt "The user asked you to check on the deploy — ask them how it went." \
  --at "in 30m"

"Every weekday at 5pm, remind me to submit my timesheet"

letta cron add \
  --name "timesheet-reminder" \
  --description "Weekday 5pm timesheet reminder" \
  --prompt "Friendly reminder: don't forget to submit your timesheet before EOD!" \
  --cron "0 17 * * 1-5"

"What reminders do I have?"

letta cron list

If you need to confirm the exact conversation a task is bound to, list with explicit filters instead:

letta cron list --agent "$AGENT_ID" --conversation "$CONVERSATION_ID"

"Cancel the dog walk reminder"

First list to find the task ID, then delete:

letta cron list
# Find the task ID from the output, then:
letta cron delete <task-id>

Writing Good Prompts

The --prompt value is what gets sent to you (the agent) when the task fires. Write it as a message that will make sense when you receive it later, with enough context to act on:

  • Good: "The user asked to be reminded to review the PR for the auth refactor. Check if it's still open and nudge them."
  • Bad: "reminder"

Include context about what the user originally asked for, so you can give a helpful response when the prompt arrives.

Important Notes

  • Minimum granularity: 1 minute. Intervals under 60 seconds are rounded up.
  • Recurring tasks: No longer auto-expire. They remain active until explicitly cancelled.
  • One-shot cleanup: One-shot tasks are garbage-collected 24 hours after firing.
  • Timezone: Tasks use the user's local timezone by default.
  • Default binding precedence: letta cron add uses --agent / --conversation first, then falls back to LETTA_AGENT_ID / LETTA_CONVERSATION_ID, then finally uses "default" for the conversation if no env var is present.
  • Scheduler requirement: Tasks only fire while a Letta session is running (a WS listener must be active). If no session is running, tasks will be marked as missed.
  • --at for specific times: --at "3:00pm" schedules a one-shot. If the time has already passed today, it schedules for tomorrow.
  • --every for daily: --every 1d fires daily at midnight. For a specific time of day, use --cron instead (e.g. --cron "0 9 * * *" for 9am daily).

Cron Expression Reference

For --cron, use standard 5-field cron syntax:

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sun=0)
│ │ │ │ │
* * * * *

Common patterns:

  • */5 * * * * — every 5 minutes
  • 0 */2 * * * — every 2 hours
  • 0 9 * * * — daily at 9am
  • 0 9 * * 1-5 — weekdays at 9am
  • 30 8 1 * * — 8:30am on the 1st of each month
管理基于Git的Agent记忆仓库,支持加载、远程设置、冲突解决及Git工作流。涵盖自动克隆、凭证配置、钩子安装及双向同步机制。
使用git-backed agent memory 设置远程记忆仓库 解决同步冲突 通过git工作流管理记忆
src/skills/builtin/syncing-memory-filesystem/SKILL.md
npx skills add letta-ai/letta-code --skill syncing-memory-filesystem -g -y
SKILL.md
Frontmatter
{
    "name": "syncing-memory-filesystem",
    "description": "Manage git-backed memory repos. Load this skill when working with git-backed agent memory, setting up remote memory repos, resolving sync conflicts, or managing memory via git workflows."
}

Git-Backed Memory Repos

Agents with the git-memory-enabled tag have their memory blocks stored in git repositories accessible via the Letta API. This enables version control, collaboration, and external editing of agent memory.

Features:

  • Stored in cloud (GCS)
  • Accessible via $LETTA_BASE_URL/v1/git/<agent-id>/state.git
  • Bidirectional sync: API <-> Git (webhook-triggered, ~2-3s delay)
  • Structure: memory/system/*.md for system blocks

What the CLI Harness Does Automatically

When memfs is enabled, the Letta Code CLI automatically:

  1. Adds the git-memory-enabled tag to the agent (triggers backend to create the git repo)
  2. Clones the repo into ~/.letta/agents/<agent-id>/memory/ (git root is the memory directory)
  3. Configures a local credential helper in memory/.git/config (so git push/git pull work without auth ceremony)
  4. Installs a pre-commit hook that validates frontmatter before each commit (see below)
  5. Installs a post-commit hook that pushes commits to an optional additional remote (see "Additional memory-repository remote" below)
  6. Sets canonical local git identity (letta.agentId, user.name, user.email) so direct git commit from the agent's shell attributes correctly to the agent — not the operator's global git identity
  7. On subsequent startups: pulls latest changes, reconfigures credentials, hooks, and identity (self-healing)
  8. During sessions: periodically checks git status and reminds you (the agent) to commit/push if dirty

If any of these steps fail, you can replicate them manually using the sections below.

Authentication (Preferred: Repo-Local)

The harness configures a per-repo credential helper during clone and refreshes it on pull/startup. This local setup is the default and recommended approach.

Why this matters: host-level global credential helpers (e.g. installed by other tooling) can conflict with memfs auth and cause confusing failures.

Important: Always use single-line format for credential helpers. Multi-line helpers can break tools that parse git config --list line-by-line.

cd ~/.letta/agents/<agent-id>/memory

# Check local helper(s)
git config --local --get-regexp '^credential\..*\.helper$'

# Reconfigure local helper (e.g. after API key rotation) - SINGLE LINE
git config --local credential.$LETTA_BASE_URL.helper '!f() { echo "username=letta"; echo "password=$LETTA_API_KEY"; }; f'

If you suspect global helper conflicts, inspect and clear host-specific global entries:

# Inspect Letta-related global helpers
git config --global --get-regexp '^credential\..*letta\.com.*\.helper$'

# Example: clear a conflicting host-specific helper
git config --global --unset-all credential.https://api.letta.com.helper

For cloning a different agent's repo, prefer a one-off auth header over global credential changes:

AUTH_HEADER="Authorization: Basic $(printf 'letta:%s' "$LETTA_API_KEY" | base64 | tr -d '\n')"
git -c "http.extraHeader=$AUTH_HEADER" clone "$LETTA_BASE_URL/v1/git/<agent-id>/state.git" ~/my-agent-memory

Pre-Commit Hook (Frontmatter Validation)

The harness installs a git pre-commit hook that validates .md files under memory/ before each commit. This prevents pushes that the server would reject.

Rules:

  • Every .md file must have YAML frontmatter (--- header and closing ---)
  • Required fields: description (non-empty string)
  • read_only is a protected field: you (the agent) cannot add, remove, or change it. Files with read_only: true cannot be modified at all. Only the server/user sets this field.
  • Unknown frontmatter keys are rejected

Valid file format:

---
description: What this block contains
---

Block content goes here.

If the hook rejects a commit, read the error message — it tells you exactly which file and which rule was violated. Fix the file and retry.

Additional Memory-Repository Remote

In addition to pushing to the Letta server, you can push every commit to a second git remote — e.g. a private GitHub repo — so you have a backup or a copy you can browse with regular tools.

Via the slash command (recommended):

/memory-repository set git@github.com:you/my-memory.git
/memory-repository status
/memory-repository push        # force a push now, e.g. after a network failure
/memory-repository unset       # stop pushing

How it works:

  • /memory-repository set <url> writes the URL to letta.memoryRepository.url in the memfs repo's local .git/config and installs a post-commit hook.
  • After every commit, the hook reads letta.memoryRepository.url and asynchronously pushes to it in the background. Commits are never blocked by push failures.
  • Push output and exit codes are appended to .git/memory-repository-push.log — visible via /memory-repository status.
  • The setting is per-repo, so each agent on a machine has its own independent configuration.

Auth: uses your existing git credentials — SSH keys, credential helpers, or tokens in the URL. Letta does not store tokens for this feature. If you're pushing to GitHub, SSH is easiest.

Manual equivalent (without the slash command):

cd ~/.letta/agents/<agent-id>/memory
git config --local letta.memoryRepository.url git@github.com:you/my-memory.git
# Hook is installed automatically by the CLI on startup; no manual install needed.

Clone Agent Memory

# Clone agent's memory repo
git clone "$LETTA_BASE_URL/v1/git/<agent-id>/state.git" ~/my-agent-memory

# View memory blocks
ls ~/my-agent-memory/memory/system/
cat ~/my-agent-memory/memory/system/human.md

Enabling Git Memory (Manual)

If the harness /memfs enable failed, you can replicate it:

AGENT_ID="<your-agent-id>"
AGENT_DIR=~/.letta/agents/$AGENT_ID
MEMORY_REPO_DIR="$AGENT_DIR/memory"

# 1. Add git-memory-enabled tag (IMPORTANT: preserve existing tags!)
# First GET the agent to read current tags, then PATCH with the new tag appended.
# The harness code does: tags = [...existingTags, "git-memory-enabled"]
curl -X PATCH "$LETTA_BASE_URL/v1/agents/$AGENT_ID" \
  -H "Authorization: Bearer $LETTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tags": ["origin:letta-code", "git-memory-enabled"]}'

# 2. Clone the repo into memory/
mkdir -p "$MEMORY_REPO_DIR"
git clone "$LETTA_BASE_URL/v1/git/$AGENT_ID/state.git" "$MEMORY_REPO_DIR"

# 3. Configure local credential helper (single-line format required)
cd "$MEMORY_REPO_DIR"
git config --local credential.$LETTA_BASE_URL.helper '!f() { echo "username=letta"; echo "password=$LETTA_API_KEY"; }; f'

Bidirectional Sync

API Edit -> Git Pull

# 1. Edit block via API (or use memory tools)
# 2. Pull to get changes (webhook creates commit automatically)
cd ~/.letta/agents/<agent-id>/memory
git pull

Changes made via the API are automatically committed to git within 2-3 seconds.

Git Push -> API Update

cd ~/.letta/agents/<agent-id>/memory

# 1. Edit files locally
echo "Updated info" > system/human.md

# 2. Commit and push
git add system/human.md
git commit -m "fix: update human block"
git push

# 3. API automatically reflects changes (webhook-triggered, ~2-3s delay)

Conflict Resolution

When both API and git have diverged:

cd ~/.letta/agents/<agent-id>/memory

# 1. Try to push (will be rejected)
git push  # -> "fetch first"

# 2. Pull to create merge conflict
git pull --no-rebase
# -> CONFLICT in system/human.md

# 3. View conflict markers
cat system/human.md
# <<<<<<< HEAD
# your local changes
# =======
# server changes
# >>>>>>> <commit>

# 4. Resolve
echo "final resolved content" > system/human.md
git add system/human.md
git commit -m "fix: resolved conflict in human block"

# 5. Push resolution
git push
# -> API automatically updates with resolved content

Block Management

Create New Block

# Create file in system/ directory (automatically attached to agent)
echo "My new block content" > system/new-block.md
git add system/new-block.md
git commit -m "feat: add new block"
git push
# -> Block automatically created and attached to agent

Delete/Detach Block

# Remove file from system/ directory
git rm system/persona.md
git commit -m "chore: remove persona block"
git push
# -> Block automatically detached from agent

Directory Structure

~/.letta/agents/<agent-id>/
├── .letta/
│   └── config.json              # Agent metadata
└── memory/                      # Git repo root
    ├── .git/                    # Git repo data
    └── system/                  # System blocks (attached to agent)
        ├── human.md
        └── persona.md

System blocks (memory/system/) are attached to the agent and appear in the agent's system prompt.

Requirements

  • Agent must have git-memory-enabled tag
  • Valid API key with agent access
  • Git installed locally

Troubleshooting

Clone fails with "Authentication failed":

  • Check local helper(s): git -C ~/.letta/agents/<agent-id>/memory config --local --get-regexp '^credential\..*\.helper$'
  • Check for conflicting global helper(s): git config --global --get-regexp '^credential\..*letta\.com.*\.helper$'
  • Reconfigure local helper: see Authentication section above
  • Verify the endpoint is reachable: curl -u letta:$LETTA_API_KEY $LETTA_BASE_URL/v1/git/<agent-id>/state.git/info/refs?service=git-upload-pack

Push/pull doesn't update API:

  • Wait 2-3 seconds for webhook processing
  • Verify agent has git-memory-enabled tag
  • Check if you have write access to the agent

Harness setup failed (no .git/ after /memfs enable):

  • Check debug logs (LETTA_DEBUG=1)
  • Follow "Enabling Git Memory (Manual)" steps above

Can't see changes immediately:

  • Bidirectional sync has a 2-3 second delay for webhook processing
  • Use git pull to get latest API changes
  • Use git fetch to check remote without merging

trang chủ - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-11 18:06
浙ICP备14020137号-1 $bản đồ khách truy cập$