Skip to main content
This guide shows how to implement skills in the SDK. For conceptual overview, see Skills Overview. OpenHands supports an extended version of the AgentSkills standard with optional keyword triggers.

Skill Injection Behavior

Understanding where skill content appears in the prompt is critical. The behavior differs based on skill format and trigger configuration:
Token Usage Warning: Legacy skills with trigger=None add their full content to <REPO_CONTEXT> in the initial SystemPromptEvent. That system message remains part of the conversation context for subsequent LLM calls, so the content still affects token usage on each turn. Consider using AgentSkills format (SKILL.md) for progressive disclosure instead.

Prompt Structure

Skills appear in different parts of the system prompt:
When a trigger matches, content is injected into the user message:

Context Loading Methods

Always-Loaded Context

Content that’s always in the system prompt.

Option 1: AGENTS.md (Auto-loaded)

Place AGENTS.md at your repo root - it’s loaded automatically. See Permanent Context.

Option 2: Inline Skill (Code-defined)

Important: Inline skills with trigger=None use legacy format behavior — full content is added to <REPO_CONTEXT> in the initial system prompt and remains part of the conversation context for subsequent LLM calls. For large skills, consider using the AgentSkills SKILL.md format for progressive disclosure.

Trigger-Loaded Context

Content injected when keywords appear in user messages. See Keyword-Triggered Skills.
When user says “encrypt this”, the content is injected into the message:

Path-Triggered Rules

A rule is a skill with a PathTrigger (paths: glob frontmatter). Its content is injected deterministically when the agent reads, edits, or creates a file whose workspace-relative path matches one of the globs — no reliance on the model choosing a skill. See Path-Triggered Rules for the conceptual overview. Rules add zero baseline cost: they are excluded from <available_skills> and <REPO_CONTEXT> and are never model-invocable (disable_model_invocation is forced on). Nothing is loaded until a matching file is touched, and each rule is injected only once per conversation.
As a file-based skill, this is just a *.md file with paths: frontmatter in a skills directory (e.g. .agents/skills/api-validation.md):
When the agent creates or edits src/api/users.ts, the rule content is appended to that tool result (not the user message) inside an <EXTRA_INFO> block, so the agent reads it on its next step:

Glob Semantics

Patterns use gitignore-style matching against the workspace-relative POSIX path (case-sensitive):
  • A skill is either path-triggered or model-invocable, not both: if a file declares both paths: and triggers:, paths: wins.
  • Rules are repo-scoped — touching a file outside the workspace never fires a rule.
  • Injection is available for local conversations. ACP-backed conversations do not inject path rules, because the ACP server owns tool execution.

Progressive Disclosure (AgentSkills Standard)

For the agent to trigger skills, use the AgentSkills standard SKILL.md format. The agent sees a summary and reads full content on demand.
Skills are listed in the system prompt:
Add triggers to a SKILL.md for both progressive disclosure AND automatic injection when keywords match.

Managing Installed Skills

You can install AgentSkills into a persistent directory and manage them through openhands.sdk.skills. Skills are stored under ~/.openhands/skills/installed/ with a .installed.json metadata file that records an enabled flag. list_installed_skills() returns all installed skills, while load_installed_skills() returns only those with enabled=true. The public lifecycle API includes install_skill(), update_skill(), enable_skill(), disable_skill(), and uninstall_skill(), which gives the CLI a clean SDK surface for /skill install, /skill enable, /skill disable, and /skill uninstall.

Installed Skill Lifecycle Example

This example mirrors the installed-plugin lifecycle example, but for AgentSkills. It installs sample skills, lists them, toggles the persistent enabled flag, and uninstalls one skill while leaving the other available.
examples/05_skills_and_plugins/03_managing_installed_skills/main.py
You can run the example code as-is.
The model name should follow the LiteLLM convention: provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o). The LLM_API_KEY should be the API key for your chosen provider.
ChatGPT Plus/Pro subscribers: You can use LLM.subscription_login() to authenticate with your ChatGPT account and access Codex models without consuming API credits. See the LLM Subscriptions guide for details.

Installing Skills from a Marketplace

Use a marketplace when you want to install a curated mix of local and remote AgentSkills in one step. The example below shows how to define a marketplace, install all listed skills, and inspect the installed metadata.
examples/01_standalone_sdk/43_mixed_marketplace_skills/main.py
You can run the example code as-is.
The model name should follow the LiteLLM convention: provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o). The LLM_API_KEY should be the API key for your chosen provider.
ChatGPT Plus/Pro subscribers: You can use LLM.subscription_login() to authenticate with your ChatGPT account and access Codex models without consuming API credits. See the LLM Subscriptions guide for details.

Full Example

examples/01_standalone_sdk/03_activate_skill.py
You can run the example code as-is.
The model name should follow the LiteLLM convention: provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o). The LLM_API_KEY should be the API key for your chosen provider.
ChatGPT Plus/Pro subscribers: You can use LLM.subscription_login() to authenticate with your ChatGPT account and access Codex models without consuming API credits. See the LLM Subscriptions guide for details.

Creating Skills

Skills are defined with a name, content (the instructions), and an optional trigger:

Keyword Triggers

Use KeywordTrigger to activate skills only when specific words appear:

File-Based Skills (SKILL.md)

For reusable skills, use the AgentSkills standard directory format.

Directory Structure

Each skill is a directory containing:
my-skill/
SKILL.md
scripts/
helper.sh
references/
examples.md
assets/
config.json
where

SKILL.md Format

The SKILL.md file defines the skill with YAML frontmatter:

Frontmatter Fields

Add triggers to make your SKILL.md keyword-activated by matching a user prompt. Without triggers, the skill can only be triggered by the agent, not the user.

Loading Skills

Use load_skills_from_dir() to load all skills from a directory:
examples/05_skills_and_plugins/01_loading_agentskills/main.py
You can run the example code as-is.
The model name should follow the LiteLLM convention: provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o). The LLM_API_KEY should be the API key for your chosen provider.
ChatGPT Plus/Pro subscribers: You can use LLM.subscription_login() to authenticate with your ChatGPT account and access Codex models without consuming API credits. See the LLM Subscriptions guide for details.

Key Functions

load_skills_from_dir()

Loads all skills from a directory, returning three dictionaries:
When passing to AgentContext(skills=...), all three types are accepted. The injection behavior depends on the skill’s is_agentskills_format flag and trigger field — see Skill Injection Behavior.

discover_skill_resources()

Discovers resource files in a skill directory:

Skill Location in Prompts

The <location> element in <available_skills> follows the AgentSkills standard, allowing agents to read the full skill content on demand. When a triggered skill is activated, the content is injected with the location path:
This enables skills to reference their own scripts and resources using relative paths like ./scripts/encrypt.sh.

Example Skill: ROT13 Encryption

Here’s a skill with triggers (OpenHands extension): SKILL.md:
scripts/encrypt.sh:
When the user says “encrypt”, the skill is triggered and the agent can use the provided script.

Loading Public Skills

OpenHands maintains a public skills repository with community-contributed skills. You can automatically load these skills without waiting for SDK updates.

Automatic Loading via AgentContext

Enable public skills loading in your AgentContext:
When enabled, the SDK will:
  1. Clone or update the public skills repository to ~/.openhands/cache/skills/ on first run
  2. Load all available skills from the repository
  3. Merge them with your explicitly defined skills

Skill Naming and Triggers

Skill Precedence by Name: If a skill name conflicts, your explicitly defined skills take precedence over public skills. For example, if you define a skill named code-review, the public code-review skill will be skipped entirely. Multiple Skills with Same Trigger: Skills with different names but the same trigger can coexist and will ALL be activated when the trigger matches. To add project-specific guidelines alongside public skills, use a unique name (e.g., custom-codereview-guide instead of code-review). Both skills will be triggered together.
Skill Activation Behavior: When multiple skills share a trigger, all matching skills are loaded. Content is concatenated into the agent’s context with public skills first, then explicitly defined skills. There is no smart merging—if guidelines conflict, the agent sees both.

Programmatic Loading

You can also load public skills manually and have more control:

Custom Skills Repository

You can load skills from your own repository:

How It Works

The load_public_skills() function uses git-based caching for efficiency:
  • First run: Clones the skills repository to ~/.openhands/cache/skills/public-skills/
  • Subsequent runs: Pulls the latest changes to keep skills up-to-date
  • Offline mode: Uses the cached version if network is unavailable
This approach is more efficient than fetching individual skill files via HTTP and ensures you always have access to the latest community skills.
Explore available public skills at github.com/OpenHands/extensions. These skills cover various domains like GitHub integration, Python development, debugging, and more.

Customizing Agent Context

Message Suffixes

Append custom instructions to the system prompt or user messages via AgentContext:
  • system_message_suffix: Appended to system prompt (always active, combined with repo skills)
  • user_message_suffix: Appended to each user message

Replacing the Entire System Prompt

For complete control, provide a custom Jinja2 template via the Agent class:
Custom template example (custom_system_prompt.j2):
Key points:
  • Use relative filenames (e.g., "system_prompt.j2") to load from the agent’s prompts directory
  • Use absolute paths (e.g., "/path/to/prompt.j2") to load from any location
  • Pass variables to the template via system_prompt_kwargs
  • The system_message_suffix from AgentContext is automatically appended after your custom prompt

Dynamic Command Execution

Skills support inline shell command execution for injecting dynamic context at render time. This is useful for including repository state, environment information, or computed values in skill content.
Security: Commands execute with full shell privileges. Only use this feature with trusted skill sources. User-provided content should never be passed to command execution.

Basic Syntax

Use !`command` to execute a shell command and replace it with stdout:
When triggered, the skill content becomes:

Safety Rules

Code blocks are never executed. Both fenced and inline code blocks are preserved:
Unclosed fenced blocks protect trailing content. If a fenced block isn’t closed (odd number of ``` delimiters), everything after it is treated as inside the fence:

Escape Syntax

Use \!`cmd` to output the literal text !`cmd` without execution:
Output:

Error Handling

Failed commands return inline error markers:

Programmatic Rendering

When using skills programmatically, call render_content() to execute commands:
The working_dir parameter sets the current directory for command execution, enabling workspace-relative commands like git status.

Migrating from Legacy to AgentSkills Format

If you have legacy inline skills consuming many tokens, convert them to AgentSkills format for progressive disclosure:

Before (Legacy Format)

After (AgentSkills Format)

Create a directory api-guidelines/SKILL.md:
Then load it:

Benefits

Next Steps