A minimal, fully-functional Edgeless OTel Command plug-in that renders a "Hello, swarm" panel. Fork this repository to build your own plug-in.
The plug-in registers one sidebar panel called "Example: Hello swarm" that displays a live summary of the current trace data:
- Total trace count and service count for the active time window
- Coloured service pills, one per service
- The last 5 trace IDs (clickable — opens the trace detail view)
It is intentionally minimal. Every line of index.js is commented to explain
the API contract so you can see exactly how to build something real.
edgeless-plugin-example/
manifest.json Declares the plug-in identity and its panel contribution
index.js ES module with the activate() entry point and panel logic
icon.png 64x64 icon shown in the plug-in browser (replace with yours)
LICENSE MIT
README.md This file
.gitignore
-
Locate your Edgeless OTel Command plug-in directory:
~/Library/Application Support/edgeless-otel-command/plugins/ -
Create a subdirectory whose name matches the
idfield inmanifest.json:mkdir -p ~/Library/Application\ Support/edgeless-otel-command/plugins/edgeless.plugin.example
-
Copy the plug-in files into that directory:
cp manifest.json index.js icon.png \ ~/Library/Application\ Support/edgeless-otel-command/plugins/edgeless.plugin.example/
-
Open (or restart) Edgeless OTel Command. The plug-in will appear in Settings → Plug-ins and its panel will appear in the sidebar.
The fastest workflow is to clone directly into the plug-ins directory so that the app loads your working copy:
cd ~/Library/Application\ Support/edgeless-otel-command/plugins/
git clone https://github.com/thedavidmurray/edgeless-plugin-example edgeless.plugin.exampleAfter editing any file:
- Press Cmd+R in Edgeless OTel Command to reload the app (hot-reload of plug-ins does not require a full restart on macOS).
There is no build step. index.js is loaded directly as an ES module.
If you want TypeScript, JSDoc type-checking, or bundling, add those tools
yourself — the host only requires a valid ES module as the entry point.
- Edit
index.js(or add more.jsfiles and import them fromindex.js). - Hit Cmd+R.
- Switch to your panel in the sidebar.
The host calls destroy() on the old instance before loading the new one, so
no cleanup is needed between reloads.
Each panel id under contributes.panels must match the id you pass to
edgeless.panels.register(id, def) in index.js.
// Register a panel (call in activate)
edgeless.panels.register('myPanelId', {
label: 'My Panel',
render(container, ctx) { /* update container DOM */ },
destroy() { /* optional cleanup */ },
});
// Navigate to a trace detail page
edgeless.router.navigate('#/trace/<traceId>');
// Formatting utilities
edgeless.lib.fmtDur(microseconds) // "1.23ms", "45.6s", etc.
edgeless.lib.fmtAge(microseconds) // "3m ago", "just now", etc.
edgeless.lib.hashColor(string) // deterministic hex colour "#a3b4c5"
edgeless.lib.tagsToObj(tagArray) // [{key,value}] → {key: value}
// Logging (appears in View → Developer → Logs)
edgeless.app.log('message', 'debug' | 'info' | 'warn' | 'error');The ctx object passed to render has the same shape every call:
| Field | Type | Description |
|---|---|---|
ctx.traces |
Trace[] |
All traces in the time window |
ctx.byService |
{ [name]: Trace[] } |
Traces grouped by service name |
ctx.services |
string[] |
Sorted unique service names |
ctx.serviceFilter |
string | null |
Active service filter |
ctx.timeWindowMin |
number |
Time window size in minutes |
ctx.settings |
object |
Read-only host settings snapshot |
ctx.lib |
object |
Same as edgeless.lib |
-
Push your plug-in to a public GitHub repository.
-
Open a PR against the official registry:
thedavidmurray/edgeless-otel-plugins-registryYour PR should add a single entry to
registry.json:{ "id": "com.yourname.myplugin", "repo": "https://github.com/yourname/myplugin", "version": "0.1.0" } -
A maintainer will review your plug-in for the Plug-in Guidelines and merge when it passes.
-
Once merged, the plug-in appears in the Edgeless OTel Command built-in plug-in browser within 24 hours.
MIT — see LICENSE.
{ "id": "com.yourname.myplugin", // reverse-DNS, globally unique "name": "My Plug-in", "version": "0.1.0", // semver "description": "One sentence.", "author": "Your Name", "homepage": "https://github.com/...", "license": "MIT", "minAppVersion": "1.2.0", // minimum Edgeless version required "contributes": { "panels": [ { "id": "main", "label": "My Panel" } ] } }