Skip to content
Merged
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
65 changes: 55 additions & 10 deletions .agents/skills/code-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,23 @@ multiple source-of-truth codebases. Accuracy is critical.

## Source Code Verification (Required for SDK/CLI/App docs)

When reviewing documentation that references APIs, function signatures, class names, or code examples
from an upstream repository, you **MUST** clone the corresponding repository and verify the documentation
against the actual source code. Do not trust that code examples or API descriptions are accurate without
checking.
When reviewing documentation that references APIs, function signatures, class names, code examples,
or behavioral descriptions from an upstream repository, you **MUST** clone the corresponding repository
and verify the documentation against the actual source code. Do not trust that code examples or API
descriptions are accurate without checking.

### Repositories to clone for verification
**Every review comment and every approval MUST include evidence from the source code.** For each
documentation claim you verify (or flag as incorrect), provide a direct GitHub permalink to the
relevant source file and line(s). A review that simply says "looks good" without citing source
code is incomplete.

| Documentation path | Source repository |
|--------------------|-------------------|
| `sdk/` | `OpenHands/software-agent-sdk` |
| `openhands/` | `OpenHands/OpenHands` |
| CLI-related docs | `OpenHands/OpenHands-CLI` |
### Repositories to clone for verification

| Documentation path | Source repository | GitHub base URL |
|--------------------|-------------------|-----------------|
| `sdk/` | `OpenHands/software-agent-sdk` | `https://github.com/OpenHands/software-agent-sdk` |
| `openhands/` | `OpenHands/OpenHands` | `https://github.com/OpenHands/OpenHands` |
| CLI-related docs | `OpenHands/OpenHands-CLI` | `https://github.com/OpenHands/OpenHands-CLI` |

### Prefer upstream PR branches when linked

Expand All @@ -42,6 +46,7 @@ It's OK to approve a docs/ PR on the basis of a linked upstream PR, they will be
- **Field/attribute names** on data classes and models are correct
- **Supported values** (e.g., format strings like `"github:owner/repo"`) are actually handled in code
- **Behavioral descriptions** match the implementation logic
- **Prompt/context descriptions** distinguish between initial injection/construction, conversation-history inclusion, LLM context, and actual request transport. Flag ambiguous wording such as “sent with each request” unless the docs are intentionally describing transport-level behavior.
- **Example code** would actually run without errors

### How to verify
Expand All @@ -58,6 +63,46 @@ git clone --depth=1 https://github.com/OpenHands/software-agent-sdk.git /tmp/age
grep -rn "function_name" /tmp/agent-sdk/
```

### Providing evidence in review comments (Required)

For **every** documentation change that describes code behavior, APIs, or implementation details,
your review MUST include a link to the corresponding source code as evidence. Use GitHub permalinks
(with commit SHA or branch) so links remain stable.

**Format for inline review comments:**

When commenting on a specific line or section of the documentation, include evidence like:

```
✅ Verified: `is_agentskills_format` field exists on the Skill class.
→ Source: https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context.py#L42

🔴 Incorrect: The docs say `trigger=None` causes injection into `<REPO_CONTEXT>`, but the code
shows it injects into `<EXTRA_INFO>`.
→ Source: https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/agent.py#L150-L165
```

**Format for the overall review body:**

Include a "Source Verification" section that lists the key claims verified and their evidence:

```
## Source Verification

| Documentation Claim | Verified? | Source Evidence |
|---------------------|-----------|-----------------|
| Legacy skills with `trigger=None` are included in the initial system prompt and remain in LLM context for subsequent turns | ✅ | [agent.py#L150](permalink) |
| `load_skills_from_dir()` returns tuple of (skills, repo_skills) | ✅ | [context.py#L85](permalink) |
| AgentSkills format uses progressive disclosure | ❌ Incorrect | [agent.py#L200](permalink) shows... |
```

If you cannot find source code to verify a documentation claim, explicitly flag it:

```
⚠️ Unverified: Could not find source code for the claimed behavior of "X".
This should be verified before merging.
```

## Review Decisions

You **must** use the correct GitHub review `event` value when submitting your review.
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ Workflow: `.github/workflows/sync-agent-sdk-openapi.yml`
- Follow the style rules in `openhands/DOC_STYLE_GUIDE.md`.
- Use Mintlify components (`<Note>`, `<Warning>`, `<Tabs>`, etc.) where appropriate.
- When linking internally, prefer **absolute** doc paths (e.g. `/overview/quickstart`).
- When documenting prompt/context behavior, avoid ambiguous transport phrasing like “sent with each request” unless discussing the actual API transport. Prefer precise wording such as “included in the initial system prompt” and “remains part of the conversation/LLM context for subsequent turns.”
- Cloud integration docs live under `openhands/usage/cloud/`, and pages surfaced in **Documentation → Integrations → Cloud API** must also be added to the `Cloud API` group in `docs.json`.

### Mintlify tab ownership
Expand Down
118 changes: 115 additions & 3 deletions sdk/guides/skill.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,57 @@

OpenHands supports an **extended version** of the [AgentSkills standard](https://agentskills.io/specification) 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:

| Skill Format | Trigger | Where Content Appears | Model Mediated? |
|--------------|---------|----------------------|-----------------|
| **AgentSkills** (`SKILL.md`) | Any | `<available_skills>` (description only) | ✅ Yes — agent calls `invoke_skill()` |
| **AgentSkills** (`SKILL.md`) | Has triggers | `<available_skills>` + auto-inject on match | ✅ Yes |
| **Legacy** (inline/`*.md`) | `None` | **`<REPO_CONTEXT>` (full content in the initial system prompt; included in LLM context for each turn)** | ❌ No |
| **Legacy** (inline/`*.md`) | Has triggers | `<available_skills>` + auto-inject on match | ✅ Yes |

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

### Prompt Structure

Skills appear in different parts of the system prompt:

```xml icon="file"
<!-- System Prompt Structure -->

<REPO_CONTEXT>
<!-- Legacy trigger=None skills: FULL content in the initial system prompt;
included in LLM context for each turn while retained in history -->
[BEGIN context from [agents]]
... AGENTS.md content ...
[END Context]
</REPO_CONTEXT>

<SKILLS>
<available_skills>
<!-- AgentSkills + legacy with triggers: description only -->
<skill>
<name>github</name>
<description>Interact with GitHub...</description>
</skill>
</available_skills>
</SKILLS>
```

When a trigger matches, content is injected into the **user message**:

```xml icon="file"
<EXTRA_INFO>
The following information has been included based on a keyword match for "github".
Skill location: /path/to/skill
... skill content ...
</EXTRA_INFO>
```

## Context Loading Methods

| Method | When Content Loads | Use Case |
Expand All @@ -30,7 +81,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 84 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L84

Did you really mean 'agent_context'?
```

### Option 2: Inline Skill (Code-defined)
Expand All @@ -50,6 +101,10 @@
)
```

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

## Trigger-Loaded Context

Content injected when keywords appear in user messages. See [Keyword-Triggered Skills](/overview/skills/keyword).
Expand Down Expand Up @@ -572,7 +627,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 630 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L630

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

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L639

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 +689,7 @@

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

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L692

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

### `SKILL.md` Format

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

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L701

Did you really mean 'frontmatter'?

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

#### Frontmatter Fields

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L723

Did you really mean 'Frontmatter'?

| Field | Required | Description |
|-------|----------|-------------|
Expand Down Expand Up @@ -833,12 +888,18 @@
```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 891 in sdk/guides/skill.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L891

Did you really mean 'repo_skills'?

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L891

Did you really mean 'knowledge_skills'?

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L891

Did you really mean 'agent_skills'?
```

- **repo_skills**: Skills from `repo.md` files (always active)
- **knowledge_skills**: Skills from `knowledge/` subdirectories
- **agent_skills**: Skills from `SKILL.md` files (AgentSkills standard)
| Return Value | Source Files | Injection Behavior |
|--------------|--------------|-------------------|
| **repo_skills** | `repo.md`, `AGENTS.md`, `.cursorrules` | Full content in `<REPO_CONTEXT>` in the initial system prompt; included in LLM context for each turn |
| **knowledge_skills** | `knowledge/` subdirectories, `*.md` with triggers | Listed in `<available_skills>`, auto-inject on trigger |
| **agent_skills** | `SKILL.md` files (AgentSkills standard) | Listed in `<available_skills>`, agent calls `invoke_skill()` |

<Tip>
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](#skill-injection-behavior).
</Tip>

#### `discover_skill_resources()`

Expand Down Expand Up @@ -913,7 +974,7 @@
Enable public skills loading in your `AgentContext`:

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

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L977

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 +1039,7 @@
from openhands.sdk.context.skills import load_public_skills

# Load from a custom repository
custom_skills = load_public_skills(

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L1042

Did you really mean 'custom_skills'?
repo_url="https://github.com/my-org/my-skills",
branch="main"
)
Expand Down Expand Up @@ -1145,8 +1206,8 @@

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

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L1209

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

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

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/skill.mdx#L1210

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

### Programmatic Rendering
Expand All @@ -1165,6 +1226,57 @@

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)

```python icon="python"
# Legacy: Full content in <REPO_CONTEXT> in the initial system prompt
Skill(
name="api-guidelines",
content="""
# API Guidelines
... 2000 lines of detailed documentation ...
""",
trigger=None, # Always-on context - affects token usage on each turn!
)
```

### After (AgentSkills Format)

Create a directory `api-guidelines/SKILL.md`:

```markdown icon="markdown"
---
name: api-guidelines
description: Comprehensive API design guidelines for the project. Invoke when designing or reviewing API endpoints.
---

# API Guidelines

... 2000 lines of detailed documentation ...
```

Then load it:

```python icon="python"
from openhands.sdk.skills import load_skills_from_dir

# AgentSkills: Only description in prompt, agent reads full content on demand
_, _, skills = load_skills_from_dir("/path/to/skills")
agent_context = AgentContext(skills=list(skills.values()))
```

### Benefits

| Aspect | Legacy `trigger=None` | AgentSkills `SKILL.md` |
|--------|----------------------|------------------------|
| Token usage | Full content in system prompt; included in LLM context for each turn | Description only (~100 chars) |
| Model control | None — always present | Agent decides when to read |
| Scalability | Limited by context window | Many skills without token bloat |

## Next Steps

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