OpenHands / OpenHands/software-agent-sdk

[Bug]: Skills marketplace returns empty against the current extensions manifest layout

Open
#4,665 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

architecture bug plugins priority:medium ready-for-dev skills
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.json layout when marketplaces/default.json is 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.