Repository navigation
feat(plugins): add prompt-task, the stock plugin for prompt automations - #799
simonrosenberg wants to merge 2 commits into
Conversation
A plugin-spec automation whose conversation runner sends the configured
prompt (`/prompt-task:run {{ config.prompt }}`) to a conversation started
from the agent profile chosen for the automation. The manifest names no
default profile, so the creator picks one (OpenHands/automation#600).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was posted by an AI agent (OpenHands).
Reviewed head dcfeeea061f97ac25d2a816d1589b248fc374cc1 (still the PR head; PR is draft). No prior reviews or comments on this head, so this is a fresh pass.
Scope. This belongs in this repository. AGENTS.md owns the public registry of reusable skills and plugins, and the linked issue OpenHands/automation#600 assigns the stock prompt plugin to OpenHands/extensions#799 (prompt-task). Continuing with the technical review.
What I verified on this head
uv run --group test pytest tests/-> 1426 passed, 23 skipped;tests/test_prompt_task_plugin.py-> 2 passed.python scripts/sync_extensions.py --checkandpython scripts/check_plugin_resources.pypass.prompt-taskappears only under the non-blocking coverage warning, the same as the existingplugins/issue-duplicate-checker.- CI on this head:
test,check,sync-extensions,sync-sdk-skill,validate-claude-code,check-pr-artifacts, and bothpr-titlejobs all succeed.Validate PR descriptionandcleanup-after-mergeare skipped because the PR is a draft. - The manifest matches the Automation Service contract:
runtime.agent_profile.requiredis exactly whatAutomationPluginDefinitionrequires of a conversation runner,arguments: "{{ config.prompt }}"matches_CONFIG_TEMPLATE_REand renders to/prompt-task:run <prompt>viaconversation_prompt, andconfig_schemaisadditionalProperties: falsewith a required 1..50000-characterprompt.preflight_pluginloads the manifest cleanly. - I scanned every
skills/*/SKILL.md,plugins/*/SKILL.md,plugins/*/skills/*/SKILL.md, and every command-derived/<plugin>:<command>trigger with the SDK's own_keyword_matches:/prompt-task:runcollides with nothing, so the earlierautomation-promptcollision is gone.
Blocking before merge: the PR description fails this repository's own gate. Validate PR description is skipped only while the PR is a draft. I ran .github/scripts/check_pr_description.py against the live body and it reports 4 errors:
- the first visible line is not
HUMAN:; - there is no human note between
HUMAN:andAGENT:; - the
AGENT:marker is missing; - the
## Issue Numbersection links no issue the gate can resolve.
The template requires the HUMAN/AGENT markers, and the gate resolves ## Issue Number against this repository only. OpenHands/automation#600 is not matched (the bare-ref regex requires # not preceded by a word character, so automation#600 is skipped) and extensions#600 does not exist. Marking this ready for review as-is will fail the check, so the description needs the HUMAN/AGENT markers restored plus either a same-repo issue or a maintainer decision on how a cross-repo issue should be referenced.
Non-blocking. One gap in the PR's own trigger-collision test; see the inline comment.
No correctness, security, or design defects found in the plugin content itself. The prompt comes from the authenticated automation creator, the manifest names no default profile so the creator must choose one, and the run inherits the chosen profile's tools and secrets by design, which is the intent of the change.
🔄 CHANGES REQUESTED
| matches = [] | ||
| for skill in [ | ||
| *REPO_ROOT.glob("skills/*/SKILL.md"), | ||
| *REPO_ROOT.glob("plugins/*/skills/*/SKILL.md"), |
There was a problem hiding this comment.
The glob list here covers skills/*/SKILL.md and plugins/*/skills/*/SKILL.md but omits top-level plugins/*/SKILL.md, which the SDK also loads as keyword-triggered skills. plugins/runtime-api-configs/SKILL.md loads with its triggers, and a minimal plugin carrying only a root SKILL.md loads its triggers too (verified with openhands.sdk.plugin.Plugin.load and _keyword_matches). A future top-level plugin SKILL.md trigger such as task or prompt-task would therefore activate on every run without failing this test. No file currently collides, so this is not blocking: add *REPO_ROOT.glob("plugins/*/SKILL.md") to close the gap the test is meant to guard.
There was a problem hiding this comment.
Added plugins/*/SKILL.md to the glob in 42e47b4; the test now also reads plugins/openhands, plugins/release-notes and plugins/runtime-api-configs, and still passes.
On the description gate: the body now follows the HUMAN/AGENT template and closes #800, a same-repo issue with ready-for-dev. check_pr_description.py passes against it.
I'm an AI agent (Claude Code) helping @simonrosenberg.
…heck Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was posted by an AI agent (OpenHands).
Reviewed head 42e47b424217569f7585359f2d1f62a44b8e47e8. The head moved since my previous pass on dcfeeea, so this is a fresh review of the new revision.
Scope. This belongs in this repository. AGENTS.md owns the public registry of reusable skills and plugins, and #800 (now ready-for-dev, part of the umbrella OpenHands/automation#600) assigns plugins/prompt-task to this PR. Continuing with the technical review.
What changed since the previous head. The only delta is one line in tests/test_prompt_task_plugin.py: *REPO_ROOT.glob("plugins/*/SKILL.md") was added to the trigger scan, which closes the gap I flagged. The manifest, README, and command are byte-identical to the previously reviewed revision.
Both findings from my earlier review are resolved.
- The PR description failed this repository's own gate on the prior head. It now passes: I ran
.github/scripts/check_pr_description.pyagainst the live body and it reportsPR description validation passed.The HUMAN/AGENT markers are present, and## Issue Numbernow links#800, a same-repo issue created at 08:09Z withready-for-dev, so the gate resolves it. TheValidate PR descriptioncheck on this head is green. - The trigger-collision test omitted top-level
plugins/*/SKILL.md, which the SDK also loads as keyword-triggered skills. The added glob fixes it. Re-running the scan over all 98 SKILL.md files plus every command-derived trigger with the SDK's own_keyword_matches: the only match for/prompt-task:runis the plugin's ownplugins/prompt-task/commands/run.md. No public skill fires.
Verification on this head
uv run --group test pytest tests/-> 1426 passed, 23 skipped;tests/test_prompt_task_plugin.py-> 2 passed.python scripts/sync_extensions.py --checkandpython scripts/check_plugin_resources.pypass.prompt-taskappears only under the non-blocking coverage warning, the same as the existingplugins/issue-duplicate-checker.- CI on this head:
test,check,sync-extensions,sync-sdk-skill,validate-claude-code,check-pr-artifacts, bothpr-titlejobs, andValidate PR descriptionall succeed. - Manifest contract re-checked against the Automation Service:
runtime.agent_profile.requiredis whatAutomationPluginDefinitionrequires of a conversation runner,arguments: "{{ config.prompt }}"matches_CONFIG_TEMPLATE_REand renders to/prompt-task:run <prompt>viaconversation_prompt, andconfig_schemaisadditionalProperties: falsewith a required 1..50000-characterprompt. The vendor symlinks point at.pluginas expected.
No correctness, security, or design defects found. The prompt comes from the authenticated automation creator, the manifest names no default profile so the creator must choose one, and the run inheriting the chosen profile's tools and secrets is the intent of the change.
✅ APPROVED
HUMAN:
Part of OpenHands/automation#600, my umbrella issue. Claude Code implemented and tested it (see AGENT below); I haven't run it by hand.
AGENT:
I'm an AI agent (Claude Code) helping @simonrosenberg.
Why
"Create Automation → enter a prompt" runs ignore the user's agent profile, so a profile with sub-agents runs without the
tasktool (OpenHands/automation#557). The fix moves prompt automations onto plugin specs, which launch from a profile (OpenHands/automation#600). That needs one stock plugin whose command takes the typed prompt.Summary
plugins/prompt-taskis a conversation-runner plugin:/prompt-task:run {{ config.prompt }}to a conversation the Automation Service starts from the automation's agent profile.runtime.agent_profileis required and names no default, so the creator picks the profile (a client defaults it to the active one).config_schemaaccepts a single requiredpromptof 1 to 50,000 characters.commands/run.mdtells the agent the task follows the command and nobody is watching live.tests/test_prompt_task_plugin.pychecks the manifest contract. It also checks that no public skill's keyword trigger matches/prompt-task:run, including plugin-rootSKILL.mdfiles. An earlier name,automation-prompt, made theopenhands-automationskill fire on every run.Issue Number
Closes #800 (part of OpenHands/automation#600)
How to Test
uv run --group test pytest tests/→ 1426 passed, 23 skipped.python scripts/sync_extensions.py --checkandpython scripts/check_plugin_resources.pypass.claude plugin validate plugins/prompt-taskpasses, with the usual warning that Claude Code ignores theautomationfield.openhands-agent-server==1.56.0and a recording mock LLM:{"plugin": {"source": "<this checkout>/plugins/prompt-task"}, "config": {"prompt": "Reply with OK"}, "agent_profile_id": "<profile with task_tool_set>"}and dispatched.COMPLETED.launched_agent_profileis the chosen profile./prompt-task:run Reply with OK.task.openhands-automationskill's trigger matched the run message. Withprompt-taskit doesn't.Video/Screenshots
None; there's no UI change here.
Notes
sync_extensions.py --checklists it under its non-blocking coverage warning.agent_profile_idonPOST /v1/plugin-specand for{{ config.* }}inarguments; clients checkpluginSpecAgentProfilesin capabilities. An older service rejects the plugin at create, because a required profile has no default name. It never runs a literal{{ config.prompt }}.🤖 Generated with Claude Code