How to Build a Desktop Plugin
Extend the Biosimulant Desktop app with custom tools or AI agents. Plugins are standalone processes that communicate with the desktop app via JSON-RPC 2.0 over stdin/stdout.
Plugin kinds
| Kind | Use Case |
|---|---|
tool_provider | Utility tools, data processing, custom commands |
agent_provider | AI agents that can run sessions, send turns, handle approvals |
Step 1: Create the manifest
Create a plugin.json:
{
"id": "com.example.my-tool",
"name": "My Tool",
"version": "0.1.0",
"description": "A custom tool for Biosimulant Desktop",
"kind": "tool_provider",
"entrypoint": "python main.py",
"permissions": [
"workspace:read"
],
"capabilities": [
"tool:custom_action"
],
"ui": {
"contributions": [
{
"slot": "sidebar.item",
"label": "My Tool",
"icon": "wrench"
}
]
}
}Step 2: Implement the JSON-RPC protocol
Your plugin must handle two required methods:
# main.py
import sys
import json
def handle_request(request):
method = request.get("method")
req_id = request.get("id")
if method == "plugin/health":
return {"jsonrpc": "2.0", "id": req_id, "result": {"status": "ok"}}
if method == "plugin/shutdown":
return {"jsonrpc": "2.0", "id": req_id, "result": {"status": "ok"}}
if method == "tool/custom_action":
params = request.get("params", {})
result = do_something(params)
return {"jsonrpc": "2.0", "id": req_id, "result": result}
return {
"jsonrpc": "2.0",
"id": req_id,
"error": {"code": -32601, "message": f"Method not found: {method}"},
}
def do_something(params):
# Your tool logic here
return {"message": "Done!", "data": params}
def main():
for line in sys.stdin:
line = line.strip()
if not line:
continue
try:
request = json.loads(line)
response = handle_request(request)
sys.stdout.write(json.dumps(response) + "\n")
sys.stdout.flush()
except json.JSONDecodeError:
pass
if __name__ == "__main__":
main()Step 3: Add UI contributions
Plugins can contribute to these UI slots:
| Slot | Description |
|---|---|
sidebar.item | Icon + label in the main sidebar |
page.main | Full-page view when sidebar item is clicked |
lab.sidepanel | Tab in the lab detail sidebar |
settings.section | Section in the settings page (planned) |
Step 4: Test locally
- Open Biosimulant Desktop
- Go to Settings > Plugins
- Click Install from file
- Select your plugin directory (containing
plugin.json) - The plugin appears in the sidebar
Step 5: Package for distribution
Create a .bsiplugin archive:
# Build script
mkdir -p dist
tar -czf dist/my-tool.bsiplugin \
plugin.json \
main.py \
requirements.txtCalling host methods
Your plugin can call back to the desktop app:
def call_host(method, params=None):
request = {
"jsonrpc": "2.0",
"id": next_id(),
"method": method,
"params": params or {},
}
sys.stdout.write(json.dumps(request) + "\n")
sys.stdout.flush()
# Read response from stdin
response = json.loads(sys.stdin.readline())
return response.get("result")
# Check connectivity
result = call_host("host/ping")
# Request user approval for an action
approval = call_host("host/request_approval", {
"action": "delete_model",
"description": "Delete model xyz from workspace"
})Environment variables
The host sets these when spawning your plugin:
| Variable | Description |
|---|---|
BIOSIMULANT_PLUGIN_INSTALL_DIR | Plugin installation directory |
BIOSIMULANT_PLUGIN_DATA_DIR | Persistent data directory for your plugin |
BIOSIMULANT_DESKTOP_VERSION | Desktop app version |
For complete working examples, see the Reference Examples page, which includes a tool_provider (Echo) and an agent_provider (Codex) with full source code.
Next Steps
- Plugin Manifest Reference: full manifest schema
- Runtime & JSON-RPC: protocol details
- UI Contributions: all available slots
- Packaging & Distribution: publishing to the registry