Skip to main content

View source on GitHub

This example builds on load-plugin. That one calls the API with your key to start a conversation with a plugin loaded. Here we make a no-code launch link anyone can click — perfect for an HTML <button> or a Markdown badge in a plugin’s README. Like load-plugin, this example is self-contained: it ships its own dad-joke/ plugin and the launch links load it straight from this repo on GitHub. The link points at the OpenHands frontend /launch route:
When opened, the frontend decodes plugins, shows a confirmation modal (pre-filling any parameter fields), and on submit calls POST /api/v1/app-conversations — the exact call load-plugin makes by hand. The user supplies their own auth by being logged in, so the link contains no secrets.
Official docs: Plugin Launcher is the reference for the /launch route — the plugins/message params, how parameters become editable inputs, and a simpler unencoded format for development. This example is a runnable companion to that page.Full end-to-end trace (marketplace → directory → frontend → app server → SDK): Plugin Launch Flow design doc.

Try It

These are the actual badges this example generates — click one to launch a conversation with the bundled dad-joke plugin: Tell a dad joke   Open with dad-joke loaded
  • Tell a dad joke — runs /dad-joke:about immediately (variant 1).
  • Open with dad-joke loaded — loads the plugin and waits for your prompt (variant 2).
The badges fetch the plugin from this repo’s default branch, so they work once this example is merged to main. Testing from a branch? Regenerate them with --ref your-branch (see below).

Run It

With no arguments it prints two fully worked examples (below). Pass flags to build your own:
No API key needed — this only constructs URLs.

Walkthrough: Encoding the Launch URL

The whole trick is turning a list of plugin specs into one URL-safe query parameter. Three steps (encode_plugins in build_launch_url.py):
Then assemble the URL, URL-escaping each query value (build_launch_url):
Notes:
  • Default json.dumps separators (", " / ": ") are kept, matching the encoding the OpenHands plugin directory uses.
  • URL-escape the base64. Standard base64 can contain +, /, and =, which are unsafe in a query string. quote(..., safe="") turns the = padding into %3D, etc. The frontend reverses this automatically.
  • It’s reversible — decode_plugins() (base64-decode → json.loads) gets you back the original list. The script asserts this round-trip on every run.

The plugin spec fields

parameters are only defaults for the form. The user can edit them in the modal before starting; the app server then formats the final values into the conversation’s first message. (The SDK’s PluginSource itself has no parameters field — see the design doc’s “Parameter Journey”.)

Simpler format for quick tests

For local or staging experiments you can skip base64 entirely and pass unencoded query params — plugin_source, plugin_ref, plugin_repo_path:
The encoded plugins form is what you want for shareable badges — and it’s the only one that supports multiple plugins (or pre-filled parameters) in a single link. Both formats are documented on the Plugin Launcher page.

Two Variants

1. Run a skill on launch — entry command

Set message to the plugin’s entry slash command. The conversation starts and immediately runs the skill. dad-joke declares entry_command: "about", so its command is /dad-joke:about, and the animal parameter pre-fills the modal:
HTML button:
Markdown badge:

2. Just load the plugin — user prompts after

Omit message. The conversation starts with the plugin’s skills loaded but no first action, so the user types their own prompt. The dad-joke skill is keyword-triggered: when the user asks for a joke, it asks for their favorite animal and then delivers.
Markdown badge:

Use the Functions in Your Own Tooling

build_launch_url.py is importable:

load-plugin

the programmatic equivalent (the API call this link ultimately triggers).

Plugin Launcher

official docs for the /launch route.

Plugin Marketplace

the plugin directory: a browseable catalog (served at /plugins, with a /api/plugins API) that builds launch links like these from a marketplace source repo. This example is what that directory does, by hand.

Plugins overview

what plugins are and the format they follow.

Plugin Launch Flow design doc

the full marketplace → directory → frontend → app server → SDK journey.