OpenHands / OpenHands/software-agent-sdk
[Bug]: Skills marketplace returns empty against the current extensions manifest layout
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 539
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 137
Description
Bug Description
The skills marketplace loader checks for marketplaces/default.json and returns [] if it is absent before attempting manifest discovery (openhands-agent-server/openhands/agent_server/skills_service.py:706-738).
The current OpenHands/extensions repository uses .plugin/marketplace.json; its marketplaces/ directory contains large-codebase.json and openhands-extensions.json, not default.json. The plugin marketplace loader already handles this correctly by calling Marketplace.load(repo_path) first (plugins_service.py:331-357).
As a result, a cold /skills/marketplace load can be blank while /plugins/marketplace loads the same repository successfully. The skills path also caches empty failures for the full TTL, while the plugin path deliberately does not.
Expected Behavior
Skills and plugins should derive their views from the same successfully fetched and parsed marketplace snapshot, using manifest discovery first and the explicit path only as fallback.
Actual Behavior
An independent, self-contained reproducer is posted in the issue comments. Save
it as /tmp/repro_4665.py, then run:
git clone --depth 1 https://github.com/OpenHands/extensions.git /tmp/openhands-extensions-repro-4665
uv run python /tmp/repro_4665.py
On SDK commit bc5dfc50d, it exercises a fresh real OpenHands/extensions clone at 39fc25a, the actual Git cache, Marketplace loader, skills service, and filesystem; no mocks and prints:
manifest_plugins=64
default_marketplace_exists=False
service_catalog_entries=0
Suggested Implementation
Add one small shared marketplace snapshot loader/cache backed by Marketplace.load. Fetch/parse once, cache only successful snapshots, and let skills/plugins derive their distinct response shapes while computing installation state fresh.
Acceptance Criteria
- Skills load from the real
.plugin/marketplace.jsonlayout whenmarketplaces/default.jsonis absent. - Custom explicit marketplace paths remain supported as fallback.
- Skills and plugins within the TTL use the same fetched/parsed snapshot.
- Transient fetch/parse failures do not cache an empty catalog.
- Existing plugin-over-skill name precedence, plugin filtering, installed-state freshness, and REST schemas remain unchanged.
Version
Current main at 6d3881035. Repository layout was independently verified through the GitHub API on 2026-08-27; existing issue search found no duplicate.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the skills marketplace path in openhands-agent-server/openhands/agent_server/skills_service.py:706-738 and compare it with the Marketplace.load flow in plugins_service.py:331-357. Run /tmp/repro_4665.py against a fresh OpenHands/extensions clone to reproduce the empty skills catalog. Done means both services use the current manifest layout, preserve their response behavior, share successful snapshots within the TTL, and do not cache transient empty failures.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100