Build custom panels, tools, and web apps that run inside Jarvis with full IPC access
The Jarvis plugin system lets you build custom panels, tools, and web applications that run inside Jarvis with full access to the IPC bridge. Plugins appear in the command palette and load as webview panes — the same mechanism that powers built-in panels like Settings, Chat, and Games.
The plugin system is organized into two tiers, each with different capabilities and complexity:
Tier
What it is
Where it lives
What it can do
Bookmark
A named URL
config.toml
Opens any website in a Jarvis pane
Local Plugin
HTML/JS/CSS folder
~/.config/jarvis/plugins/
Full jarvis:// protocol + IPC bridge
Bookmark plugins are the simplest form: a name, a URL, and an optional category, all declared in your configuration file. They require no files on disk and load any website directly in a Jarvis pane.Local plugins are full HTML/JS/CSS applications that live in a folder on your filesystem. They are served through the jarvis:// custom protocol, have access to the IPC bridge (window.jarvis.ipc), and can communicate bidirectionally with the Rust backend.Both tiers appear as entries in the command palette. Selecting a plugin navigates the focused pane to the plugin’s content. Pressing Escape returns the pane to its previous state.
Understanding the complete loading flow helps when debugging or building more advanced plugins:
1. Jarvis starts (or ReloadConfig is dispatched) ↓2. discover_local_plugins() scans ~/.config/jarvis/plugins/ - Lists subdirectories - Reads plugin.toml from each - Builds LocalPlugin { id, name, category, entry } ↓3. Each plugin dir is registered with the ContentProvider ↓4. User opens command palette (Cmd+Shift+P) ↓5. inject_plugin_items() creates palette entries: - Bookmarks → Action::OpenURL("https://...") - Local → Action::OpenURL("jarvis://localhost/plugins/{id}/{entry}") ↓6. User selects a plugin from the palette ↓7. dispatch(Action::OpenURL(url)) - The focused pane's webview navigates to the URL - The previous URL is saved (so Escape can go back) ↓8. WebView requests jarvis://localhost/plugins/my-plugin/index.html ↓9. Custom protocol handler → ContentProvider.resolve() - Reads the file from disk - Performs containment check (directory traversal protection) - Returns 200 with correct MIME type ↓10. Plugin HTML loads with the IPC bridge already injected (window.jarvis.ipc is available immediately) ↓11. User presses Escape → navigates back to the previous page
The IPC bridge is injected into every webview at creation time, not by the plugin. Your plugin’s JavaScript can use window.jarvis.ipc without any setup.