8.7 KiB
Skills
Skills extend your LettaBot agent with CLI tools and specialized knowledge. They follow the open Agent Skills standard used by Letta Code, Cursor, Claude Code, and other compatible agents.
This document covers how skills work within lettabot specifically -- directory hierarchy, feature-gated installation, the SKILL.md format, and how to author new skills.
How skills work
Skills go through two phases:
- Installation -- Feature-gated skills (scheduling, Google, voice memo) are automatically copied to the agent's skill directory based on config flags in
lettabot.yaml. Non-feature-gated skills are discovered directly from the directory hierarchy. - Runtime -- When a session starts, skill directories containing executables are prepended to
PATHso the agent can invoke them as CLI tools.
Directory hierarchy
LettaBot scans these directories in priority order. Same-name skills at higher priority override lower ones:
| Priority | Path | Scope | Description |
|---|---|---|---|
| 1 (highest) | .skills/ |
Project | Skills specific to this lettabot project |
| 2 | ~/.letta/agents/{id}/skills/ |
Agent | Skills for one specific agent |
| 3 | ~/.letta/skills/ |
Global | Shared across all agents on this machine |
| 4 | skills/ (in lettabot repo) |
Bundled | Ships with lettabot |
| 5 (lowest) | ~/.agents/skills/ |
skills.sh | Installed via skills.sh |
On Railway with a mounted volume, LettaBot stores .letta skill paths under $RAILWAY_VOLUME_MOUNT_PATH/.letta/ by default, so agent-scoped and global skills survive redeploys.
Feature-gated skills are copied from source directories into the agent-scoped directory (~/.letta/agents/{id}/skills/) when a session is first acquired. The copy is idempotent -- skills already present in the target are skipped.
Feature-gated skills
Some skills are only installed when their corresponding feature is enabled in lettabot.yaml:
| Config flag | Skills installed | Purpose |
|---|---|---|
features.cron: true |
scheduling |
Cron jobs and one-off reminders via lettabot-schedule |
integrations.google.enabled: true or polling.gmail.enabled: true |
gog, google |
Google Workspace and Gmail integration |
| TTS provider configured (ElevenLabs or OpenAI key set) | voice-memo |
Voice memo replies via lettabot-tts |
The mapping from config flags to skill names lives in FEATURE_SKILLS in src/skills/loader.ts. The code also supports passing explicit skill names programmatically via additionalSkills in SkillsInstallConfig.
SKILL.md format
Each skill is a directory containing a SKILL.md file with YAML frontmatter and a body written for the agent (not humans). The body is loaded into the agent's context when the skill is relevant -- it's a prompt, not documentation.
---
name: scheduling
description: Create scheduled tasks and one-off reminders.
---
# Scheduling
(Agent-facing instructions: CLI usage, when to use the skill, examples, constraints...)
Frontmatter fields
| Field | Required | Description |
|---|---|---|
name |
Yes | Skill identifier (must be unique within its scope) |
description |
No | Brief description shown to the agent |
emoji |
No | Display emoji |
homepage |
No | URL for the skill's homepage or docs |
metadata |
No | JSON-encoded object with a clawdbot key (see below) |
ClawdBot metadata
The metadata field can contain a JSON-encoded clawdbot object for requirements and install specs:
metadata: >-
{"clawdbot": {
"emoji": "📦",
"requires": {"bins": ["mycli"], "env": ["MY_API_KEY"]},
"install": [{"kind": "brew", "formula": "mycli"}]
}}
requires -- prerequisites for the skill to be eligible:
| Field | Type | Description |
|---|---|---|
bins |
string[] |
All of these binaries must exist on PATH |
anyBins |
string[] |
At least one of these must exist |
env |
string[] |
Required environment variables |
Run lettabot skills status to see which skills are eligible and which have missing binaries, environment variables, or platform mismatches.
install -- how to install dependencies (tried in order, filtered by platform):
| Field | Type | Description |
|---|---|---|
kind |
'brew' | 'node' | 'go' | 'uv' | 'download' |
Package manager |
formula |
string |
Homebrew formula (for brew) |
package |
string |
npm/uv package name (for node/uv) |
module |
string |
Go module path (for go) |
url |
string |
Download URL (for download) |
bins |
string[] |
Binaries this installs |
os |
string[] |
Platform filter (darwin, linux, win32) |
label |
string |
Display label for the install option |
Other metadata fields:
| Field | Type | Description |
|---|---|---|
os |
string[] |
Restrict skill to these platforms |
always |
boolean |
Always eligible regardless of requirements |
skillKey |
string |
Override the skill's key identifier |
primaryEnv |
string |
Primary environment variable for the skill |
Skill execution
When a session starts, prependSkillDirsToPath() in src/skills/loader.ts prepends skill directories to PATH immediately before createSession/resumeSession is called. The SDK spawns the Letta Code subprocess at session-creation time, so the subprocess inherits the augmented PATH at fork. Two sources are combined:
- Agent-scoped skills (
~/.letta/agents/{id}/skills/) — feature-gated skills installed byinstallSkillsToAgent()on startup. - Working-dir skills (
WORKING_DIR/.skills/) — skills enabled vialettabot skills enable <name>or the interactivelettabot skillswizard.
On Railway with a mounted volume, WORKING_DIR defaults to $RAILWAY_VOLUME_MOUNT_PATH/data when not explicitly set, so working-dir skills are persisted on the volume by default.
On Railway with a mounted volume, agent-scoped skills are stored under $RAILWAY_VOLUME_MOUNT_PATH/.letta/agents/{id}/skills/.
Only directories containing at least one non-.md file are added. The prepend is idempotent — directories already on PATH are not duplicated. PATH is not restored after the call; the augmented PATH persists for the lifetime of the process, which is correct because the subprocess retains its inherited environment.
To verify skill directories are present after startup, check the child subprocess's /proc/[pid]/environ (not the parent lettabot process, which shares the same augmented PATH).
Bundled skills
LettaBot ships with two built-in skills in the skills/ directory:
- scheduling -- Create recurring cron jobs and one-off reminders via the
lettabot-scheduleCLI. Enabled byfeatures.cron: true. See Cron Setup for details. - voice-memo -- Reply with voice notes using the
<voice>directive andlettabot-ttsCLI. Enabled when a TTS provider (ElevenLabs or OpenAI) is configured.
Installing external skills
Use the interactive CLI to discover and enable skills:
# Interactive skill selector
lettabot skills
# Enable/disable skills from Clawdhub, skills.sh, and built-in sources
lettabot skills sync
# Check status of all discovered skills
lettabot skills status
Important: These commands discover skills relative to the current working directory. Run them from the lettabot project root to ensure all project-level skills (
.skills/) and bundled skills (skills/) are found. Running from a different directory will only show globally installed skills.
External skill sources:
See the Letta Code skills documentation for the general skill installation flow and additional skill sources.
Authoring a new skill
To add a skill to lettabot:
- Create a directory under
skills/<name>/(in the lettabot repo root) with aSKILL.mdfile. The frontmatter declares metadata (see above). The body is a prompt loaded into the agent's context -- write it as instructions the agent will follow, not as human documentation. - Place any executables or scripts alongside
SKILL.mdin the same directory. These become available on the agent's PATH at runtime. - If the skill should be feature-gated (only installed when a config flag is set), add an entry to
FEATURE_SKILLSinsrc/skills/loader.tsand wire up the corresponding config flag inmain.ts. - Verify with
lettabot skills statusthat the skill is discovered and eligible.
For project-local skills that don't ship with lettabot, place them in .skills/<name>/ instead.