Skip to content

Commit 5df9870

Browse files
docs(cookbook): sync from OpenHands/enterprise-cookbook
Syncs the Enterprise Cookbook tab with OpenHands/enterprise-cookbook@25bf9b7. Every file under `cookbook/` and the Enterprise Cookbook tab in `docs.json` are generated from that repository. Change them there, not here; edits made directly in this repository are overwritten by the next sync. _Opened automatically by the docs-publish workflow in OpenHands/enterprise-cookbook ([run](https://github.com/OpenHands/enterprise-cookbook/actions/runs/37968207020))._
1 parent 703d1de commit 5df9870

3 files changed

Lines changed: 260 additions & 0 deletions

File tree

‎cookbook/index.mdx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ Extend conversations with plugins, skills, and MCP servers.
9393
Start a conversation with a plugin pre-loaded via the REST API.
9494
</Card>
9595

96+
<Card title="Plugin With Script" icon="file-code" href="/cookbook/plugin-with-script">
97+
Bundle a script in a plugin and have its command and skill tell the agent to run it.
98+
</Card>
99+
96100
<Card title="Test MCP Config" icon="vial" href="/cookbook/test-mcp-config">
97101
Validate MCP server configs against a sandbox agent-server via POST /api/mcp/test.
98102
</Card>

‎cookbook/plugin-with-script.mdx‎

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
---
2+
title: Plugin With Script
3+
description: Bundle a script in a plugin and have its command and skill tell the agent to run it.
4+
icon: file-code
5+
---
6+
7+
{/* GENERATED from OpenHands/enterprise-cookbook@main (plugin-with-script/README.md). Edit the source, not this file. */}
8+
9+
<Card title="View source on GitHub" icon="github" href="https://github.com/OpenHands/enterprise-cookbook/tree/main/plugin-with-script" horizontal />
10+
11+
A plugin can ship code as well as instructions. This example's
12+
[`city-weather/`](https://github.com/OpenHands/enterprise-cookbook/tree/main/plugin-with-script/city-weather) plugin bundles a small Python script, and its
13+
command and skill tell the agent to run that script and show what it prints.
14+
The agent doesn't work out the API calls itself; it runs one command.
15+
16+
Put the work in a script when it should be the same every time: calling an API,
17+
parsing a file, or formatting a report. The result is repeatable, uses fewer
18+
tokens than having the agent improvise, and you can test the script on its own.
19+
20+
## How It Works
21+
22+
```mermaid
23+
sequenceDiagram
24+
participant U as User
25+
participant O as OpenHands
26+
participant A as Agent
27+
participant S as weather.py
28+
participant M as Open-Meteo
29+
U->>O: /city-weather:now Tokyo
30+
O->>O: fetch the plugin into the sandbox
31+
O->>A: message + command text + "Skill location: …/commands/now.md"
32+
A->>S: python3 …/skills/city-weather/scripts/weather.py "Tokyo"
33+
S->>M: geocode the city, fetch the forecast
34+
M-->>S: JSON
35+
S-->>A: formatted report
36+
A-->>U: the report, as printed
37+
```
38+
39+
1. OpenHands fetches the plugin into the sandbox, under
40+
`~/.openhands/cache/plugins/`.
41+
2. The message `/city-weather:now Tokyo` triggers the plugin's command. The
42+
agent receives the command's instructions along with the absolute path of the
43+
file they came from.
44+
3. The instructions say where the script is relative to that file, so the agent
45+
runs it by its absolute path and shows the output.
46+
47+
## Run It
48+
49+
<Tabs>
50+
<Tab title="Load via API">
51+
Use the companion [`load-plugin`](/cookbook/load-plugin) example:
52+
53+
```bash
54+
cd ../load-plugin
55+
pip install requests
56+
export OH_API_KEY="sk-oh-..."
57+
python load_plugin.py \
58+
--repo-path plugin-with-script/city-weather \
59+
--message "/city-weather:now Tokyo"
60+
```
61+
</Tab>
62+
63+
<Tab title="Launch via Badge">
64+
Click to run the command on launch:
65+
66+
[![Get the weather in Tokyo](https://img.shields.io/badge/Get%20the%20weather%20in%20Tokyo-blue)](https://app.all-hands.dev/launch?plugins=W3sic291cmNlIjogImdpdGh1YjpPcGVuSGFuZHMvZW50ZXJwcmlzZS1jb29rYm9vayIsICJyZWYiOiAibWFpbiIsICJyZXBvX3BhdGgiOiAicGx1Z2luLXdpdGgtc2NyaXB0L2NpdHktd2VhdGhlciIsICJwYXJhbWV0ZXJzIjogeyJjaXR5IjogIlRva3lvIn19XQ%3D%3D\&message=%2Fcity-weather%3Anow%20Tokyo)
67+
68+
Or load the plugin and ask in your own words, such as "What's the weather in
69+
Paris?":
70+
71+
[![Open with city-weather loaded](https://img.shields.io/badge/Open%20with%20city--weather%20loaded-blue)](https://app.all-hands.dev/launch?plugins=W3sic291cmNlIjogImdpdGh1YjpPcGVuSGFuZHMvZW50ZXJwcmlzZS1jb29rYm9vayIsICJyZWYiOiAibWFpbiIsICJyZXBvX3BhdGgiOiAicGx1Z2luLXdpdGgtc2NyaXB0L2NpdHktd2VhdGhlciJ9XQ%3D%3D)
72+
</Tab>
73+
</Tabs>
74+
75+
The conversation runs the script once and finishes with its report:
76+
77+
```text
78+
City Weather Report for Tokyo, Japan
79+
80+
- Current Time: 2026-10-10 01:30 GMT+9
81+
- Temperature: 62°F / 16°C
82+
- Current Precipitation: 0.0 mm
83+
84+
Precipitation Forecast (Next 4 Hours):
85+
| Time | Probability |
86+
|-------|-------------|
87+
| 01:00 | 0% |
88+
| 02:00 | 0% |
89+
| 03:00 | 0% |
90+
| 04:00 | 0% |
91+
```
92+
93+
To use the skill instead of the command, send a message such as
94+
`--message "What's the weather in Paris?"`. The skill is triggered by "weather
95+
in", "weather for", and "forecast for", and runs the same script.
96+
97+
<Tip>
98+
To test changes from a branch before they're merged, pass `--ref <branch>` to
99+
`load_plugin.py`. For OpenHands Enterprise, pass `--base-url` with your
100+
install's URL, or rebuild the badges with
101+
[`build_launch_url.py --base-url`](/cookbook/launch-plugin-badge).
102+
</Tip>
103+
104+
## Run the Script Locally
105+
106+
The script uses only the Python standard library and the free
107+
[Open-Meteo](https://open-meteo.com/) API, which needs no key. Run it directly
108+
to check it before the agent does:
109+
110+
```bash
111+
python3 city-weather/skills/city-weather/scripts/weather.py "New York"
112+
```
113+
114+
```text
115+
City Weather Report for New York, United States
116+
117+
- Current Time: 2026-10-09 12:30 GMT-4
118+
- Temperature: 70°F / 21°C
119+
- Current Precipitation: 0.0 mm
120+
...
121+
```
122+
123+
If the city isn't found or Open-Meteo can't be reached, it prints an error and
124+
exits with status 1, and the instructions tell the agent to show that error.
125+
126+
## How the Agent Finds the Script
127+
128+
The plugin is fetched to a path in the sandbox that the plugin author can't
129+
know in advance. When a command or skill fires, OpenHands adds the location of
130+
its file to what the agent sees:
131+
132+
```text
133+
Skill location: /home/openhands/.openhands/cache/plugins/enterprise-cookbook-3c5c88fa6e51c50a/plugin-with-script/city-weather/commands/now.md
134+
(Use this path to resolve relative file references in the skill content below)
135+
```
136+
137+
So write the script's path relative to the file that refers to it:
138+
139+
| File | Location given to the agent | Script path in the instructions |
140+
| ------------------------------ | --------------------------------------- | ------------------------------------------------------- |
141+
| `commands/now.md` | `<plugin>/commands/now.md` | `<plugin>/skills/city-weather/scripts/weather.py` |
142+
| `skills/city-weather/SKILL.md` | `<plugin>/skills/city-weather/SKILL.md` | `scripts/weather.py`, relative to the skill's directory |
143+
144+
The command spells out the relationship so the agent doesn't have to guess:
145+
146+
````markdown city-weather/commands/now.md expandable
147+
---
148+
argument-hint: <city>
149+
description: Report the current weather and precipitation forecast for a city
150+
---
151+
152+
# City Weather Report
153+
154+
Report the weather for the city named in **$ARGUMENTS** by running the script
155+
bundled with this plugin. Don't call the weather APIs yourself.
156+
157+
## Instructions
158+
159+
1. Read the city from the arguments: **$ARGUMENTS**. If it is empty, ask the
160+
user which city they want and wait for their answer.
161+
2. Find the script. The skill location given above is this file,
162+
`<plugin>/commands/now.md`. The script is in the same plugin at
163+
`<plugin>/skills/city-weather/scripts/weather.py`.
164+
3. Run it with the city as its argument, quoted:
165+
166+
```bash
167+
python3 <plugin>/skills/city-weather/scripts/weather.py "<city>"
168+
```
169+
170+
4. Show the script's output to the user exactly as printed. If it exits with an
171+
error, show the error and stop.
172+
173+
## Examples
174+
175+
`/city-weather:now Tokyo`
176+
`/city-weather:now New York`
177+
````
178+
179+
<Info>
180+
This works for commands and skills, which the agent reads. Hooks are different:
181+
OpenHands runs them from the agent's workspace with no plugin-root path, so a
182+
hook can't call a script bundled in its plugin. That's why the hook examples,
183+
such as [`command-blacklist`](/cookbook/command-blacklist), put their script inline in
184+
`hooks.json`.
185+
</Info>
186+
187+
## Where Scripts Go
188+
189+
This plugin follows the
190+
[Claude Code plugin layout](https://code.claude.com/docs/en/plugins-reference),
191+
which OpenHands loads:
192+
193+
- **A script used by one skill** goes in that skill's directory, under
194+
`skills/<skill>/scripts/`. That's where `weather.py` is.
195+
- **A script shared by several skills, or called by hooks,** goes in `scripts/`
196+
at the plugin root.
197+
198+
The command is there so that `/city-weather:now` and the plugin's
199+
`entry_command` can start it on launch. In OpenHands, `entry_command` and
200+
`/<plugin>:<name>` refer to files in `commands/`, while a skill is triggered by
201+
keywords in the message.
202+
203+
<Accordion title="Why not use ${CLAUDE_SKILL_DIR}?">
204+
Claude Code replaces `${CLAUDE_SKILL_DIR}` and `${CLAUDE_PLUGIN_ROOT}` with
205+
absolute paths when it loads a skill, and its docs show bundled scripts referred
206+
to that way. OpenHands doesn't replace these variables, so the agent would see
207+
them as literal text. It gives the agent the skill's location instead, which is
208+
why this plugin's instructions use paths relative to the file.
209+
210+
Claude Code also puts a plugin's `bin/` directory on the `PATH`. OpenHands
211+
doesn't, so call scripts by their path.
212+
</Accordion>
213+
214+
## Plugin Structure
215+
216+
```text
217+
city-weather/
218+
├── .claude-plugin/
219+
│ └── plugin.json # manifest: name, entry_command, parameters
220+
├── commands/
221+
│ └── now.md # /city-weather:now <city>
222+
└── skills/
223+
└── city-weather/
224+
├── SKILL.md # triggered by "weather in", "weather for", "forecast for"
225+
└── scripts/
226+
└── weather.py # the script both of them run
227+
```
228+
229+
## Related
230+
231+
<CardGroup cols={2}>
232+
<Card title="load-plugin" href="/cookbook/load-plugin" icon="plug">
233+
Start a conversation with a plugin loaded through the REST API
234+
</Card>
235+
236+
<Card title="launch-plugin-badge" href="/cookbook/launch-plugin-badge" icon="rocket">
237+
Build launch links and badges like the ones above
238+
</Card>
239+
240+
<Card title="command-blacklist" href="/cookbook/command-blacklist" icon="shield-halved">
241+
A plugin whose script runs as a hook, inlined in hooks.json
242+
</Card>
243+
244+
<Card title="Plugins overview" href="/overview/plugins" icon="book-open">
245+
What plugins are and the format they follow
246+
</Card>
247+
248+
<Card title="Plugin Launcher" href="/openhands/usage/cloud/plugin-launcher" icon="book-open">
249+
The /launch route the badges use
250+
</Card>
251+
252+
<Card title="Claude Code skills" href="https://code.claude.com/docs/en/skills" icon="arrow-up-right-from-square">
253+
Supporting files in a skill directory, including scripts/
254+
</Card>
255+
</CardGroup>

‎docs.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,7 @@
681681
"pages": [
682682
"cookbook/launch-plugin-badge",
683683
"cookbook/load-plugin",
684+
"cookbook/plugin-with-script",
684685
"cookbook/test-mcp-config",
685686
"cookbook/upload-skills"
686687
]

0 commit comments

Comments
 (0)