Skip to content

feat(sdk/subagent): Support skills in file-based Agents#2260

Merged
VascoSch92 merged 5 commits intomainfrom
vasco/skills-subagent
Mar 4, 2026
Merged

feat(sdk/subagent): Support skills in file-based Agents#2260
VascoSch92 merged 5 commits intomainfrom
vasco/skills-subagent

Conversation

@VascoSch92
Copy link
Copy Markdown
Contributor

@VascoSch92 VascoSch92 commented Mar 2, 2026

Summary

(ref #2186)

  • Add skills field to AgentDefinition, allowing subagents to reference skills by name in markdown frontmatter (comma-separated or YAML list)
  • agent_definition_to_factory resolves skill names to Skill objects at factory creation time using load_project_skills and load_user_skills (project takes priority over user)
  • Refactor schema.py to extract frontmatter parsing into dedicated helpers (_extract_color, _extract_tools, _extract_skills) and promote KNOWN_FIELDS to a module-level constant

Example

  ---
  name: code-reviewer
  skills: code-review, linting
  tools:
    - file_editor
  ---

  You are a code review specialist.

Checklist

  • If the PR is changing/adding functionality, are there tests to reflect this?
  • If there is an example, have you run the example to make sure that it works?
  • If there are instructions on how to run the code, have you followed the instructions and made sure that it works?
  • If the feature is significant enough to require documentation, is there a PR open on the OpenHands/docs repository with the same branch name?
  • Is the github CI passing?

Agent Server images for this PR

GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.12-nodejs22 Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:5aa1d20-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-5aa1d20-python \
  ghcr.io/openhands/agent-server:5aa1d20-python

All tags pushed for this build

ghcr.io/openhands/agent-server:5aa1d20-golang-amd64
ghcr.io/openhands/agent-server:5aa1d20-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:5aa1d20-golang-arm64
ghcr.io/openhands/agent-server:5aa1d20-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:5aa1d20-java-amd64
ghcr.io/openhands/agent-server:5aa1d20-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:5aa1d20-java-arm64
ghcr.io/openhands/agent-server:5aa1d20-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:5aa1d20-python-amd64
ghcr.io/openhands/agent-server:5aa1d20-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-amd64
ghcr.io/openhands/agent-server:5aa1d20-python-arm64
ghcr.io/openhands/agent-server:5aa1d20-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-arm64
ghcr.io/openhands/agent-server:5aa1d20-golang
ghcr.io/openhands/agent-server:5aa1d20-java
ghcr.io/openhands/agent-server:5aa1d20-python

About Multi-Architecture Support

  • Each variant tag (e.g., 5aa1d20-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., 5aa1d20-python-amd64) are also available if needed

@VascoSch92 VascoSch92 requested a review from all-hands-bot March 2, 2026 18:09
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 2, 2026

API breakage checks (Griffe)

Result: Failed

Log excerpt (first 1000 characters)

============================================================
Checking openhands-sdk (openhands.sdk)
============================================================
Comparing openhands-sdk 1.11.5 against 1.11.4
::notice title=openhands-sdk API::Ignoring Field metadata-only change (non-breaking): load_public_skills
::notice title=openhands-sdk API::Ignoring Field metadata-only change (non-breaking): temperature
::warning file=openhands-sdk/openhands/sdk/llm/llm.py,line=196,title=LLM.top_p::Attribute value was changed: `Field(default=1.0, ge=0, le=1)` -> `Field(default=None, ge=0, le=1, description='Nucleus sampling parameter. Defaults to None (uses provider default). Set to a value between 0 and 1 to control diversity of outputs.')`
::error title=SemVer::Breaking changes detected (1); require at least minor version bump from 1.11.x, but new is 1.11.5

============================================================
Checking openhands-workspace (openhands.workspace)
============================

Action log

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 2, 2026

Agent server REST API breakage checks (OpenAPI)

Result: Passed

Action log

Copy link
Copy Markdown
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid engineering. Clean implementation with comprehensive tests. Eager skill resolution at factory creation time is the right design choice - fail fast rather than at runtime. No critical or important issues found. ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 2, 2026

Coverage

Coverage Report •
FileStmtsMissCoverMissing
openhands-agent-server/openhands/agent_server
   skills_service.py1333573%116, 150, 153–156, 159–161, 164–165, 168–172, 175–179, 181, 185–186, 188, 199–203, 336–337, 341–343
openhands-sdk/openhands/sdk/context
   agent_context.py125695%267–269, 298, 321, 327
openhands-sdk/openhands/sdk/context/skills
   skill.py4273492%91–92, 247–248, 434–440, 443, 532–535, 710–711, 805–806, 837–838, 895–896, 978, 1003, 1010–1011, 1052–1053, 1059–1060, 1066–1067
openhands-sdk/openhands/sdk/conversation/impl
   local_conversation.py3412193%282, 287, 315, 358, 376, 392, 454, 603–604, 607, 759, 767, 769, 780, 782–784, 809, 971, 978–979
openhands-sdk/openhands/sdk/subagent
   registry.py103694%76, 183–184, 188, 226–227
   schema.py57296%41, 54
TOTAL19570507074% 

@VascoSch92 VascoSch92 changed the title add skills to file-based agents feat(sdk/subagent): Support skills in file-based Agents Mar 2, 2026
@VascoSch92 VascoSch92 marked this pull request as ready for review March 2, 2026 18:21
Copy link
Copy Markdown
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Good taste. Eager skill resolution at factory creation time is the right design choice—fail fast with clear errors rather than runtime surprises. Clean refactoring, comprehensive tests, simple priority system (dict update FTW). Solid engineering. ✅

@VascoSch92
Copy link
Copy Markdown
Contributor Author

@enyst

The answer from my OH :-):

Currently user is loaded first and project overrides it. But the canonical order is user < project, 
meaning project should override user — which is actually what .update() does here. 
The precedence order is already correct: user skills go in first, then project skills override via .update().
                                                                                                                                                                                                                     Wait, let me re-read the comment — the comment says "project skills override user skills (user loaded first, project second)" which is accurate. The code matches the canonical user < project precedence.
                       
So the code and precedence are actually correct for the two sources it handles. 
There's nothing to fix here — the order already respects the canonical precedence. 
Did you have something specific in mind that looks wrong?      

For instance, I would prefer not to add public skills yet, as it isn't clear how we should load them (should we load everything or just the specific ones provided?). In any case, we can handle that later; it will only be a two-line change.

Is that okay with you?

@enyst
Copy link
Copy Markdown
Collaborator

enyst commented Mar 3, 2026

Thank you, sorry for the misunderstanding. I don't have an opinion on whether we should load public skills yet, I would just love to see that we (try to?) use the same behavior as we have for the main agent, unless we know it provably shouldn't apply.

I'm a bit uncertain if it should apply here... but the result seems weird? Why would the main agent not load skills by default (the flag is false), but the sub-agents will?

@VascoSch92
Copy link
Copy Markdown
Contributor Author

I'm a bit uncertain if it should apply here... but the result seems weird? Why would the main agent not load skills by default (the flag is false), but the sub-agents will?

Sorry, I really don't understand. Can you point me to where this is happening?

The priority order in resolving Skills is the same used in the SDK for the main agents. We just not load public & plugin skills (at least not yet)

@VascoSch92 VascoSch92 requested a review from all-hands-bot March 4, 2026 08:09
Copy link
Copy Markdown
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Good taste. Eager skill resolution at factory creation time is the right design choice—fail fast with clear errors rather than runtime surprises. The consolidation of skill loading into load_available_skills eliminates duplication while maintaining clear precedence (public → user → project via dict updates). Clean refactoring, comprehensive tests. Solid engineering. ✅

@VascoSch92
Copy link
Copy Markdown
Contributor Author

@enyst Refactored to centralized everything. Now the PR is doing a little bit too much things :-)

Copy link
Copy Markdown
Collaborator

@enyst enyst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I was wondering if it will look readable (hey, not all DRY does!), but IMHO it is much better. We were at the 3rd spot in the code with similar stuff happening 🫠

I left a little comment on defaults, because we’re trying, as much as possible, to have a clear public API without side-effects on user machine (ish) and so using the SDK directly should require the user to explicitly opt in those that have boolean flags. Otherwise LGTM, thank you!

@VascoSch92 VascoSch92 merged commit 3c2bce2 into main Mar 4, 2026
28 of 29 checks passed
@VascoSch92 VascoSch92 deleted the vasco/skills-subagent branch March 4, 2026 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants