Skip to content

Launch the Robot Framework plugins programme - #1

Merged
manykarim merged 121 commits into
mainfrom
migrate/launch-programme
Nov 9, 2026
Merged

manykarim merged 121 commits into
mainfrom
migrate/launch-programme

Conversation

@manykarim

Copy link
Copy Markdown
Collaborator

Brings the repository to its launch state: the plugins split from rf-agentskills, the installer renamed to robotframework-plugins, and the programme around them (OpenSpec changes split-rf-agentskills and launch-plugin-programme).

What's in it

  • Plugins: rf-core, rf-web, rf-api, rf-mobile, rf-desktop (1.0.0) and the rf-agentskills bundle (4.0.0), with the marketplace and catalogue generated from each plugin's catalog.yaml.
  • Installer: robotframework-plugins 2026.11.0, a calendar-versioned continuation of rf-agentskills 0.8.0. The forwarding rf-agentskills 0.9.0 is in legacy/.
  • Security gate: the house content rules, and Cisco skill-scanner, SkillSpector, cc-audit and Gitleaks at pinned versions, compared with reviewed baselines in security/baselines/. The model-assisted deep scan runs only on the security-deep-scan label and on main.
  • Governance: CODEOWNERS, the required-reviews check, tiers and lifecycle checks, the PR template.
  • Docs: README, CONTRIBUTING, GOVERNANCE, SECURITY, RELEASING, and templates/plugin/.

Known before merge

  • The security gate fails until a security reviewer fills in reviewed_by on the baseline entries (task 5.3). This is deliberate.
  • required-reviews needs the two MarketSquare teams and the REVIEW_TEAMS_TOKEN secret (task 6.1).

🤖 Generated with Claude Code

https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP

manykarim and others added 30 commits January 13, 2026 10:44
Restructure the repository as a Claude Code plugin marketplace with a
single plugin (rf-agentskills) containing all 11 Robot Framework skills.
Includes marketplace/plugin manifests, 4 specialized agents, automated
hooks, MCP server, CI/CD workflows, tests, and validation scripts.

- Migrate and rename 11 skills into plugins/rf-agentskills/skills/
- Consolidate 5 Python scripts with ${CLAUDE_PLUGIN_ROOT} paths
- Add 4 agents (test-architect, debug-expert, keyword-consultant, migration-guide)
- Add hooks for .robot validation, skill routing, env checks
- Add marketplace.json and plugin.json manifests
- Add CI/CD workflows, pytest tests, and validate-marketplace.py
- Rewrite README with marketplace installation instructions

Co-Authored-By: claude-flow <ruv@ruv.net>
Co-Authored-By: claude-flow <ruv@ruv.net>
…ts, build infra

Critical fixes:
- MCP server _SCRIPT_PATHS pointed to non-existent paths (completely broken)
- MCP server sys.exit(1) in rf_results.py would crash server (SystemExit is BaseException)
- Removed vscode-extension/skills/skills/ double-nesting (148 duplicate files)

Script fixes (root skills/ = single source of truth):
- Added try/except ImportError guards to rf_libdoc.py and rf_results.py
- Changed sys.exit(1) to raise RuntimeError in rf_results.py
- Removed unused import re from testcase_builder.py
- Fixed _find_keyword dict indentation in rf_libdoc.py
- Synced all fixes to plugin and vscode-extension copies

MCP server rewrite:
- Fixed _SCRIPT_PATHS to use flat plugins/scripts/ directory
- Added module caching (no reload on every tool call)
- Refactored builder tools to call internal functions directly (no sys.argv hack)
- Added SystemExit handling in call_tool exception handler
- Removed unused _capture_stdout, tempfile, StringIO

Plugin improvements:
- Agent .md files: replaced bare python scripts/ paths with ${CLAUDE_PLUGIN_ROOT}
- Hooks: reduced UserPromptSubmit from ~1200 to ~60 tokens
- Hooks: fixed Stop hook to use ${CLAUDE_PLUGIN_ROOT} paths
- Library skills: added companion skills cross-reference table (10 SKILL.md files)

Build infrastructure:
- scripts/sync-skills.sh: syncs root skills/ to plugin and vscode channels
- scripts/check-drift.sh: validates no drift between distribution channels
- CI: added check-drift job to .github/workflows/ci.yml

Tests (21 -> 53):
- tests/test_testcase_builder.py (12 tests)
- tests/test_resource_architect.py (10 tests)
- tests/test_rf_results.py (9 tests)
- tests/test_drift_detection.py (1 test)

VS Code extension: restored source files (package.json, tsconfig.json,
src/extension.ts) from git history; skills/ now generated by sync-skills.sh

README.md rewritten with project structure, build/sync workflow, MCP tools,
and development instructions.

E2E tested with Codex CLI, Copilot CLI, and Claude CLI (22/22 pass).

Co-Authored-By: claude-flow <ruv@ruv.net>
The sync script now handles the full root -> plugin transformation:
- Rewrites name: field (long name -> short name)
- Rewrites script paths (relative -> ${CLAUDE_PLUGIN_ROOT}/scripts/)
- Rewrites companion skill references (long -> short names)
- Copies references/ and assets/ unchanged

Root skills/ is the single source of truth. Plugin and VS Code copies
are fully derived by running: bash scripts/sync-skills.sh

Co-Authored-By: claude-flow <ruv@ruv.net>
…v1.1.0

CI workflow rewritten with 7 jobs:
- test: Python 3.10/3.12/3.13 matrix, pytest (no more || true)
- lint: ruff on root scripts, plugin scripts, and MCP server
- validate-plugin: manifest and SKILL.md frontmatter checks
- validate-robot-syntax: parse all .robot example files
- check-drift: verify root/plugin script sync
- build-vscode-extension: compile TS, package VSIX, upload artifact
- build-claude-plugin: sync + validate + tar.gz, upload artifact
- build-portable-skills: standalone/codex/copilot packages, upload artifacts

Release workflow builds and attaches 5 artifacts to GitHub Release:
- robotframework-agentskills-{version}.vsix (VS Code + Copilot Chat)
- rf-agentskills-claude-plugin-{version}.tar.gz (Claude Code plugin)
- robotframework-skills-{version}.tar.gz (standalone, any agent)
- robotframework-skills-codex-{version}.tar.gz (.codex/skills/ layout)
- robotframework-skills-copilot-{version}.tar.gz (.github/skills/ layout)

Version bumped to 1.1.0 across VERSION, plugin.json, marketplace.json,
and package.json.

Co-Authored-By: claude-flow <ruv@ruv.net>
The release workflow calls CI as a reusable workflow via
`uses: ./.github/workflows/ci.yml`, which requires the
`workflow_call` trigger to be defined.

Co-Authored-By: claude-flow <ruv@ruv.net>
Co-Authored-By: claude-flow <ruv@ruv.net>
Rename SKILL.md name: fields from long form to rf-* prefix:
  /robotframework-browser-skill -> /rf-browser
  /robotframework-selenium-skill -> /rf-selenium
  /robotframework-appium-skill -> /rf-appium
  /robotframework-requests-skill -> /rf-requests
  /robotframework-restinstance-skill -> /rf-restinstance
  /robotframework-keyword-builder -> /rf-keyword-builder
  /robotframework-testcase-builder -> /rf-testcase-builder
  /robotframework-resource-architect -> /rf-resource-architect
  /robotframework-libdoc-search -> /rf-libdoc-search
  /robotframework-libdoc-explain -> /rf-libdoc-explain
  /robotframework-results -> /rf-results

The name: field in SKILL.md frontmatter is what VS Code Copilot,
Codex, Claude, and other agents use as the slash command. Shorter
names are more ergonomic (e.g., /rf-browser vs /robotframework-browser-skill).

Plugin channel keeps its own short names (browser, selenium, etc.)
via the sync-skills.sh transform.

Co-Authored-By: claude-flow <ruv@ruv.net>
The Agent Skills specification requires directory name == name: field.
sync-skills.sh now:
- Uses rf-* names as VS Code skill directory names (matching SKILL.md name:)
- Auto-updates package.json chatSkills paths to match
- Dereferences symlinks (vsce can't follow them across renamed dirs)

Before: vscode-extension/skills/robotframework-browser-skill/ (name: rf-browser) MISMATCH
After:  vscode-extension/skills/rf-browser/ (name: rf-browser) MATCH

Co-Authored-By: claude-flow <ruv@ruv.net>
Changes since v1.1.0:
- Shortened skill slash commands (rf-browser, rf-selenium, etc.)
- Fixed VS Code skill dir names to match name: field per Agent Skills spec
- Sync script now auto-updates package.json chatSkills paths
- Symlinks dereferenced for vsce compatibility

Co-Authored-By: claude-flow <ruv@ruv.net>
…, and rf-mcp session grading

Complete evaluation system for Robot Framework agent skills with:

- DDD-structured Python package (rf-skill-eval) managed by uv
- 6 ADRs covering dependency mgmt, bounded contexts, invocation strategy,
  scoring model, CI integration (OAuth + API key), result persistence
- 10 grader check types: 7 deterministic (file_exists, file_contains,
  robot_pass, no_deprecated_keywords, lint_clean, import_resolves,
  custom_python) + 3 session-based (tool_call_count, tool_result_count,
  tool_call_sequence)
- Workspace isolation: fixture staging, settings.json deny rules,
  prompt preamble with absolute path, post-run integrity check + cleanup
- 9 task YAMLs (7 narrow + 2 realistic) across with/without rf-mcp scenarios
- 2 fixture SUTs (sut-minimal, sut-browser)
- GitHub Actions workflow (3-tier: PR narrow, weekly canary, manual dispatch)
  with CLAUDE_CODE_OAUTH_TOKEN primary auth, concurrency cap, regression alerts
- Local pipeline scripts (eval-setup, eval-smoke, eval-local)
- Project .mcp.json registering rf-mcp for interactive Claude Code sessions
- 99 tests passing, ruff + mypy strict clean
- Live-validated with 5+ Haiku runs across 3 task types, all stable

Co-Authored-By: claude-flow <ruv@ruv.net>
The first CI dry-run revealed two structural gaps that made the harness
grade something other than what it claims to:

- The rf-agentskills plugin was never staged into the agent's runtime,
  so 6/7 "passing" tasks succeeded on raw model + rf-mcp ability rather
  than on the skill under test. The one task that explicitly required
  libdoc-search failed at turn 6 because the agent had to improvise.
- doctor accepted a CLAUDE_CODE_OAUTH_TOKEN with an embedded newline
  and let the workflow report success while every task aborted in 34ms
  with "API Error: Header has invalid value".

Changes:

- Runner: stage plugins/rf-agentskills/skills/<name>/ into both
  ${CLAUDE_CONFIG_DIR}/skills/<name>/ and <workspace>/.claude/skills/<name>/
  for resilience, and substitute ${CLAUDE_PLUGIN_ROOT} (which doesn't
  expand in personal/project skill bash blocks per Claude Code #9354)
  with the absolute path of the staged plugin copy.
- Runner: new plugin_root constructor arg defaults to
  <repo>/plugins/rf-agentskills.
- Doctor: probe auth with `claude --print "ok" --max-turns 1` and exit
  non-zero on API errors. Catches malformed tokens in seconds.
- Grader: optional input_pattern on tool_call_count regex-searches the
  JSON-serialized tool_input — lets tasks assert "Skill was invoked
  with skill=libdoc-search" or "Bash ran rf_libdoc.py".
- Task: narrow-libdoc-search-01 now allows the Skill tool, bumps
  max_turns 6 -> 10, and adds an invoked_libdoc_search_skill grader.

Co-Authored-By: claude-flow <ruv@ruv.net>
Guards against two regressions seen interactively with the rf-agentskills
plugin: the agent over-invoking RF tooling on prompts that have nothing
to do with Robot Framework, and hook/skill guidance pushing the agent
into a loop on simple tasks.

The task asks the agent to write a small JSON file. With max_turns=4
and timeout_seconds=60 a hooked loop blows past either bound. Negative
graders enforce zero rf-mcp calls and zero libdoc-search invocations
even though both are in allowed_tools and the skill is staged. A total
tool-call ceiling of 6 catches PostToolUse-style re-triggering.

Co-Authored-By: claude-flow <ruv@ruv.net>
Previous behavior provisioned only the skill referenced by the task,
which left every other plugin component (subagents, hooks, plugin-
defined MCP servers) inert. Session-init events showed plugins:[] —
the harness was grading "base model + one skill", not the actual
rf-agentskills plugin a user installs.

Treatment runs now stage the full plugin once into <config>/rf-
agentskills/ with ${CLAUDE_PLUGIN_ROOT} substituted across .md/.json
/.sh/.py/.txt files, then fan out to the locations Claude Code reads:

  - <config>/skills/<name>/         + <ws>/.claude/skills/<name>/
  - <config>/agents/<name>.md       + <ws>/.claude/agents/<name>.md
  - <config>/.mcp.json              -- merges plugin servers (rf-tools)
                                       alongside the harness-default
                                       rf-mcp via existing extra_servers
                                       hook in build_mcp_config
  - <config>/settings.json          -- hooks/hooks.json content wired
                                       in under the top-level "hooks"
                                       field (PostToolUse, UserPromptSubmit,
                                       SessionStart, Stop)

This matches what a user gets from a real plugin install, so the
narrow-non-rf-control-01 negative test now actually exercises hook
behavior on a non-RF prompt instead of trivially passing on a hookless
session. validate_robot.sh skips non-.robot/.resource files (exits 0)
so the JSON-authoring task should remain green.

Public-API change: _provision_skills no longer takes a Profile — it
copies *every* skill in the staged plugin. Gating moves up to execute()
which only calls _stage_plugin when profile.enabled_skills is non-empty.
Tests updated; 112/112 pass.

Co-Authored-By: claude-flow <ruv@ruv.net>
Symptoms from the previous CI run:

- Plugin skills + agents loaded correctly (visible in session-init).
- Hooks did NOT fire — stderr.log was 0 bytes, no validate_robot.sh or
  check_rf_environment.sh output, no hook events in the stream JSON.
- libdoc-search-01 regressed: agent picked the lookalike libdoc-explain
  skill, hit Claude Code's persisted-output threshold on the 60KB JSON,
  burned 11 turns trying to recover via bash/jq pipelines, and tripped
  max_turns=10.

Diagnosis:

- Claude Code 2.1.121 reads the `permissions` block from
  ${CLAUDE_CONFIG_DIR}/settings.json (we observed the deny rules being
  honoured) but does NOT activate the `hooks` block from the same file
  in headless `-p` mode without permission-mode override. The trust-
  prompt for project hooks never gets answered, so they silently no-op.
- actions/upload-artifact@v4 strips dotfiles by default, so .mcp.json
  and .claude/* were missing from artifacts even though they existed at
  runtime — confused the post-mortem.

Fixes:

- Pass --permission-mode bypassPermissions to claude. The workspace
  boundary is still enforced by the prompt preamble plus the post-run
  snapshot diff, so this does not weaken sandboxing.
- include-hidden-files: true on the artifact upload step.
- Bump narrow-libdoc-search-01 max_turns 10→14 to absorb skill-
  selection overhead now that 11 sibling skills are co-loaded; this
  is intentional headroom, not a workaround.

Co-Authored-By: claude-flow <ruv@ruv.net>
Headless Claude Code (-p mode) silently skips the hooks block from
\${CLAUDE_CONFIG_DIR}/settings.json even with bypassPermissions — only
the permissions block is honoured at user scope. The previous run
confirmed this empirically: settings.json was written with the full
hooks tree and substituted paths, but stderr.log stayed at 0 bytes
across all 8 tasks and zero hook events appeared in any session
transcript.

Project-scope settings.json (<workspace>/.claude/settings.json) is
read for hooks. With --permission-mode bypassPermissions in place,
project hooks fire without a trust prompt.

Split: user-scope file keeps permissions only (where it works), and
when hooks are present we also write a project-scope file containing
just {"hooks": ...}. No new public API.

Co-Authored-By: claude-flow <ruv@ruv.net>
The eval is supposed to catch hook/skill regressions in the
rf-agentskills plugin, and on the first run with the full plugin
active it did exactly that — Haiku no-ops on a plain JSON-authoring
prompt because the UserPromptSubmit hook biases every prompt toward
"is this an RF task?" reasoning.

Keep the test in its failing state so the signal stays visible. The
fix belongs in the plugin (conditional UserPromptSubmit on RF
triggers), not in the eval. Document both this regression and the
PostToolUse matcher issue in eval/tasks/README.md so future readers
understand why CI is red on this PR.

Co-Authored-By: claude-flow <ruv@ruv.net>
tests: add skill evaluation harness with CI pipeline
The previous static type:"prompt" hooks injected rf-agentskills
guidance into every prompt and every session-end. CI eval task
narrow-non-rf-control-01 caught the regression that produced: a
plain JSON-authoring prompt no-op'd because Haiku read the static
"if RF, load skill" injection as a permission gate ("is this RF?"
-> no -> done), produced 93 tokens of text, and exited with zero
tool calls.

Fix: convert both hooks to type:"command" scripts that read the
event JSON on stdin and only emit additionalContext when there's a
genuine Robot Framework signal in the prompt (UserPromptSubmit) or
a .robot/.resource file was actually written this session (Stop).

Investigation context (preserved in docs/plugin/hooks-fix-proposal.md):

- Local 9-variant matcher probe against Claude Code 2.1.121
  confirmed PostToolUse with matcher:"Write|Edit" works correctly
  - the artifact analysis from PR #2 was wrong about that. The
  matcher fires; PostToolUse hooks just don't emit hook_started/
  progress/response stream events the way SessionStart does. Don't
  inspect the stream JSON to verify hook firing - inspect side
  effects.

- Cross-agent comparison (Cursor 1.7+, GitHub Copilot 2026.1, Cline)
  confirmed Claude Code's hooks.json schema is becoming the de
  facto standard. Stay with the existing matcher syntax; invest in
  making the conditional behavior right.

What changed:

- plugins/rf-agentskills/scripts/maybe_inject_rf_context.sh: reads
  UserPromptSubmit event JSON, tests prompt against a tight RF
  regex (robot framework, .robot, .resource, library names, skill
  ids, subagent ids, tooling like robotidy/robocop/rfbrowser).
  Emits hookSpecificOutput.additionalContext only on match.

- plugins/rf-agentskills/scripts/maybe_remind_robot_tests.sh: reads
  Stop event JSON, greps the transcript for any tool result with
  file_path ending in .robot or .resource, only injects the
  "run robot, inspect report.html" reminder when at least one such
  file was touched.

- plugins/rf-agentskills/hooks/hooks.json: UserPromptSubmit and
  Stop now point at the new conditional scripts.

- plugins/rf-agentskills/hooks/README.md (new): documents the four
  hooks, why two are conditional, the verification recipe, and
  authoring guidelines for future hooks.

- eval/tasks/narrow/narrow-rf-injection-positive-01.yaml (new):
  positive control - RF prompt should trigger injection and the
  agent should leverage an rf-agentskills lookup path. Companion
  to narrow-non-rf-control-01.

- eval/tasks/narrow/narrow-non-rf-control-01.yaml: history note
  updated - what was a known-failing canary is now expected to pass.

- eval/tasks/README.md: "Known plugin regressions" section
  rewritten to "Resolved" - documents both the real fix and the
  PostToolUse false alarm so future debugging doesn't chase the
  same false trail.

- tests/test_hook_scripts.py (new): 41 parametrised cases covering
  positive triggers, negative misses, malformed JSON, missing
  fields, oversized prompts, and pathological transcripts. Locks
  in the regex specification.

Verification:

- 209/209 unit tests pass (41 new + 168 existing).
- Local run of narrow-non-rf-control-01: 6/6 graders pass, 1 tool
  call (Write), no rf tooling invoked.
- Local run of narrow-rf-injection-positive-01: 4/4 graders pass,
  agent invoked Skill (libdoc-search) plus Bash/Read/Write to
  produce docs/click-element.md.

Co-Authored-By: claude-flow <ruv@ruv.net>
CI run 25061223238 showed the conditional UserPromptSubmit injection
working as designed (leveraged_rf_lookup grader passed, count=5: agent
invoked Skill(libdoc-explain) plus 4 Bash libdoc lookups). But Haiku
picked libdoc-explain rather than libdoc-search and got stuck in the
~60KB persisted-output recovery loop, hitting max_turns=12 before
writing the final markdown file.

Mirrors narrow-libdoc-search-01's budget (16) which covers the same
libdoc output-extraction overhead. The underlying libdoc-explain
output-size issue is tracked separately - this bump is intentional
headroom for skill selection variance, not a workaround.

Co-Authored-By: claude-flow <ruv@ruv.net>
The Test (Python 3.10/3.12/3.13) job runs `pip install robotframework
pytest && pytest tests/` and tries to collect tests/eval/conftest.py,
which imports rf_skill_eval. That package isn't installed in this job
(it's the eval harness, installed via uv sync only in the Skill
Evaluation workflow), so collection aborts:

    ModuleNotFoundError: No module named 'rf_skill_eval'

This has been red on main since PR #2 merged - my hooks PR inherits
the failure rather than introducing it. Same fix unblocks main and
PR #3.

Scope split: the CI Test job exercises the plugin's own Python
scripts; tests/eval/ is the harness suite, exercised end-to-end by
the Skill Evaluation workflow (and locally via `uv run pytest
tests/eval/`).

Co-Authored-By: claude-flow <ruv@ruv.net>
CI run 25073374915 saw Haiku burn all 8 turns on style-discovery
reads (workspace listing, resources/common.resource, Glob tests/,
two example .robot files, data/ listing, users-api-response.json,
README.md) and never reach the Write. The prompt explicitly asks
to "follow the project's existing style" so exploration is
justified - the budget was the problem.

Task passed in the previous 3 runs at the same budget (lucky path
selection); this bump keeps the test reliable without papering over
behavior. 10 turns sits below the 12-16 used by other narrow tasks.

Co-Authored-By: claude-flow <ruv@ruv.net>
fix(plugin): conditional UserPromptSubmit and Stop hooks
manykarim and others added 28 commits November 9, 2026 11:44
Narrow tier, all plugins staged, 3 replicates: 54/54 gated passes on Haiku 5.5
and on Sonnet 5.5. Trigger validation on Haiku 5.5 (6 runs): no skill below
its 3.0.0 baseline (lowest one-sided Fisher p 0.33). Partial tier: 12/12 on
both models, all by a passing suite rather than a plugin suggestion.
narrow-language-bdd-01 tokens +15% over 9 runs (budget 30%).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
Copilot CLI 1.0.91 lists the nine bundle skills and three subagents, and runs
every rf-core hook script (bundle and split install). It never passes hook
additionalContext to the model.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
….3, 7.3 done

Codex 0.162.1 lists the nine bundle skills as rf-agentskills:<name> and the
split plugins' skills under their own prefixes. It loads no plugin subagents
(3.0.0 neither) and holds plugin hooks for trust review, so a headless session
runs none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
Syncs its delta specs: new plugin-split spec; updates library-skill-install-
guidance, plugin-subagents, rf-session-context-hooks, robotcode-prerequisite,
setup-skill, skill-eval-harness and skill-triggering.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
…ubagents

scripts/check_content_rules.py checks shipped content for Unicode tag and
zero-width characters, HTML comments in SKILL.md and subagents, subagents
without a tools list or with '*', unrestricted shell in allowed-tools,
downloads piped into a shell or interpreter in scripts and hooks, and MCP
servers started without an exact version. The scanner spike's canaries are
rebuilt as test fixtures.

rf-test-architect and rf-migration-guide now declare
Read, Write, Edit, Grep, Glob, Bash, Skill; the OpenCode variants get an
explicit permission block. Launch task 4.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
Cisco skill-scanner 2.3.2 and SkillSpector 2.13.4 (commit-pinned) in their
own virtualenvs; cc-audit 3.23.37 and Gitleaks 8.30.1 as release binaries
with SHA-256 checks. Verified in a clean ubuntu:24.04 container. Launch
task 5.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
scripts/compare-findings.py normalises each scanner's SARIF to
(scanner, rule, file, fingerprint), with a line-independent fingerprint
(SkillSpector's own ids change per run), fails on new HIGH/CRITICAL
findings and on expired, over-long or incomplete baseline entries, reports
the rest, and writes a Markdown summary and draft entries. Launch task 5.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
scripts/security-scan.sh copies a plugin's tracked, shipped files (no tests/,
evals/ or caches), runs Cisco skill-scanner (skills; agents --lenient),
SkillSpector --no-llm, cc-audit (mcp, plugin, hook, subagent) and Gitleaks
on the copy, and compares the SARIF with security/baselines/<plugin>.yaml.

The baselines hold the 11 HIGH findings of a clean scan with a reason each
(all false positives or the D8 uv-install decision). reviewed_by is empty, so
the gate fails until a security reviewer signs them (launch task 5.3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
…aselines

security-gate.yml runs on every PR (read-only, no secrets) and nightly: house
rules, the scanners on the plugins select-plugin-tests.py --security picks
(a bundle whenever one of its members changes), Gitleaks on the PR commits,
SARIF artifacts and the comparison summary in the job summary.

Fingerprints no longer include the path, and compare-findings.py takes
several baselines with --map, so the bundle's copies are judged by the
baselines of the plugins they come from. Baselines regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
…mode

Only that pass reads hooks and scripts: the C4 canary (a hook POSTing
process.env) now fails the gate as HIGH DATA_EXFIL_ENV_DUMP, in rf-core and
in the bundle copy. The hooks' spawnSync calls (fixed argv, no shell) are
baselined with a reason. Spec and design D6 updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
security-deep-scan.yml runs on the security-deep-scan label (pull_request_target)
and on pushes to main. Scripts and scanners come from the base branch; the PR
head is checked out into ./pr as data and never executed; actions are pinned
to commit SHAs. It comments the findings and sets a security-deep-scan commit
status. security-scan.sh gains SCAN_ROOT (scan another checkout as data),
--deep (model passes) and copies symlinks as links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
skill-evaluation.yml treats a PR from a fork as having no credentials and
runs pr-eval only for PRs whose head branch is in this repository, whatever
the repository's fork-secrets setting (launch task 5.6). Tests check that no
workflow holding the eval secrets uses pull_request_target or workflow_run.

Gitleaks 8.30.1 detects a correctly shaped fake Anthropic key
(anthropic-api-key); the test builds the key at run time so none is
committed (launch task 5.7).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
- .github/governance.yaml: the reviewer teams
  (MarketSquare/robotframework-plugins-reviewers, -security), the
  security-relevant paths, and a dated tier grace entry: the plugins are
  verified with one maintainer until 2027-01-31.
- scripts/required-reviews.py + required-reviews.yml (with review-relay.yml
  for review events on fork PRs): one approval from each group a PR concerns,
  set as the required-reviews commit status. Base-branch code only; the PR is
  read through the API. Needs a REVIEW_TEAMS_TOKEN secret.
- scripts/check-governance.py (in CI): CODEOWNERS matches catalog.yaml
  maintainers; verified plugins have trigger sets, eval tasks, baselines and
  two maintainers, or a grace entry.
- CODEOWNERS lists the teams; PR template with the review checklist.

Launch tasks 6.2 and 6.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
build-catalog.py --check fails when a plugin is removed before it was
deprecated for two installer releases (from installer/CHANGELOG.md, not
counting pre-releases) and 90 days, naming the earliest release and date;
when the marketplace lists a removed plugin; and when an active plugin has no
maintainer left (the schema now allows an empty list so that a deprecated
plugin can have none). Launch task 7.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
A plugin that the catalogue no longer bundles leaves its files stale on
upgrade, so the existing pruning removes them and keeps user-modified ones.
The summary now names the plugins an install dropped, marked when the
catalogue no longer has them. Test for 'Upgrade cleans up a removed plugin'
on Claude Code, Codex, Cursor and OpenCode. Launch task 7.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
Sockets are blocked in the test process (connect, create_connection,
getaddrinfo) while the installer runs a file-mode install for each of the
seven agents. Launch task 8.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
- adoption-collect.yml: weekly GitHub traffic snapshots on the adoption-data
  branch (ADOPTION_TOKEN if the default token is refused; task 8.1, verified
  after its first run).
- Plugin feedback issue form; feedback-label.yml adds plugin:<name> from the
  form's answer when it names a real plugin.
- scripts/adoption-report.py and adoption-report.yml: the quarterly report
  from traffic, PyPI downloads, issues and the eval baselines at plugin tags,
  opened as a PR. Lists promotion, demotion and deprecation candidates.
  Tested on fixture data, including a demotion candidate (task 8.2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
scripts/check-docs-voice.py fails on banned corporate phrases (the spec's
five plus the same kind of filler) and on more than one exclamation mark per
document, in the documents written for people. Code, link targets and
comments are skipped; changelogs and dated records are history. Launch
task 9.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
README opens with what the plugins do, keeps the generated catalogue and the
per-agent install steps, and adds the trust tiers (and what they don't
promise), no telemetry, and the move from rf-agentskills. Development notes
move to CONTRIBUTING.md, which also covers adding a plugin, the PR checks,
review, the writing rules and the three kinds of version. GOVERNANCE.md:
tiers, review groups, maintainer targets, lifecycle. SECURITY.md: private
reporting, the 7-day response, what the checks cover and can't promise.

Launch tasks 9.2 and 9.3 (open: voice-guide review; Security tab after push).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
templates/plugin/ has catalog.yaml, plugin.json, a README and one skill
(rf-template) with a reference and a dry-run example. scripts/check-template.sh
(CI job template-plugin) copies it to plugins/example/ in a scratch checkout
and runs the PR checks and the tests CI would select.

What that surfaced:
- select-plugin-tests.py skipped plugins without tests of their own, so a
  change to rf-web never ran rf-core's tests; it now selects them.
- The feedback form's plugin list is generated by build-catalog.py.
- Trigger sets and per-skill contract entries are checked for verified
  plugins only (they are verified-tier evidence); tests pinned to today's
  plugin set check it as a subset.

Launch task 9.4 (verified locally; the CI job still has to run).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
…EADME and changelog

RELEASING.md: per-plugin releases tagged <plugin>--v<version>, CalVer
installer releases tagged robotframework-plugins-v<version>, the version
table, and PyPI trusted publishing (no token). The installer README covers
plugin selection, upgrades, marketplace mode and no telemetry under the new
name; the changelog's unreleased 2026.12.0 entry records the rename, the
plugin selection and the per-plugin support folders. Launch task 9.5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
…publishing

release.yml now runs on <plugin>--v<version> tags (the tag must match the
plugin's plugin.json; builds the plugin's archive, standalone skills and
Claude Desktop ZIPs, with notes from its changelog) and on
robotframework-plugins-v<version> tags (the tag must match pyproject.toml and
the current month; builds and checks the wheel and sdist, notes start with
the version table, then publishes by trusted publishing in a protected
environment: pypi, or testpypi for a release candidate). Actions are pinned
to commit SHAs.

scripts/build-packages.sh still built 'rf-agentskills', which no longer
exists after the rename; it builds robotframework-plugins now.

Launch task 10.1 (open: PyPI trusted publisher and the TestPyPI run).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
legacy/rf-agentskills/ builds the last rf-agentskills: it depends on
robotframework-plugins>=2026.12.0, its rf-agentskills command prints a
one-line notice to stderr and runs robotframework-plugins with the same
arguments and exit code, and its PyPI description says the project moved.
Checked in an isolated virtualenv from local wheels: the notice, a full
install, and exit code 2 on a bad argument. Publish it once after the first
CalVer release, then delete the folder (launch task 10.3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
The release workflow accepts only the current month, and the first
release goes out in November.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
- check_content_rules.py loads on Python 3.10; there it reports a TOML
  MCP configuration as unreadable instead of skipping it.
- build-catalog.py prints POSIX paths, and the catalogue tests read and
  write UTF-8, so they pass on Windows.
- The security gate gets a 'Security gate result' job, the one check
  branch protection can require: the scan jobs are named per plugin.
- .gitleaksignore records the placeholder API key in a RESTinstance
  example from the migrated history; it is a security-reviewed path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
manykarim reviewed the 27 HIGH baseline entries: hook child processes
started without a shell, an environment passed only to the hook's own
child process, the documented uv install script (design D8), and
documentation examples that scanners read as tool calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHEmzL3ErAhGQykKWDx2wP
@manykarim
manykarim merged commit b393f68 into main Nov 9, 2026
31 checks passed
@manykarim
manykarim deleted the migrate/launch-programme branch November 12, 2026 21:54
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.

1 participant