feat: add configurable marketplace_path setting for public skills loading#2253
feat: add configurable marketplace_path setting for public skills loading#2253
Conversation
API breakage checks (Griffe)Result: Passed |
Agent server REST API breakage checks (OpenAPI)Result: Failed Log excerpt (first 1000 characters) |
Coverage Report •
|
||||||||||||||||||||||||||||||||||||||||
all-hands-bot
left a comment
There was a problem hiding this comment.
🟡 Acceptable - Works but significant complexity concerns
This PR adds marketplace path configuration, but the implementation introduces substantial complexity that may not be justified by the use case. The core functionality works, but there are important questions about design choices and breaking changes.
Key concerns:
- 🟠 Cache directory rename breaks existing installations
- 🟠
load_public_skills()function complexity increased significantly - 🟡 Cross-repo marketplace loading - unclear if this solves a real problem
- 🟡 Multiple helper functions for parsing different path formats
Questions:
- What is the actual use case for cross-repo marketplace references?
- Is the added complexity (cross-repo loading, multiple cache management) solving a real problem or a theoretical one?
See inline comments for specific issues.
|
@OpenHands Do a /codereview-roasted on this PR. Note that we know and intend the change in public skills location, it’s FINE, ignore that one. Post your review as a top-level comment to the PR. |
|
I'm on it! enyst can track my progress at all-hands.dev |
|
/codereview-roasted (ignoring the intended public-skills location change) Taste Rating🔴 Needs improvement [CRITICAL ISSUES]
[IMPROVEMENT OPPORTUNITIES]
[TESTING GAPS]
VERDICT❌ Needs rework before this is safe to merge. The feature goal is fine; the current “name vs source” ambiguity is not. KEY INSIGHT: you added a second identifier ( |
|
I retrieved PR #2253’s metadata and diff via the GitHub CLI, then performed a /codereview-roasted focusing on correctness, breakage risk, complexity, and test coverage (while explicitly ignoring the intended “public skills location” change per your instruction). I posted the review as a top-level comment on the PR. During posting, my first attempt got mangled by shell interpolation (backticks/ Top-level review comment link: |
all-hands-bot
left a comment
There was a problem hiding this comment.
🟡 Acceptable - Core functionality works, but extracting unused data violates good taste.
Key Insight: The marketplace source field is extracted but never used anywhere—both call sites immediately discard it. Either use it or don't extract it.
Review Decision: COMMENT (not APPROVE) because:
- Changes skill loading behavior (per eval/benchmark risk policy)
- Unnecessary complexity in data extraction
- PR is marked DRAFT
|
📁 PR Artifacts Notice This PR contains a
|
38ff8b7 to
19f6839
Compare
all-hands-bot
left a comment
There was a problem hiding this comment.
🟡 Acceptable - Code works, but use case unclear
Assessment: The code is technically sound after previous simplification rounds. Earlier complexity issues (cross-repo loading, unused data extraction) have been properly addressed.
Key Observations:
-
Pragmatism Question: The PR exposes
marketplace_pathas configurable but doesn't explain what real problem this solves. Is this for actual user requests, internal OpenHands workflows, or theoretical flexibility? Adding configurability without a concrete use case goes against the "solve real problems" principle. -
Breaking Change: Cache directory rename (
public-skills→openhands-extensions) is acknowledged and acceptable per resolved threads. -
Implementation: The simplified version is clean:
- Helper functions are reasonable extractions
- Return type change from
set[str]tolist[str]preserves marketplace order (good choice) - Test coverage adequate
Review Decision: 💬 COMMENT (not APPROVE) because:
- PR changes skill loading behavior (falls under eval/benchmark risk policy)
- PR is marked DRAFT
- Use case justification unclear
Recommendation: Before merging, clarify the use case in the PR description and run lightweight evals to ensure no regression in agent behavior.
KEY INSIGHT: Technically solid implementation, but needs clearer motivation for why this configurability is necessary.
|
Addressed some review concerns! |
all-hands-bot
left a comment
There was a problem hiding this comment.
🟡 Acceptable - Core functionality works after simplification rounds. One minor style issue in .pr/ artifacts.
Review Decision: COMMENT per eval/benchmark policy - this changes skill loading behavior (filters which skills are loaded into agent context). A human maintainer should verify with lightweight evals before merging.
Key Observations:
- ✅ Solves real use case (neubig/workflow multi-repo pattern)
- ✅ Helper functions are reasonable extractions
- ✅ Good test coverage for new parameter
⚠️ Minor:.pr/demo script usessys.path.inserthack (acceptable for temporary artifacts)
Verdict: Worth merging pending eval verification.
all-hands-bot
left a comment
There was a problem hiding this comment.
🟡 Acceptable - Implementation is solid after review rounds, but has one blocking issue (breaking API change without deprecation) and requires eval verification per policy.
enyst
left a comment
There was a problem hiding this comment.
OpenHands-GPT-5.2 here.
Style and Formatting
- No issues.
Clarity and Readability
- No issues.
Security and Common Bug Patterns
- No issues.
Testing and Behavior Verification
[openhands-sdk/openhands/sdk/context/skills/skill.py, Lines 1012–1104] 🧪 The PR advertises Claude Code compatibility for plugins[], but _load_skill_from_source only checks for SKILL.md at the plugin root (or <name>.md). Standard Claude plugin layouts keep skills under skills/<skill>/SKILL.md, so plugin entries that point at plugin roots will load zero skills. Either load skills via load_skills_from_dir/plugin manifest or clarify that plugins[] entries must point directly at skill directories. A test covering a plugin with skills/ layout would catch this.
|
@OpenHands Understand this PR and look at this comment #2253 (review) Read agentskills.io spec and the claude code plugin spec, to understand the context we want to keep. Also, find the latest issue posted by xingyaoww and closed, about plugins and skills, and read it in full. Then analyze the behavior of this PR and tell us what it does and how it does it. Take a deep breath and publish it as a review using gh api (not as a comment, as a review it's allowed) |
|
I'm on it! enyst can track my progress at all-hands.dev |
enyst
left a comment
There was a problem hiding this comment.
Review — behavior vs specs
What this PR does
- Introduces a configurable
marketplace(URL/path) that replaces the oldrepo_url/branchinputs forload_public_skills, with a newDEFAULT_MARKETPLACEpointing tohttps://raw.githubusercontent.com/OpenHands/extensions/main/marketplaces/default.json. - Updates AgentContext + agent-server skill loading to thread that
marketplacevalue through (load_available_skills(..., marketplace=...)). - Extends the marketplace schema with an OpenHands-only
skills[]array andmetadata.skillRoot, alongside Claude Code–compatibleplugins[]andmetadata.pluginRoot. - Changes cached repo naming from a fixed
public-skills/to a derivedowner-repo/(e.g.,openhands-extensions/), causing a one-time re-clone. - Makes
sync_public_skillsa no-op (skills are fetched on demand).
AgentSkills spec alignment (agentskills.io)
- ✅ AgentSkills expects each skill to be a directory containing SKILL.md, with optional
scripts/,references/, andassets/. The newskills[]loader treats each entry as a skill directory and loadsSKILL.mdfrom that path, which matches the spec and keeps the progressive disclosure model intact. - ✅
skillRootmatches the idea of a canonical skills directory; relative skill paths are resolved under it.
Claude Code plugin marketplace spec alignment (code.claude.com)
- ✅
metadata.pluginRootis supported and applied to relative pluginsourcepaths. ⚠️ Plugin layout mismatch: Claude Code’s marketplace examples show plugins withskills/<skill>/SKILL.mdunder the plugin root. This PR’s plugin loader path (_load_skill_from_source) only checks forSKILL.mddirectly at the plugin root (or<name>.md), and does not traverseskills/within the plugin. As a result, a standard Claude Code plugin entry (source: ./plugins/review-plugin) yields zero skills unless the plugin is “flat” (root-level SKILL.md) or the marketplacesourcepoints directly at a skill subdirectory.- This mirrors the earlier review note: plugin entries that follow the official Claude Code layout won’t load any skills in this PR.
Related closed issue (#2272 by xingyaoww)
- The issue identifies that root-level SKILL.md in
anthropics/skillsisn’t discovered by the plugin loader (it only scansskills/). - This PR’s marketplace loading path does check the plugin root for
SKILL.md, so marketplace-based loading would work for a flat skill. However, it does not change the actual plugin loader (Plugin.get_all_skills), so the issue remains unsolved for installed plugins—and it still doesn’t handle the canonicalskills/<skill>/SKILL.mdlayout.
Behavioral details (important edge cases)
- Raw GitHub URLs are parsed and cloned to enable relative
sourcepaths to resolve, aligning with Claude’s warning that relative paths only work with git-based marketplaces. - For non-GitHub HTTP URLs, the code fetches only the JSON (no repo clone). Relative
sourcestrings therefore fail (base_dir=None), again matching Claude’s “URL-based marketplaces can’t resolve relative paths.”
Potential follow-ups
- If Claude Code compatibility for
plugins[]is a goal, the loader should either:- scan
plugin_root/skills/**/SKILL.md(similar toload_skills_from_dir), or - instantiate the plugin and call its
_load_skills(which already knows theskills/layout).
- scan
- Consider a test that uses the official plugin layout (
plugins/<plugin>/skills/<skill>/SKILL.md) to guard against regressions. - The PR description mentions
marketplace_path, but the actual API ismarketplace— worth reconciling to avoid confusion.
Overall, the skills[] extension aligns well with AgentSkills, but Claude Code plugin compatibility is currently partial because the loader assumes a flat SKILL.md under each plugin source rather than skills/<skill>/.
This comment was marked as duplicate.
This comment was marked as duplicate.
|
I'm sorry, I'm going to work on this more. |
|
Moved to draft - merge conflicts This PR has merge conflicts (mergeable=false). Please rebase or merge from main to resolve. Also missing: Conversation verification link in Evidence section. |
all-hands-bot
left a comment
There was a problem hiding this comment.
🟡 Acceptable - Pragmatic solution after multiple simplification rounds. Requires human eval verification per policy.
Taste Rating: This PR solves a real problem (custom marketplace support for multi-repo patterns). Previous iterations removed cross-repo complexity and over-engineering, which is good. Current implementation is straightforward.
Key Insight: The marketplace abstraction cleanly separates "what to load" (marketplace JSON) from "where to load from" (repo cloning), eliminating the need for complex cross-repo logic.
Review Decision: COMMENT per eval/benchmark policy - this changes skill loading behavior (which skills are loaded and how they are resolved). A human maintainer should verify with lightweight evals before merging.
openhands-agent-server/openhands/agent_server/skills_service.py
Outdated
Show resolved
Hide resolved
Co-authored-by: openhands <openhands@all-hands.dev>
a4e82a5 to
4170cca
Compare
Summary
Adds the remaining
marketplace_pathplumbing needed to control which marketplace is used when loading public skills.Closes #2297
Details
Overlap audit against
mainA separate PR already landed the mixed-marketplace example and
Marketplace.skills[]support onmain, so this PR was reduced to the still-missing pieces only:AgentContext.marketplace_pathload_available_skills(..., marketplace_path=...)load_public_skills(..., marketplace_path=...)/skillsrequest plumbing formarketplace_pathBehavior
marketplaces/default.jsonmarketplaces/custom.jsonNoneto load all public skills without marketplace filteringTesting
Result:
Evidence
Verification link: View conversation
Live marketplace-path demo against a temporary git repo:
This shows the branch's behavior directly:
marketplace_path=Noneloads all public skills from the same repositoryChecklist
mainaudited and redundant scope removed