www/docs/development/plugins/full-featured-plugin.md
Full-featured plugins run inside dedicated hosts (Python or Node.js) and talk to wox.core over WebSocket. They stay loaded, can keep state, and can use the richer Wox API surface such as previews, settings UI, toolbar messages, MRU restore, screenshot capture, AI streaming, and deep links.
Choose this model when your plugin needs one or more of these:
If your plugin is a small one-file automation script, start with the Script Plugin guide instead.
~/.wox/plugins/<your-plugin-id>/plugin.json and your entry file (main.py, index.js, or built output such as dist/index.js)SDK install commands:
uv add wox-pluginpnpm add @wox-launcher/wox-pluginIf you use Codex, see AI Skills For Plugin Development.
These examples return QueryResponse, so the plugin's plugin.json must set
MinWoxVersion to 2.0.4 or newer. Return list[Result] or Result[]
directly if the same plugin build must run on older Wox releases.
from wox_plugin import Plugin, Query, QueryResponse, Result, Context, PluginInitParams
from wox_plugin.models.image import WoxImage
class MyPlugin(Plugin):
async def init(self, ctx: Context, params: PluginInitParams) -> None:
self.api = params.api
self.plugin_dir = params.plugin_directory
async def query(self, ctx: Context, query: Query) -> QueryResponse:
return QueryResponse(results=[
Result(
title="Hello Wox",
sub_title="This is a sample result",
icon=WoxImage.new_emoji("👋"),
score=100,
)
])
plugin = MyPlugin()
import { Plugin, Query, QueryResponse, Context, PluginInitParams } from "@wox-launcher/wox-plugin"
class MyPlugin implements Plugin {
private api!: PluginInitParams["API"]
private pluginDir = ""
async init(ctx: Context, params: PluginInitParams): Promise<void> {
this.api = params.API
this.pluginDir = params.PluginDirectory
}
async query(ctx: Context, query: Query): Promise<QueryResponse> {
return {
Results: [
{
Title: "Hello Wox",
SubTitle: "This is a sample result",
Icon: { ImageType: "emoji", ImageData: "👋" },
Score: 100,
},
],
}
}
}
export const plugin = new MyPlugin()
Returning list[Result] or Result[] directly is deprecated. Python and Node.js hosts still accept the old shape for compatibility with older Wox releases. Use QueryResponse only when plugin.json declares MinWoxVersion >= 2.0.4.
plugin.json essentialsRuntime = PYTHON or NODEJSEntry at the file Wox should executeFeatures only for capabilities you actually useExample:
{
"Id": "my-awesome-plugin",
"Name": "My Awesome Plugin",
"Description": "Do awesome things",
"Author": "You",
"Version": "1.0.0",
"MinWoxVersion": "2.0.4",
"Runtime": "NODEJS",
"Entry": "dist/index.js",
"TriggerKeywords": ["awesome", "ap"],
"Features": [{ "Name": "querySelection" }, { "Name": "ai" }],
"SettingDefinitions": [
{
"Type": "textbox",
"Value": { "Key": "api_key", "Label": "API Key", "DefaultValue": "" }
}
]
}
Wox sends a normalized Query object into query():
Query.Type is input or selectionQuery.RawQuery keeps the original inputQuery.TriggerKeyword, Query.Command, and Query.Search give you the parsed partsQuery.Id is the identifier you should keep when doing async follow-up updatesQuery.Env carries optional environment context when the queryEnv feature is enabledSee Query Model for the exact split and feature-dependent fields.
Each Result can include:
IconPreviewTailsActionsGroup and GroupScoreUseful patterns:
Preview for markdown, text, image, URL, or file previewsTails for badges or small metadataPreventHideAfterAction when an action continues to update the same result in placeIf you need to update a visible result after an action starts, use:
GetUpdatableResultUpdateResultIf you need to stream or append additional results for the same active query, use:
PushResultsDefine your settings UI in plugin.json with SettingDefinitions.
Common setting types:
textboxcheckboxselectselectAIModeltabledynamicheadlabelnewlineAt runtime:
GetSettingSaveSettingOnSettingChangedOnGetDynamicSettingquerySelection: receive text/file selection queriesqueryEnv: receive active-window or browser contextai: use Wox-configured AI APIsdeepLink: register plugin deep linksmru: restore items from Wox MRU storageresultPreviewWidthRatio: deprecated; use QueryResponse.Layout.ResultPreviewWidthRatiogridLayout: deprecated; use QueryResponse.Layout.GridLayoutOnly enable features you actually need. They change how Wox routes queries and builds plugin context.
Wox now exposes a built-in screenshot workflow to full-featured plugins.
Use it when your plugin needs the user to draw a region and then continue processing the resulting PNG path itself, for example:
Screenshot() returns:
Success: whether the capture completed successfullyScreenshotPath: exported PNG path when successfulErrMsg: failure reason, or a warning message when the capture completed with caveatsScreenshotOption supports:
HideAnnotationToolbar: keep the flow focused on raw area selectionAutoConfirm: finish immediately after the user completes a valid selectionconst capture = await this.api.Screenshot(ctx, {
HideAnnotationToolbar: true,
AutoConfirm: true,
})
if (!capture.Success) {
await this.api.Notify(ctx, `Screenshot failed: ${capture.ErrMsg}`)
return
}
await this.api.Notify(ctx, `Saved to ${capture.ScreenshotPath}`)
Behavior notes:
HideAnnotationToolbar unsetai featuredeepLink feature and OnDeepLinkmru feature and OnMRURestoreThese are optional capabilities. Keep the initial version of your plugin smaller if you do not need them yet.
~/.wox/plugins/, or symlink your working directory thereplugin.json, reload the plugin from Wox settings or restart WoxIf your plugin touches core/host contracts, rebuild Wox itself instead of assuming the host will pick up type changes automatically.
When something fails:
plugin.json first~/.wox/log/make build