Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions sdk/arch/skill.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@

## Core Responsibilities

The Skill system has four primary responsibilities:
The Skill system has five primary responsibilities:

1. **Context Injection** - Add specialized prompts to agent context based on triggers
2. **Trigger Evaluation** - Determine when skills should activate (always, keyword, task)
3. **MCP Integration** - Load MCP tools associated with repository skills
4. **Third-Party Support** - Parse `.cursorrules`, `agents.md`, and other skill formats
3. **Dynamic Content Rendering** - Execute inline shell commands for dynamic context injection
4. **MCP Integration** - Load MCP tools associated with repository skills
5. **Third-Party Support** - Parse `.cursorrules`, `agents.md`, and other skill formats

## Architecture

Expand All @@ -35,6 +36,7 @@

subgraph Content["Skill Content"]
Markdown["Markdown with Frontmatter"]
Dynamic["Dynamic Commands<br><i>!`command` execution</i>"]
MCPTools["MCP Tools Config<br><i>Repo skills only</i>"]
Inputs["Input Metadata<br><i>Task skills only</i>"]
end
Expand All @@ -52,31 +54,36 @@
Keyword --> Markdown
TaskMatch --> Markdown

Markdown -.->|Optional| Dynamic
Repo -.->|Optional| MCPTools
Task -.->|Requires| Inputs

Markdown --> Context
Dynamic --> Context
MCPTools --> Context
Context --> Prompt

classDef primary fill:#f3e8ff,stroke:#7c3aed,stroke-width:2px
classDef secondary fill:#e8f3ff,stroke:#2b6cb0,stroke-width:2px
classDef tertiary fill:#fff4df,stroke:#b7791f,stroke-width:2px
classDef dynamic fill:#e9f9ef,stroke:#2f855a,stroke-width:2px

class Repo,Knowledge,Task primary
class Always,Keyword,TaskMatch secondary
class Context tertiary
class Dynamic dynamic
```

### Key Components

| Component | Purpose | Design |
|-----------|---------|--------|
| **[`Skill`](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context/skills/skill.py)** | Core skill model | Pydantic model with name, content, trigger |

Check warning on line 81 in sdk/arch/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/arch/skill.mdx#L81

Did you really mean 'Pydantic'?
| **[`KeywordTrigger`](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context/skills/trigger.py)** | Keyword-based activation | String matching on user messages |
| **[`TaskTrigger`](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context/skills/trigger.py)** | Task-based activation | Special type of KeywordTrigger for skills with user inputs |
| **[`InputMetadata`](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context/skills/types.py)** | Task input parameters | Defines user inputs for task skills |
| **[`render_content_with_commands`](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context/skills/execute.py)** | Dynamic content | Executes inline `!`command`` patterns |
| **Skill Loader** | File parsing | Reads markdown with frontmatter, validates schema |

Check warning on line 86 in sdk/arch/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/arch/skill.mdx#L86

Did you really mean 'frontmatter'?

## Skill Types

Expand Down Expand Up @@ -291,15 +298,36 @@
```

**Workflow:**
1. **Load Skill:** Parse markdown file with frontmatter

Check warning on line 301 in sdk/arch/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/arch/skill.mdx#L301

Did you really mean 'frontmatter'?
2. **Extract MCP Config:** Read `mcp_tools` field
3. **Spawn MCP Servers:** Create MCP clients for each server
4. **Register Tools:** Add MCP tools to agent's tool registry
5. **Inject Context:** Add skill content to agent prompt

## Dynamic Content Rendering

Skills support inline command execution for injecting dynamic context at render time:

1. Parse content for `` !`cmd` `` patterns outside code blocks
2. Execute each command via subprocess

Check warning on line 312 in sdk/arch/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/arch/skill.mdx#L312

Did you really mean 'subprocess'?
3. Replace pattern with stdout (or error marker)
4. Return rendered content

**Syntax:**
- `` !`command` `` - Executes command and replaces with stdout
- `` \!`command` `` - Escapes to literal `` !`command` `` text
- Fenced (```) and inline (`) code blocks are never executed

**Safety:**
- Unclosed fenced blocks (odd ``` count) extend to EOF, protecting trailing content
- Failed commands return `[Error: ...]` markers
- Output truncated at 50KB per command

See [Dynamic Command Execution](/sdk/guides/skill#dynamic-command-execution) for usage details.

## Skill File Format

Skills are defined in markdown files with YAML frontmatter:

Check warning on line 330 in sdk/arch/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/arch/skill.mdx#L330

Did you really mean 'frontmatter'?

```markdown
---
Expand All @@ -312,6 +340,7 @@
# Skill Content

This is the instruction text that will be added to the agent's context.
Dynamic values: !`git branch --show-current`

Check warning on line 343 in sdk/arch/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/arch/skill.mdx#L343

Did you really mean 'Frontmatter'?
```

**Frontmatter Fields:**
Expand Down
110 changes: 110 additions & 0 deletions sdk/guides/skill.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

# Automatically finds AGENTS.md, CLAUDE.md, GEMINI.md at workspace root
skills = load_project_skills(workspace_dir="/path/to/repo")
agent_context = AgentContext(skills=skills)

Check warning on line 33 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L33

Did you really mean 'agent_context'?
```

### Option 2: Inline Skill (Code-defined)
Expand Down Expand Up @@ -572,7 +572,7 @@
Skills are defined with a name, content (the instructions), and an optional trigger:

```python icon="python" focus={3-14}
agent_context = AgentContext(

Check warning on line 575 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L575

Did you really mean 'agent_context'?
skills=[
Skill(
name="AGENTS.md",
Expand All @@ -581,7 +581,7 @@
trigger=None, # Always active
),
Skill(
name="flarglebargle",

Check warning on line 584 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L584

Did you really mean 'flarglebargle'?
content='IMPORTANT! The user has said the magic word "flarglebargle". '
"You must only respond with a message telling them how smart they are",
trigger=KeywordTrigger(keywords=["flarglebargle"]),
Expand Down Expand Up @@ -634,7 +634,7 @@

| Component | Required | Description |
|-------|----------|-------------|
| `SKILL.md` | Yes | Skill definition with frontmatter |

Check warning on line 637 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L637

Did you really mean 'frontmatter'?
| `scripts/` | No | Executable scripts |
| `references/` | No | Reference documentation |
| `assets/` | No | Static assets |
Expand All @@ -643,7 +643,7 @@

### `SKILL.md` Format

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

Check warning on line 646 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L646

Did you really mean 'frontmatter'?

```md icon="markdown"
---
Expand All @@ -665,7 +665,7 @@
Instructions and documentation for the agent...
```

#### Frontmatter Fields

Check warning on line 668 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L668

Did you really mean 'Frontmatter'?

| Field | Required | Description |
|-------|----------|-------------|
Expand Down Expand Up @@ -833,7 +833,7 @@
```python icon="python" focus={3}
from openhands.sdk.context.skills import load_skills_from_dir

repo_skills, knowledge_skills, agent_skills = load_skills_from_dir(skills_dir)

Check warning on line 836 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L836

Did you really mean 'repo_skills'?

Check warning on line 836 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L836

Did you really mean 'knowledge_skills'?

Check warning on line 836 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L836

Did you really mean 'agent_skills'?
```

- **repo_skills**: Skills from `repo.md` files (always active)
Expand Down Expand Up @@ -913,7 +913,7 @@
Enable public skills loading in your `AgentContext`:

```python icon="python" focus={2}
agent_context = AgentContext(

Check warning on line 916 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L916

Did you really mean 'agent_context'?
load_public_skills=True, # Auto-load from public registry
skills=[
# Your custom skills here
Expand Down Expand Up @@ -978,7 +978,7 @@
from openhands.sdk.context.skills import load_public_skills

# Load from a custom repository
custom_skills = load_public_skills(

Check warning on line 981 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L981

Did you really mean 'custom_skills'?
repo_url="https://github.com/my-org/my-skills",
branch="main"
)
Expand Down Expand Up @@ -1055,6 +1055,116 @@
- 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.

<Warning>
**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.
</Warning>

### Basic Syntax

Use `` !`command` `` to execute a shell command and replace it with stdout:

```markdown icon="markdown"
---
name: repo-context
description: Injects current repository state
triggers:
- git
- commit
---

# Repository Context

Current branch: !`git branch --show-current`
Last commit: !`git log -1 --oneline`
```

When triggered, the skill content becomes:

```markdown icon="markdown"
# Repository Context

Current branch: main
Last commit: a1b2c3d Fix authentication bug
```

### Safety Rules

**Code blocks are never executed.** Both fenced and inline code blocks are preserved:

````markdown icon="markdown"
# Safe Examples

Regular inline code: `git status` → preserved as-is
Fenced block: → preserved as-is
```bash
!`echo "not executed"`
```

Dynamic command: !`echo "executed"` → replaced with "executed"
````

**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:

````markdown icon="markdown"
```bash
!`echo "inside fence - not executed"`
```

!`echo "between fences - executed"`

```bash
!`echo "unclosed fence - not executed"`
````

### Escape Syntax

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

```markdown icon="markdown"
# Documenting the Syntax

To execute a command, use \!`command` syntax.
For example: \!`git status` shows the current git state.
```

Output:
```markdown
# Documenting the Syntax

To execute a command, use !`command` syntax.
For example: !`git status` shows the current git state.
```

### Error Handling

Failed commands return inline error markers:

| Scenario | Output |
|----------|--------|
| Command fails | `[Error: Command `xyz` exited with code 1: error message]` |

Check warning on line 1148 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L1148

Did you really mean 'xyz'?
| Command times out | `[Error: Command `xyz` timed out after 10s]` |

Check warning on line 1149 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L1149

Did you really mean 'xyz'?
| Large output (>50KB) | Output truncated with `... [output truncated]` |

### Programmatic Rendering

When using skills programmatically, call `render_content()` to execute commands:

```python icon="python" focus={6-7}
from openhands.sdk.context import Skill

skill = Skill.load("/path/to/skill/SKILL.md")

# Render with command execution
rendered = skill.render_content(working_dir="/path/to/repo")
print(rendered) # Commands replaced with output
```

The `working_dir` parameter sets the current directory for command execution, enabling workspace-relative commands like `git status`.

## Next Steps

- **[Custom Tools](/sdk/guides/custom-tools)** - Create specialized tools
Expand Down
Loading