Skip to content

Commit 077f6df

Browse files
docs(examples): add local plugin install + update example
Co-authored-by: openhands <openhands@all-hands.dev>
1 parent 3bd7632 commit 077f6df

File tree

1 file changed

+98
-0
lines changed
  • examples/05_skills_and_plugins/03_local_plugin_install

1 file changed

+98
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""Example: Install + manage a local plugin (no LLM required).
2+
3+
This demonstrates the installed plugins utilities introduced in this PR.
4+
5+
Key ideas:
6+
- Installed plugin packages live under `~/.openhands/plugins/installed/` by default.
7+
- Each plugin is a self-contained directory that can include `skills/`, `agents/`,
8+
`hooks/`, `.mcp.json`, etc. (Claude Code style).
9+
10+
For this example we avoid writing to the real home directory by passing a
11+
temporary `installed_dir=`.
12+
"""
13+
14+
from __future__ import annotations
15+
16+
import json
17+
import tempfile
18+
from pathlib import Path
19+
20+
from openhands.sdk.plugin import (
21+
get_installed_plugin,
22+
install_plugin,
23+
list_installed_plugins,
24+
load_installed_plugins,
25+
uninstall_plugin,
26+
update_plugin,
27+
)
28+
29+
30+
def _write_example_plugin(plugin_dir: Path, *, version: str) -> None:
31+
(plugin_dir / ".plugin").mkdir(parents=True, exist_ok=True)
32+
(plugin_dir / ".plugin" / "plugin.json").write_text(
33+
json.dumps(
34+
{
35+
"name": "local-plugin",
36+
"version": version,
37+
"description": "Example local plugin",
38+
}
39+
)
40+
)
41+
42+
skill_dir = plugin_dir / "skills" / "hello"
43+
skill_dir.mkdir(parents=True, exist_ok=True)
44+
(skill_dir / "SKILL.md").write_text(
45+
"""---
46+
name: hello
47+
description: Say hello
48+
---
49+
50+
Say hello.
51+
"""
52+
)
53+
54+
55+
def main() -> None:
56+
with tempfile.TemporaryDirectory() as tmp:
57+
tmp_path = Path(tmp)
58+
59+
# Create a local plugin directory (this simulates a repo checkout).
60+
plugin_source_dir = tmp_path / "local-plugin"
61+
_write_example_plugin(plugin_source_dir, version="1.0.0")
62+
63+
# Use a temp install dir instead of ~/.openhands/plugins/installed/
64+
installed_dir = tmp_path / "plugins" / "installed"
65+
66+
info = install_plugin(
67+
source=str(plugin_source_dir), installed_dir=installed_dir
68+
)
69+
print(f"Installed: {info.name} v{info.version} from {info.source}")
70+
71+
print("\nList installed plugins:")
72+
for item in list_installed_plugins(installed_dir=installed_dir):
73+
print(f"- {item.name} v{item.version} ({item.source})")
74+
75+
print("\nLoad installed plugins:")
76+
plugins = load_installed_plugins(installed_dir=installed_dir)
77+
for plugin in plugins:
78+
print(f"- {plugin.name}: {len(plugin.get_all_skills())} skill(s)")
79+
80+
print("\nGet installed plugin:")
81+
print(get_installed_plugin("local-plugin", installed_dir=installed_dir))
82+
83+
# Update: mutate the local plugin source and call update_plugin(), which
84+
# reinstalls from the original source with ref=None (latest).
85+
_write_example_plugin(plugin_source_dir, version="1.0.1")
86+
updated = update_plugin("local-plugin", installed_dir=installed_dir)
87+
assert updated is not None
88+
print(f"\nUpdated: {updated.name} v{updated.version}")
89+
90+
uninstall_plugin("local-plugin", installed_dir=installed_dir)
91+
print("\nAfter uninstall:")
92+
print(list_installed_plugins(installed_dir=installed_dir))
93+
94+
print("EXAMPLE_COST: 0")
95+
96+
97+
if __name__ == "__main__":
98+
main()

0 commit comments

Comments
 (0)