Skip to content

feat(examples): add plugin and skill lifecycle demos#2362

Merged
enyst merged 4 commits intomainfrom
openhands/issue-2339-skill-plugin-lifecycle-docs
Mar 10, 2026
Merged

feat(examples): add plugin and skill lifecycle demos#2362
enyst merged 4 commits intomainfrom
openhands/issue-2339-skill-plugin-lifecycle-docs

Conversation

@enyst
Copy link
Collaborator

@enyst enyst commented Mar 9, 2026

Summary

Closes #2339.

Checklist

  • If the PR is changing/adding functionality, are there tests to reflect this?
  • If there is an example, have you run the example to make sure that it works?
  • If there are instructions on how to run the code, have you followed the instructions and made sure that it works?
  • If the feature is significant enough to require documentation, is there a PR open on the OpenHands/docs repository with the same branch name?
  • Is the github CI passing?

Agent Server images for this PR

GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.13-nodejs22 Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:eac2c4d-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-eac2c4d-python \
  ghcr.io/openhands/agent-server:eac2c4d-python

All tags pushed for this build

ghcr.io/openhands/agent-server:eac2c4d-golang-amd64
ghcr.io/openhands/agent-server:eac2c4d-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:eac2c4d-golang-arm64
ghcr.io/openhands/agent-server:eac2c4d-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:eac2c4d-java-amd64
ghcr.io/openhands/agent-server:eac2c4d-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:eac2c4d-java-arm64
ghcr.io/openhands/agent-server:eac2c4d-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:eac2c4d-python-amd64
ghcr.io/openhands/agent-server:eac2c4d-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-amd64
ghcr.io/openhands/agent-server:eac2c4d-python-arm64
ghcr.io/openhands/agent-server:eac2c4d-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-arm64
ghcr.io/openhands/agent-server:eac2c4d-golang
ghcr.io/openhands/agent-server:eac2c4d-java
ghcr.io/openhands/agent-server:eac2c4d-python

About Multi-Architecture Support

  • Each variant tag (e.g., eac2c4d-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., eac2c4d-python-amd64) are also available if needed

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 9, 2026

API breakage checks (Griffe)

Result: Passed

Action log

@github-actions
Copy link
Contributor

github-actions bot commented Mar 9, 2026

Agent server REST API breakage checks (OpenAPI)

Result: Failed

Log excerpt (first 1000 characters)
{"asctime": "2026-03-10 09:08:41,243", "levelname": "WARNING", "name": "openhands.agent_server.config", "filename": "config.py", "lineno": 173, "message": "\u26a0\ufe0f OH_SECRET_KEY was not defined. Secrets will not be persisted between restarts."}
::error title=openhands-agent-server REST API::Breaking REST API change detected without MINOR version bump (1.12.0 -> 1.12.0).

Breaking REST API changes detected compared to baseline release:
- the 'file' request property type/format changed from 'string'/'' to 'string'/'binary'
/home/runner/work/software-agent-sdk/software-agent-sdk/.venv/lib/python3.13/site-packages/litellm/llms/custom_httpx/async_client_cleanup.py:66: DeprecationWarning: There is no current event loop
  loop = asyncio.get_event_loop()

Action log

@enyst
Copy link
Collaborator Author

enyst commented Mar 9, 2026

@OpenHands Understand what this PR adds (read linked issue too). Check what examples do we have in examples/ directory working with plugins and what they do.

I'm concerned about redundancy and too many slightly relevant examples, not relevant enough to warrant a new example file, maybe? Could we add enable / disable information to some existing example, either for plugins or for skills or both? Actually do we already do some enable / disable in some pre-existing example? I have a feeling I've seen that...

@openhands-ai
Copy link

openhands-ai bot commented Mar 9, 2026

I'm on it! enyst can track my progress at all-hands.dev

@openhands-ai
Copy link

openhands-ai bot commented Mar 9, 2026

I reviewed the PR, the linked issue, and the existing plugin/skill examples.

Final answer: the PR adds three new runnable lifecycle examples:

  • plugin enable/disable
  • skill enable/disable
  • skill uninstall

I confirmed that the underlying coverage requested by the issue is genuinely missing today: existing examples cover skill activation, skill loading, marketplace installation, and plugin install/load/uninstall, but none of the pre-existing examples demonstrate persistent installed enable/disable state via enable_* / disable_*.

The likely example you were remembering is examples/01_standalone_sdk/03_activate_skill.py, but that demonstrates runtime skill triggering, not install-time enable/disable lifecycle.

My conclusion was:

  • plugin enable/disable could reasonably be folded into the existing examples/05_skills_and_plugins/02_loading_plugins/main.py
  • skill enable/disable + uninstall would be better as a single installed-skill lifecycle example rather than two separate files

So the concern about redundancy is valid, but the lifecycle coverage itself is still needed. The best simplification would be consolidation, not removal.

openhands-agent and others added 2 commits March 9, 2026 06:53
- merge plugin enable/disable into the existing plugin example
- replace split skill lifecycle demos with one installed-skill example

Co-authored-by: openhands <openhands@all-hands.dev>
@enyst
Copy link
Collaborator Author

enyst commented Mar 10, 2026

@OpenHands read this entire PR comments; understand the goal. Fix the PR description if necessary.

Look up the docs/ repo (clone it for yourself) and make sure the companion docs PR is up to date with what this PR is doing. Push.

Then test the examples manually, with gpt-5-nano and your openai key. Verify if they work and confirm every function or fix if not. Publish your results when I tell you to summarize. I mean it: in this session, when I tell you to summarize, don't summarize, repeat verbatim what you told me.

@openhands-ai
Copy link

openhands-ai bot commented Mar 10, 2026

I'm on it! enyst can track my progress at all-hands.dev

Co-authored-by: openhands <openhands@all-hands.dev>
@openhands-ai
Copy link

openhands-ai bot commented Mar 10, 2026

Done.

  • I updated the SDK PR description to reflect the consolidated example layout.
  • I found and fixed a real issue in examples/05_skills_and_plugins/02_loading_plugins/main.py: Demo 1 was printing ✓ Loaded 0 skill(s) from GitHub plugin because Conversation plugin loading is lazy and had not happened yet. I fixed that in SDK commit cda2110f by triggering the first interaction before inspecting conversation.agent.agent_context and conversation.resolved_plugins.
  • I synced the companion docs PR and pushed docs commit 2e8083d to OpenHands/docs#386.
  • I also added the lazy plugin-loading note to the repo AGENTS.md.

Manual validation results:

  • uv run python examples/05_skills_and_plugins/03_managing_installed_skills/main.py

    • Passed.
    • Verified install_skill, list_installed_skills, load_installed_skills, disable_skill, enable_skill, and uninstall_skill.
    • Verified .installed.json flips enabled from true -> false -> true.
    • Verified uninstall removes rot13-encryption while code-style-guide remains.
    • Final output ended with EXAMPLE_COST: 0.
  • LLM_API_KEY=$OPENAI_API_KEY LLM_MODEL=openai/gpt-5-nano uv run python examples/05_skills_and_plugins/02_loading_plugins/main.py

    • Before the fix, the example completed but Demo 1 misleadingly reported 0 loaded skills before lazy plugin load.
    • After the fix, it passed and now reports:
      • ✓ Loaded 17 skill(s) from GitHub plugin
      • Resolved plugin refs:
      • github:anthropics/skills @ b0cbd3df1533b396d281a6886d5132f623393a9c
    • Verified local plugin install, GitHub plugin install, list_installed_plugins, load_installed_plugins, disable_plugin, enable_plugin, and uninstall_plugin.
    • Verified .installed.json flips the local plugin enabled flag true -> false -> true.
    • Final output ended with EXAMPLE COMPLETED SUCCESSFULLY and EXAMPLE_COST: 0.0029.

Also:

When you tell me to summarize, I’ll repeat this verbatim.

@enyst enyst marked this pull request as ready for review March 10, 2026 10:34
Copy link
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Acceptable - Good lifecycle documentation, but there's a critical bug that will break the skill example.

The plugin example refactoring looks solid - moving skill inspection after send_message() correctly handles lazy loading, and the early-continue pattern is cleaner. The new skill lifecycle example mirrors this well, which is good for consistency.

However, there's a copy-paste bug in the skill example that will cause it to fail. See inline comment.

@enyst enyst requested a review from all-hands-bot March 10, 2026 10:42
Copy link
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Good taste - Clean, pragmatic examples that correctly demonstrate the lifecycle APIs.

What works well:

  • Correctly handles lazy loading (skills/plugins inspected after send_message())
  • Previous enable_plugin vs enable_skill bug is already fixed
  • Clear demonstration of .installed.json metadata format for CLI developers
  • Appropriate assertions verify behavior at each step
  • Early-continue patterns keep nesting shallow

Minor note:
The skill example ends with print("\nEXAMPLE_COST: 0") while the plugin example doesn't. This might matter if these are run in CI for cost tracking, though it could be intentional since the plugin example has optional LLM interaction with variable cost.

Verdict: Worth merging - solid examples for real use cases.

@enyst enyst merged commit 8cdc117 into main Mar 10, 2026
43 of 45 checks passed
@enyst enyst deleted the openhands/issue-2339-skill-plugin-lifecycle-docs branch March 10, 2026 10:46
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.

Add plugin/skill lifecycle examples + docs sync (enable/disable/uninstall)

3 participants