Repository navigation
feat(installer): public Python API for the bundled catalogue and skill folders - #6
Conversation
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
- bundle.catalog(), bundle.skills_dirs(), bundle.CATALOG_FORMAT over the bundled plugins; real folders also from a zip import - bundle.fetch(ref="stable"): opt-in snapshot of a repository ref, pinned to a commit, cached, checked (safe extraction, valid manifests), FetchError on any failure; the only network use, never from the installer's commands - one catalogue builder (_catalog.py) for the wheel's build hook and fetch(); catalog.json gains "format": 1 and each entry its robotframework range - py.typed; README "Python API" with the compatibility promise; changelog - CI test job gets uv so the wheel tests run Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
Skill Evaluation: rf-mobile (narrow, treatment, N=3, deepseek/deepseek-v4.1-flash)Model: OpenRouter spend
Gaterf-skill-eval reportRuns: 3 · pass: 3 · fail: 0 · incomplete: 0 · skipped checks: 0 · estimated cost (OpenRouter list prices): $0.09 Pass rate = runs whose gate result is Tasks
Skills
Skipped / errored checksNone. Incomplete runsNone. Process checks (treatment arm, not in deltas)
Adversarial tier (reported only, never gates)None. |
Skill Evaluation: rf-web (narrow, treatment, N=3, deepseek/deepseek-v4.1-flash)Model: OpenRouter spend
Gaterf-skill-eval reportRuns: 6 · pass: 6 · fail: 0 · incomplete: 0 · skipped checks: 0 · estimated cost (OpenRouter list prices): $0.13 Pass rate = runs whose gate result is Tasks
Skills
Skipped / errored checksNone. Incomplete runsNone. Process checks (treatment arm, not in deltas)
Adversarial tier (reported only, never gates)None. |
Skill Evaluation: rf-api (narrow, treatment, N=3, deepseek/deepseek-v4.1-flash)Model: OpenRouter spend
Gaterf-skill-eval reportRuns: 6 · pass: 6 · fail: 0 · incomplete: 0 · skipped checks: 0 · estimated cost (OpenRouter list prices): $0.22 · turn-limit stops: 3 Pass rate = runs whose gate result is Tasks
Skills
Skipped / errored checksNone. Incomplete runsNone. Process checks (treatment arm, not in deltas)
Adversarial tier (reported only, never gates)None. |
Skill Evaluation: rf-desktop (narrow, treatment, N=3, deepseek/deepseek-v4.1-flash)Model: OpenRouter spend
Gaterf-skill-eval reportRuns: 3 · pass: 3 · fail: 0 · incomplete: 0 · skipped checks: 0 · estimated cost (OpenRouter list prices): $0.13 · turn-limit stops: 3 Pass rate = runs whose gate result is Tasks
Skills
Skipped / errored checksNone. Incomplete runsNone. Process checks (treatment arm, not in deltas)
Adversarial tier (reported only, never gates)None. |
Skill Evaluation: rf-core (narrow, treatment, N=3, deepseek/deepseek-v4.1-flash)Model: OpenRouter spend
Gaterf-skill-eval reportRuns: 36 · pass: 36 · fail: 0 · incomplete: 0 · skipped checks: 0 · estimated cost (OpenRouter list prices): $0.88 · turn-limit stops: 11 Pass rate = runs whose gate result is Tasks
Skills
Skipped / errored checksNone. Incomplete runsNone. Process checks (treatment arm, not in deltas)
Adversarial tier (reported only, never gates)None. |
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
Closes #5.
Summary
Adds a public Python API to
robotframework-plugins, so tools such as rf-mcp can depend on the package and serve the bundled skills without importing private modules.robotframework_plugins.bundle:CATALOG_FORMAT(1);catalog(): the bundled plugins, active and deprecated, as a new list on each call;skills_dirs():{plugin: Path}of each active, non-bundle plugin'sskills/folder,rf-corefirst.skills_dirs()paths are real folders for the life of the process. When the package is imported from a zip, the bundle is copied once to a temporary folder, removed at exit.bundle.fetch(ref="stable"), opt-in: the samecatalog()/skills_dirs()for a branch, tag or commit of this repository.catalog.yamlandplugin.json.FetchError, and nothing in a snapshot is run._catalog.py) for the wheel's build hook and forfetch().catalog.jsongains"format": 1, and each entry gains itsrobotframeworkrange, which the hook used to drop.py.typed;mainmeans;astral-sh/setup-uv. Without uv, the wheel tests, including the existingtest_wheel_contains_bundled_plugins, were skipped in CI.The OpenSpec change
public-bundle-api(proposal, specinstaller-python-api, design, tasks) is in the first commit.Issue #5 acceptance criteria
robotframework_plugins.bundlewithCATALOG_FORMAT,catalog()andskills_dirs()in__all___assets/catalog.jsoncarries"format": 1test_api_from_an_installed_wheelbuilds the wheel, installs it into a fresh venv and checks:skills_dirs()returns existing folders undersite-packages, each with*/SKILL.md;catalog();_assets.pyunchanged for the adapters;bundlewraps itrobotframework-plugins-v2026.11.0in November 2026 and approving thepypienvironmentTest plan
pytest tests --ignore=tests/eval: 819 passedpytest tests/installer: 274 passed, including the slow wheel and zip-import tests; the new tests also pass on Python 3.10pytest tests/installer/test_bundle_fetch.py -m networkagainst GitHub:fetch("main")returned commit 3756236 with rf-core, rf-api, rf-desktop, rf-mobile and rf-web;fetch()(stable) raised "ref 'stable' not found"build-catalog.py --check, docs voice🤖 Generated with Claude Code
https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP