@letta-ai/letta-code 0.27.4 → 0.27.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/letta.js +22101 -21301
- package/package.json +2 -2
- package/skills/acquiring-skills/SKILL.md +197 -40
- package/skills/creating-extensions/SKILL.md +36 -13
- package/skills/creating-extensions/references/architecture.md +12 -0
- package/skills/creating-extensions/references/commands.md +10 -1
- package/skills/creating-extensions/references/events.md +12 -16
- package/skills/creating-extensions/references/permissions.md +90 -0
- package/skills/creating-extensions/references/plan-mode.md +285 -0
- package/skills/creating-extensions/references/providers.md +110 -0
- package/skills/creating-extensions/references/tools.md +7 -0
- package/skills/customizing-commands/SKILL.md +2 -2
- package/skills/creating-extensions/references/btw-command.md +0 -106
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letta-ai/letta-code",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.6",
|
|
4
4
|
"description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "bun@1.3.0",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@letta-ai/letta-client": "^1.10.2",
|
|
39
|
-
"@earendil-works/pi-ai": "^0.
|
|
39
|
+
"@earendil-works/pi-ai": "^0.78.1",
|
|
40
40
|
"@pierre/diffs": "1.2.2",
|
|
41
41
|
"glob": "^13.0.0",
|
|
42
42
|
"ink-link": "^5.0.0",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: acquiring-skills
|
|
3
|
-
description:
|
|
3
|
+
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.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Acquiring New Skills
|
|
7
7
|
|
|
8
|
-
This skill teaches you how to safely discover and install skills from external sources.
|
|
8
|
+
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.
|
|
9
9
|
|
|
10
10
|
## SAFETY - READ THIS FIRST
|
|
11
11
|
|
|
@@ -16,19 +16,33 @@ Skills can contain:
|
|
|
16
16
|
### Trusted Sources (no user approval needed for download)
|
|
17
17
|
- `https://github.com/letta-ai/skills` - Letta's community skills
|
|
18
18
|
- `https://github.com/anthropics/skills` - Anthropic's official skills
|
|
19
|
+
- `official/*` - Hermes official optional skills (from `NousResearch/hermes-agent`)
|
|
19
20
|
|
|
20
21
|
### Untrusted Sources (ALWAYS verify with user)
|
|
21
|
-
For ANY source other than
|
|
22
|
+
For ANY source other than the above:
|
|
22
23
|
1. Ask the user before downloading
|
|
23
24
|
2. Explain where the skill comes from
|
|
24
25
|
3. Get explicit approval
|
|
25
26
|
|
|
27
|
+
This includes ClawHub community skills and arbitrary GitHub repos.
|
|
28
|
+
|
|
26
29
|
### Script Safety
|
|
27
30
|
Even for skills from trusted sources, ALWAYS:
|
|
28
31
|
1. Read and inspect any scripts before executing them
|
|
29
32
|
2. Understand what the script does
|
|
30
33
|
3. Be wary of network calls, file operations, or system commands
|
|
31
34
|
|
|
35
|
+
### Cross-Harness Compatibility
|
|
36
|
+
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:
|
|
37
|
+
|
|
38
|
+
- **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.
|
|
39
|
+
- **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.
|
|
40
|
+
- **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.
|
|
41
|
+
- **Platform gating** — skills may declare `platforms: [cli, discord, telegram]` in frontmatter. Ignore platform restrictions that don't apply to Letta.
|
|
42
|
+
- **Environment variables** — skills may require API keys or credentials. Check `requires.env` in frontmatter and note any setup the user needs to do.
|
|
43
|
+
|
|
44
|
+
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.
|
|
45
|
+
|
|
32
46
|
## When to Use This Skill
|
|
33
47
|
|
|
34
48
|
**DO use** when:
|
|
@@ -45,78 +59,221 @@ Even for skills from trusted sources, ALWAYS:
|
|
|
45
59
|
|
|
46
60
|
If you recognize a task that might have an associated skill, **ask the user first**:
|
|
47
61
|
|
|
48
|
-
> "This sounds like something where a community skill might help
|
|
62
|
+
> "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."
|
|
49
63
|
|
|
50
64
|
The user may prefer to start immediately rather than wait for skill discovery.
|
|
51
65
|
|
|
52
66
|
Only proceed with skill acquisition if the user agrees.
|
|
53
67
|
|
|
54
|
-
## Skill
|
|
68
|
+
## Skill Sources
|
|
69
|
+
|
|
70
|
+
### 1. Hermes Skills Hub (NousResearch)
|
|
71
|
+
|
|
72
|
+
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.
|
|
73
|
+
|
|
74
|
+
**Searching Hermes skills:**
|
|
75
|
+
|
|
76
|
+
The Hermes CLI has built-in search and browse:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
hermes skills browse # Browse all hub skills (official first)
|
|
80
|
+
hermes skills browse --source official # Browse only official optional skills
|
|
81
|
+
hermes skills search kubernetes # Search all sources
|
|
82
|
+
hermes skills search react --source skills-sh # Search the skills.sh directory
|
|
83
|
+
hermes skills search https://mintlify.com/docs --source well-known
|
|
84
|
+
hermes skills inspect openai/skills/k8s # Preview before installing
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The web catalog is at https://hermes-agent.nousresearch.com/docs/skills.
|
|
88
|
+
|
|
89
|
+
Hermes hub sources:
|
|
90
|
+
|
|
91
|
+
| Source | Example identifier | Notes |
|
|
92
|
+
|--------|--------------------|-------|
|
|
93
|
+
| `official` | `official/security/1password` | Optional skills shipped with Hermes |
|
|
94
|
+
| `skills-sh` | `skills-sh/vercel-labs/agent-skills/vercel-react-best-practices` | skills.sh directory |
|
|
95
|
+
| `well-known` | `well-known:https://mintlify.com/docs/.well-known/skills/mintlify` | Skills hosted at `/.well-known/skills/` |
|
|
96
|
+
| `url` | `https://sharethis.chat/SKILL.md` | Direct URL to a single SKILL.md |
|
|
97
|
+
| `github` | `openai/skills/k8s` | GitHub repo/path |
|
|
98
|
+
| `clawhub` | ClawHub registry skills | ClawHub marketplace |
|
|
99
|
+
| `lobehub` | LobeHub registry skills | LobeHub marketplace |
|
|
100
|
+
| `browse-sh` | `browse-sh/airbnb.com/search-listings-ddgioa` | browse.sh crawled skills |
|
|
101
|
+
|
|
102
|
+
If Hermes is not installed, you can browse the official optional skills directly:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Browse the catalog on GitHub
|
|
106
|
+
# https://github.com/NousResearch/hermes-agent/tree/main/optional-skills
|
|
107
|
+
# Categories: autonomous-ai-agents, blockchain, creative, devops, finance,
|
|
108
|
+
# health, mcp, mlops, productivity, research, security, ...
|
|
109
|
+
|
|
110
|
+
# Or clone and browse locally
|
|
111
|
+
git clone --depth 1 https://github.com/NousResearch/hermes-agent.git /tmp/hermes-browse
|
|
112
|
+
ls /tmp/hermes-browse/optional-skills/
|
|
113
|
+
ls /tmp/hermes-browse/optional-skills/finance/
|
|
114
|
+
rm -rf /tmp/hermes-browse
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Installing Hermes skills** into Letta uses the `official/` prefix (for official optional skills):
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
letta skills install official/finance/stocks
|
|
121
|
+
letta skills install official/blockchain/solana
|
|
122
|
+
letta skills install official/research/duckduckgo-search
|
|
123
|
+
letta skills install official/mlops/flash-attention
|
|
124
|
+
letta skills install official/creative/meme-generation
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The `official/<category>/<skill>` form clones `NousResearch/hermes-agent` and copies from `optional-skills/<category>/<skill>`.
|
|
128
|
+
|
|
129
|
+
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`).
|
|
130
|
+
|
|
131
|
+
### 2. ClawHub (OpenClaw)
|
|
132
|
+
|
|
133
|
+
ClawHub (https://clawhub.ai) is the public registry for OpenClaw skills and plugins. It hosts community-contributed skills with versioning, security scans, and search.
|
|
134
|
+
|
|
135
|
+
**Searching ClawHub skills:**
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Browse the web registry
|
|
139
|
+
# https://clawhub.ai
|
|
140
|
+
|
|
141
|
+
# Or use the clawhub CLI if installed
|
|
142
|
+
clawhub search "calendar"
|
|
143
|
+
clawhub search "screenshot"
|
|
144
|
+
clawhub explore
|
|
145
|
+
|
|
146
|
+
# Or search via the API directly
|
|
147
|
+
curl -s "https://clawhub.ai/api/v1/skills?q=calendar" | jq '.items[].slug'
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Installing ClawHub skills** uses the `clawhub/` or `clawhub:` prefix:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
letta skills install clawhub/nano-banana-pro
|
|
154
|
+
letta skills install clawhub:nano-banana-pro
|
|
155
|
+
letta skills install clawhub:nano-banana-pro@1.0.1 # pin a version
|
|
156
|
+
letta skills install https://clawhub.ai/skills/my-skill # URL form also works
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Note:** A bare slug like `letta skills install nano-banana-pro` will NOT resolve through ClawHub — you must include the `clawhub/` or `clawhub:` prefix.
|
|
160
|
+
|
|
161
|
+
### 3. GitHub Repositories
|
|
162
|
+
|
|
163
|
+
Any GitHub repository containing a `SKILL.md` can be installed directly.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# Full repo (installs from repo root)
|
|
167
|
+
letta skills install https://github.com/owner/repo
|
|
168
|
+
|
|
169
|
+
# Subdirectory (tree URL)
|
|
170
|
+
letta skills install https://github.com/owner/repo/tree/main/path/to/skill
|
|
171
|
+
|
|
172
|
+
# SKILL.md blob URL (installs parent directory)
|
|
173
|
+
letta skills install https://github.com/owner/repo/blob/main/path/to/skill/SKILL.md
|
|
174
|
+
|
|
175
|
+
# Shorthand: owner/repo/path
|
|
176
|
+
letta skills install owner/repo/path/to/skill
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 4. Letta & Anthropic Community Repos
|
|
55
180
|
|
|
56
181
|
| Repository | Description |
|
|
57
182
|
|------------|-------------|
|
|
58
183
|
| https://github.com/letta-ai/skills | Community skills for Letta agents |
|
|
59
184
|
| https://github.com/anthropics/skills | Anthropic's official Agent Skills |
|
|
60
185
|
|
|
61
|
-
|
|
186
|
+
These can be installed via the GitHub URL forms above, or manually cloned and copied.
|
|
187
|
+
|
|
188
|
+
## The `letta skills install` Command
|
|
189
|
+
|
|
190
|
+
The CLI handles downloading, placing the skill in the agent's memory, and committing the change:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
letta skills install <source> --agent $AGENT_ID [--force]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Your agent ID is always available as `$AGENT_ID` in the environment. Pass it explicitly with `--agent` to install into your own memfs:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
letta skills install official/finance/stocks --agent $AGENT_ID
|
|
200
|
+
letta skills install clawhub/nano-banana-pro --agent $AGENT_ID
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
| Flag | Purpose |
|
|
204
|
+
|------|---------|
|
|
205
|
+
| `--agent <id>` | Install into a specific agent's memfs (use `$AGENT_ID` for yourself) |
|
|
206
|
+
| `-n <name>` | Resolve agent by name instead of id |
|
|
207
|
+
| `--force` | Replace an existing skill with the same name |
|
|
208
|
+
|
|
209
|
+
Also available as a top-level alias: `letta install <source> --agent $AGENT_ID`.
|
|
210
|
+
|
|
211
|
+
**Managing installed skills:**
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
letta skills list --agent $AGENT_ID
|
|
215
|
+
letta skills delete <skill-name> --agent $AGENT_ID
|
|
216
|
+
```
|
|
62
217
|
|
|
63
218
|
## Installation Locations
|
|
64
219
|
|
|
220
|
+
When using `letta skills install`, skills are placed in the agent's memfs at `<memory-dir>/skills/<skill-name>/`.
|
|
221
|
+
|
|
222
|
+
For manual installation:
|
|
223
|
+
|
|
65
224
|
| Location | Path | When to Use |
|
|
66
225
|
|----------|------|-------------|
|
|
67
|
-
| **Agent-scoped** | `~/.letta/agents/<agent-id>/memory/skills/<skill>/` | Skills for a single agent (default
|
|
226
|
+
| **Agent-scoped** | `~/.letta/agents/<agent-id>/memory/skills/<skill>/` | Skills for a single agent (default) |
|
|
68
227
|
| **Global** | `~/.letta/skills/<skill>/` | General-purpose skills useful across projects |
|
|
69
228
|
| **Project** | `.skills/<skill>/` | Project-specific skills |
|
|
70
229
|
|
|
71
|
-
**Rule**: Default to **agent-scoped
|
|
230
|
+
**Rule**: Default to **agent-scoped**. Use **project** for repo-specific skills. Use **global** only if all agents should inherit the skill.
|
|
72
231
|
|
|
73
|
-
##
|
|
232
|
+
## Manual Download (When CLI Install Isn't Available)
|
|
74
233
|
|
|
75
234
|
Skills are directories containing SKILL.md and optionally scripts/, references/, examples/.
|
|
76
235
|
|
|
77
|
-
### Method: Clone to /tmp, then copy
|
|
78
|
-
|
|
79
236
|
```bash
|
|
80
|
-
#
|
|
237
|
+
# Clone, copy, cleanup
|
|
81
238
|
git clone --depth 1 https://github.com/anthropics/skills /tmp/skills-temp
|
|
82
|
-
|
|
83
|
-
# 2. Copy the skill to your skills directory
|
|
84
|
-
# For agent-scoped (recommended default):
|
|
85
239
|
cp -r /tmp/skills-temp/skills/webapp-testing ~/.letta/agents/<agent-id>/memory/skills/
|
|
86
|
-
# For global:
|
|
87
|
-
# cp -r /tmp/skills-temp/skills/webapp-testing ~/.letta/skills/
|
|
88
|
-
# For project:
|
|
89
|
-
# cp -r /tmp/skills-temp/skills/webapp-testing .skills/
|
|
90
|
-
|
|
91
|
-
# 3. Cleanup
|
|
92
240
|
rm -rf /tmp/skills-temp
|
|
93
241
|
```
|
|
94
242
|
|
|
95
|
-
|
|
243
|
+
## Registering New Skills
|
|
96
244
|
|
|
97
|
-
|
|
98
|
-
git clone --depth 1 https://github.com/anthropics/skills /tmp/skills-temp
|
|
99
|
-
rsync -av /tmp/skills-temp/skills/webapp-testing/ ~/.letta/agents/<agent-id>/memory/skills/webapp-testing/
|
|
100
|
-
rm -rf /tmp/skills-temp
|
|
101
|
-
```
|
|
245
|
+
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.
|
|
102
246
|
|
|
103
|
-
##
|
|
247
|
+
## Search Strategy
|
|
248
|
+
|
|
249
|
+
When looking for a skill to solve a user's problem:
|
|
104
250
|
|
|
105
|
-
|
|
251
|
+
1. **Search Hermes Skills Hub first** — `hermes 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.).
|
|
252
|
+
2. **Search ClawHub** — community registry with versioning. Use `clawhub search` or the web UI.
|
|
253
|
+
3. **Search GitHub** — look for repos with `SKILL.md` files. Try `github.com/letta-ai/skills` and `github.com/anthropics/skills` first.
|
|
254
|
+
4. **Ask the user** — they may know of a specific skill repo or have preferences about sources.
|
|
106
255
|
|
|
107
256
|
## Complete Example
|
|
108
257
|
|
|
109
|
-
User asks: "Can you help me
|
|
258
|
+
User asks: "Can you help me track stock prices?"
|
|
259
|
+
|
|
260
|
+
1. **Recognize opportunity**: Stock/finance data — Hermes has a stocks skill
|
|
261
|
+
2. **Ask user**: "Hermes has an official stocks skill that covers quotes, history, search, and crypto via Yahoo. Want me to install it?"
|
|
262
|
+
3. **If user agrees, install**:
|
|
263
|
+
```bash
|
|
264
|
+
letta skills install official/finance/stocks --agent $AGENT_ID
|
|
265
|
+
```
|
|
266
|
+
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.
|
|
267
|
+
5. **Invoke**: `Skill(skill: "stocks")`
|
|
268
|
+
6. **Use**: Follow the skill's instructions, adapting any harness-specific details as needed
|
|
269
|
+
|
|
270
|
+
User asks: "Can you generate images with Nano Banana Pro?"
|
|
110
271
|
|
|
111
|
-
1. **Recognize opportunity**:
|
|
112
|
-
2. **Ask user**: "
|
|
113
|
-
3. **
|
|
114
|
-
4. **Download** (trusted source):
|
|
272
|
+
1. **Recognize opportunity**: Image generation skill on ClawHub
|
|
273
|
+
2. **Ask user**: "There's a nano-banana-pro skill on ClawHub. Want me to install it?"
|
|
274
|
+
3. **Install**:
|
|
115
275
|
```bash
|
|
116
|
-
|
|
117
|
-
cp -r /tmp/skills-temp/skills/webapp-testing ~/.letta/agents/<agent-id>/memory/skills/
|
|
118
|
-
rm -rf /tmp/skills-temp
|
|
276
|
+
letta skills install clawhub/nano-banana-pro --agent $AGENT_ID
|
|
119
277
|
```
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
7. **Use**: Follow the skill's instructions for the user's task
|
|
278
|
+
4. **Review for compatibility**: Read the SKILL.md, check for any OpenClaw-specific commands or setup, adapt as needed.
|
|
279
|
+
5. **Invoke**: `Skill(skill: "nano-banana-pro")`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: creating-extensions
|
|
3
|
-
description: Creates and edits trusted local Letta Code extensions, including
|
|
3
|
+
description: Creates and edits trusted local Letta Code extensions, including tools, slash commands, local-only model providers, lifecycle/turn events, scoped conversation helpers, panels, status values, and capability-gated behavior. Use when asked to make an extension, add an agent-callable tool, add a slash command, add a local provider/model adapter, transform turns, react to app events, or add lightweight extension UI outside the dedicated /statusline flow.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Creating Extensions
|
|
@@ -13,6 +13,8 @@ Use this skill to create or update trusted global Letta Code extensions in:
|
|
|
13
13
|
|
|
14
14
|
Extensions are trusted local apps for Letta Code. They add small composable capabilities through extension APIs, not by importing app internals. Prefer scoped handles (`ctx.conversation`, `ctx.cwd`, `ctx.agent`, `letta.getContext()`) and guard optional UI with `letta.capabilities`.
|
|
15
15
|
|
|
16
|
+
Capabilities vary by surface. TUI/headless may load tools, commands, events, UI, and providers; the desktop listener loads provider-only extensions for local provider discovery. Always guard optional capabilities.
|
|
17
|
+
|
|
16
18
|
## Choose the right capability
|
|
17
19
|
|
|
18
20
|
| User wants | Build |
|
|
@@ -24,6 +26,8 @@ Extensions are trusted local apps for Letta Code. They add small composable capa
|
|
|
24
26
|
| Show transient output above input | Panel, usually from a command |
|
|
25
27
|
| Show small persistent state | Status value |
|
|
26
28
|
| React to app/session lifecycle or transform outbound turns | Event |
|
|
29
|
+
| Enforce dynamic allow/ask/deny policy for tool calls | Permission overlay |
|
|
30
|
+
| Add a custom model/API provider for local agents | Provider extension (local agents only) |
|
|
27
31
|
| Change the bottom statusline appearance | Use `customizing-statusline`, not this skill |
|
|
28
32
|
|
|
29
33
|
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.
|
|
@@ -32,17 +36,17 @@ Default to a **tool** when the model should decide when to use the capability. D
|
|
|
32
36
|
|
|
33
37
|
1. Inspect `~/.letta/extensions/` for related files.
|
|
34
38
|
2. Preserve unrelated extension code. Prefer a focused new file if merging would be messy.
|
|
35
|
-
3. Choose the extension shape:
|
|
36
|
-
- simple tool/command/event: read the specific recipe below
|
|
37
|
-
- multi-capability or stateful extension: also read `references/architecture.md`
|
|
38
|
-
4. Load only the needed recipe:
|
|
39
|
+
3. Choose the extension shape and load only the needed recipe:
|
|
39
40
|
- tools: `references/tools.md`
|
|
40
41
|
- commands: `references/commands.md`
|
|
42
|
+
- local custom providers: `references/providers.md`
|
|
41
43
|
- events: `references/events.md`
|
|
44
|
+
- permissions: `references/permissions.md`
|
|
42
45
|
- panels/status/capabilities: `references/ui.md`
|
|
43
|
-
-
|
|
46
|
+
- complex plan-mode composition: `references/plan-mode.md`
|
|
47
|
+
4. For multi-capability or stateful extensions, also read `references/architecture.md`.
|
|
44
48
|
5. Write a single-file extension unless the user asks for something larger.
|
|
45
|
-
6. Return disposers for registered commands/tools/events, timers, subscriptions, and panels that should close on reload.
|
|
49
|
+
6. Return disposers for registered providers/commands/tools/events, timers, subscriptions, and panels that should close on reload.
|
|
46
50
|
7. Do a basic review: valid names, descriptions present, schemas are object schemas, optional capabilities guarded, scoped APIs used, cleanup returned.
|
|
47
51
|
8. Tell the user the absolute file path changed and to run `/reload`. If an extension breaks startup or command handling, recover with `letta --no-extensions` or `LETTA_DISABLE_EXTENSIONS=1 letta`.
|
|
48
52
|
|
|
@@ -74,6 +78,8 @@ letta.capabilities.commands
|
|
|
74
78
|
letta.capabilities.events.lifecycle
|
|
75
79
|
letta.capabilities.events.tools
|
|
76
80
|
letta.capabilities.events.turns
|
|
81
|
+
letta.capabilities.permissions
|
|
82
|
+
letta.capabilities.providers
|
|
77
83
|
letta.capabilities.ui.panels
|
|
78
84
|
letta.capabilities.ui.statusValues
|
|
79
85
|
letta.capabilities.ui.customStatuslineRenderer
|
|
@@ -89,9 +95,21 @@ letta.capabilities.ui.customStatuslineRenderer
|
|
|
89
95
|
- Use `letta.client` only for server-specific Letta API calls; do not use it as a substitute for scoped conversation helpers.
|
|
90
96
|
- Do not import `@/backend`, `@/cli`, or other Letta Code internals from extension files.
|
|
91
97
|
|
|
98
|
+
## Diagnostics
|
|
99
|
+
|
|
100
|
+
Use `letta.diagnostics.report({ message, severity })` sparingly as a debug utility for extension 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.
|
|
101
|
+
|
|
102
|
+
Agents can inspect local extension diagnostics at:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
~/.letta/extensions/diagnostics/latest.json
|
|
106
|
+
```
|
|
107
|
+
|
|
92
108
|
## Rules
|
|
93
109
|
|
|
94
110
|
- Global trusted code only for now. Do not create project extensions.
|
|
111
|
+
- Custom provider extensions are local-backend/local-agent only. They do not add providers for Constellation/cloud agents.
|
|
112
|
+
- Provider extensions may run in a provider-only listener context; keep provider registration independent from commands/tools/UI and guard everything else.
|
|
95
113
|
- Do not assume extra npm packages are available.
|
|
96
114
|
- Do not do surprising side effects on startup; extensions activate on app start and `/reload`.
|
|
97
115
|
- Keep user-facing output short and intentional.
|
|
@@ -110,6 +128,7 @@ Before finishing, verify:
|
|
|
110
128
|
- Tool descriptions explain when the model should call them.
|
|
111
129
|
- JSON schemas are object schemas with useful descriptions.
|
|
112
130
|
- Optional UI/event/statusline APIs are capability-guarded.
|
|
131
|
+
- Provider extensions are capability-guarded and clearly documented as local-agent only.
|
|
113
132
|
- Timers, intervals, event registrations, and panels are cleaned up in a disposer.
|
|
114
133
|
- Busy commands return `{ type: "handled" }` quickly and avoid main-conversation sends.
|
|
115
134
|
- Conversation work uses `ctx.conversation` or forked handles, not app internals.
|
|
@@ -118,9 +137,13 @@ Before finishing, verify:
|
|
|
118
137
|
|
|
119
138
|
## References
|
|
120
139
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
140
|
+
| Reference | Load when |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| `references/tools.md` | The model should autonomously call a local capability |
|
|
143
|
+
| `references/commands.md` | The human should invoke `/foo` |
|
|
144
|
+
| `references/providers.md` | Adding a custom model/API provider for local agents |
|
|
145
|
+
| `references/events.md` | Reacting to lifecycle/tool/turn events or transforming turns/tools |
|
|
146
|
+
| `references/permissions.md` | Enforcing dynamic tool allow/ask/deny policy before approval/execution |
|
|
147
|
+
| `references/ui.md` | Panels, status values, or statusline capability guards are involved |
|
|
148
|
+
| `references/plan-mode.md` | Recreating plan mode with commands, tools, events, permissions, and local state |
|
|
149
|
+
| `references/architecture.md` | Multiple capabilities, local state, cleanup, background model work, or non-trivial composition |
|
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
Use this reference for non-trivial extensions: multiple capabilities, local state, timers, background model work, or UI.
|
|
4
4
|
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- Mental model
|
|
8
|
+
- Capability composition patterns
|
|
9
|
+
- Local state
|
|
10
|
+
- Timers and subscriptions
|
|
11
|
+
- Scoped conversation handles
|
|
12
|
+
- Error handling
|
|
13
|
+
- Final review checklist
|
|
14
|
+
|
|
5
15
|
## Mental model
|
|
6
16
|
|
|
7
17
|
An extension is trusted local code that registers capabilities during activation and cleans them up on reload/shutdown. Keep the public surface small:
|
|
@@ -13,6 +23,8 @@ An extension is trusted local code that registers capabilities during activation
|
|
|
13
23
|
|
|
14
24
|
Do not import Letta Code internals. If the extension API does not expose a capability yet, avoid reaching around it.
|
|
15
25
|
|
|
26
|
+
Capabilities vary by host surface. Keep each registration behind the matching `letta.capabilities` guard so one file can run in TUI, headless, and provider-only listener contexts.
|
|
27
|
+
|
|
16
28
|
## Capability composition patterns
|
|
17
29
|
|
|
18
30
|
### Tool + command
|
|
@@ -4,6 +4,15 @@ Use commands when the human explicitly invokes `/foo`.
|
|
|
4
4
|
|
|
5
5
|
For complex command-driven extensions with panels, timers, local state, or background model work, also read `architecture.md`.
|
|
6
6
|
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- Decide command vs skill vs tool
|
|
10
|
+
- Command IDs
|
|
11
|
+
- Prompt command
|
|
12
|
+
- Output-only command
|
|
13
|
+
- Panel command
|
|
14
|
+
- Busy-safe conversation command
|
|
15
|
+
|
|
7
16
|
## Decide command vs skill vs tool
|
|
8
17
|
|
|
9
18
|
| Need | Use |
|
|
@@ -116,4 +125,4 @@ const stream = await forked.sendMessageStream([
|
|
|
116
125
|
|
|
117
126
|
Do not send directly to the active conversation from a busy command; fork first unless the user explicitly asked to affect the main conversation later.
|
|
118
127
|
|
|
119
|
-
For a
|
|
128
|
+
For a worked multi-capability extension that combines commands, tools, events, permissions, and local state, see `plan-mode.md`.
|
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
Use events when trusted local code should react to app/session changes or transform outbound turns without the human explicitly invoking a command. For event-driven extensions with state, timers, panels, or background model work, also read `architecture.md`.
|
|
4
4
|
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- Capabilities
|
|
8
|
+
- Supported events
|
|
9
|
+
- Tool argument transforms
|
|
10
|
+
- Turn input transforms
|
|
11
|
+
- Event handler context
|
|
12
|
+
- Conversation status example
|
|
13
|
+
- Rules
|
|
14
|
+
|
|
5
15
|
This is the first slice of the hooks-v2 direction. The long-term goal is for typed extension events to replace settings-based hooks. Existing hooks still own blocking decisions and model feedback injection until each event has a typed return contract.
|
|
6
16
|
|
|
7
17
|
## Capabilities
|
|
@@ -34,7 +44,7 @@ letta.events.on("event_name", (event, ctx) => {
|
|
|
34
44
|
});
|
|
35
45
|
```
|
|
36
46
|
|
|
37
|
-
Tool events use this same API.
|
|
47
|
+
Tool events use this same API. Use `letta.permissions.register` for allow/ask/deny policy; use `tool_start` for last-mile argument transforms and lifecycle reactions.
|
|
38
48
|
|
|
39
49
|
```ts
|
|
40
50
|
letta.events.on("tool_start", (event, ctx) => {
|
|
@@ -105,7 +115,7 @@ Lifecycle handlers are notification-only and should not return values. `turn_sta
|
|
|
105
115
|
}
|
|
106
116
|
```
|
|
107
117
|
|
|
108
|
-
`tool_start` fires immediately before a client-side tool executes. This includes built-in tools, extension tools, and external tools executed through the local tool manager. It runs after permission/approval classification and before `PreToolUse` hooks, so trusted local extensions can change the actual executed arguments after the approval UI has already classified the original request.
|
|
118
|
+
`tool_start` fires immediately before a client-side tool executes. This includes built-in tools, extension tools, and external tools executed through the local tool manager. It runs after permission/approval classification and before `PreToolUse` hooks, so trusted local extensions can change the actual executed arguments after the approval UI has already classified the original request. Extension permission overlays are rechecked after `tool_start` on the final args.
|
|
109
119
|
|
|
110
120
|
Handlers can inspect `event.args`, mutate it directly, or return replacement args:
|
|
111
121
|
|
|
@@ -128,20 +138,6 @@ Handlers run in registration order. Later handlers see the current args after ea
|
|
|
128
138
|
|
|
129
139
|
`tool_start` is intentionally a trusted local extension point: it can rewrite commands, file paths, and other tool inputs before execution. Keep transforms focused and unsurprising.
|
|
130
140
|
|
|
131
|
-
### Denying tool execution
|
|
132
|
-
|
|
133
|
-
Handlers can deny a tool by returning `{ deny: true, reason?: "..." }`. All handlers still run (for side effects like logging or state updates), but if any handler denies, the tool is blocked. The first denial reason is shown to the model as the tool error message.
|
|
134
|
-
|
|
135
|
-
```ts
|
|
136
|
-
letta.events.on("tool_start", (event) => {
|
|
137
|
-
if (event.toolName === "Bash" && String(event.args.command).includes("rm -rf")) {
|
|
138
|
-
return { deny: true, reason: "Destructive command blocked." };
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
Denial runs before `PreToolUse` hooks. If an extension denies a tool, hooks are not invoked for that tool call.
|
|
144
|
-
|
|
145
141
|
`turn_start` fires before outbound turns that include a user message. In the TUI this includes normal submits and prompt-style command turns. In headless it includes one-shot prompts and bidirectional user turns.
|
|
146
142
|
|
|
147
143
|
Handlers can mutate `event.input` directly or return replacement input:
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Extension permission recipes
|
|
2
|
+
|
|
3
|
+
Use permission overlays when trusted local code should participate in tool approval decisions. Prefer permissions over `tool_start` denial for policy: permissions run before approval UI and again before execution on final tool arguments.
|
|
4
|
+
|
|
5
|
+
## Capability
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
letta.capabilities.permissions
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Guard registrations when writing portable extensions:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
export default function activate(letta) {
|
|
15
|
+
if (!letta.capabilities.permissions) return;
|
|
16
|
+
|
|
17
|
+
return letta.permissions.register({
|
|
18
|
+
id: "plan-mode",
|
|
19
|
+
description: "Allow read-only tools and writes only to the active plan file.",
|
|
20
|
+
check(event) {
|
|
21
|
+
if (!isPlanModeActive(event.conversationId)) return;
|
|
22
|
+
|
|
23
|
+
if (isReadOnlyTool(event.toolName, event.args)) {
|
|
24
|
+
return { decision: "allow" };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isActivePlanFileWrite(event.toolName, event.args)) {
|
|
28
|
+
return { decision: "allow", reason: "active plan file" };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
decision: "deny",
|
|
33
|
+
reason: "Plan mode is active. You can only read files or update the plan file.",
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Event shape
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
{
|
|
44
|
+
agentId: string | null;
|
|
45
|
+
conversationId: string | null;
|
|
46
|
+
toolCallId: string | null;
|
|
47
|
+
toolName: string;
|
|
48
|
+
args: Record<string, unknown>;
|
|
49
|
+
cwd: string;
|
|
50
|
+
workingDirectory: string;
|
|
51
|
+
permissionMode: string | null;
|
|
52
|
+
phase: "approval" | "execution";
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Return values
|
|
57
|
+
|
|
58
|
+
Return one of:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
{ decision: "allow", reason?: string }
|
|
62
|
+
{ decision: "ask", reason?: string }
|
|
63
|
+
{ decision: "deny", reason?: string }
|
|
64
|
+
undefined // no opinion
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Composition rules across overlays:
|
|
68
|
+
|
|
69
|
+
- `deny` wins
|
|
70
|
+
- then `ask`
|
|
71
|
+
- then `allow`
|
|
72
|
+
- `undefined` means no opinion
|
|
73
|
+
|
|
74
|
+
User/configured hard denials still win before extension overlays. Extension overlays can override normal auto-allow/default approval behavior, including unrestricted/yolo mode.
|
|
75
|
+
|
|
76
|
+
## Two phases
|
|
77
|
+
|
|
78
|
+
Permission overlays run during approval classification (`phase: "approval"`) and again immediately before execution (`phase: "execution"`) after any `tool_start` argument transforms.
|
|
79
|
+
|
|
80
|
+
During execution, `ask` cannot reopen approval yet, so use `deny` for execution-time blocking behavior.
|
|
81
|
+
|
|
82
|
+
## Rules
|
|
83
|
+
|
|
84
|
+
- Keep checks fast and deterministic.
|
|
85
|
+
- Return `undefined` when the overlay is not active for the current conversation/state.
|
|
86
|
+
- Prefer path-scoped allow rules over broad allow rules.
|
|
87
|
+
- Do not mutate `event.args`; use `tool_start` for argument transforms.
|
|
88
|
+
- For policy decisions, prefer this API over `tool_start` denial.
|
|
89
|
+
|
|
90
|
+
For a complete worked example that uses permission overlays for plan-mode enforcement, see `plan-mode.md`.
|