File: README.md
A launcher that stays out of your way
You already know what you want to do. Wox helps you get there: open an app, find a file, run an action โ then get out of the way.
Wox is a fully native, open-source launcher for macOS, Linux, and Windows โ with GPU rendering on every platform. Everyday use typically stays around ~150 MB of memory, so it can live in the background without feeling like another heavy desktop app.
Local search, keyboard-first actions, and an extensible plugin system stay in one focused input.
Download Wox ยท Browse plugins ยท Read the docs
Press Alt/Command + Space, type what you need, and press Enter.
https://github.com/user-attachments/assets/1b282fde-c1c5-426a-b45d-cd0aa329386a
Why Wox
| Fully native | Full native GPU rendering on macOS, Linux, and Windows โ not Electron, not a browser shell. |
| ~150 MB memory | Built to stay light while idle and during everyday queries, so the launcher can stay resident without taxing the machine. |
| Keyboard-first | Open apps, find files, run actions, and finish the next step without leaving the input. |
| Plugin-driven | Start with built-ins, then extend with Node.js, Python, or script plugins from the store. |
Install
| Platform | Method | Command or instructions |
|---|---|---|
| macOS | Homebrew | brew install --cask wox |
| Windows | Winget | winget install -e --id Wox.Wox |
| Windows | Scoop | scoop install extras/wox |
| Windows | Chocolatey | choco install wox |
| Arch Linux | AUR | yay -S wox-bin |
| Debian / Ubuntu | .deb |
Download wox-linux-amd64.deb from Releases, then sudo apt install ./wox-linux-amd64.deb |
| Fedora / RHEL | .rpm |
Download wox-linux-amd64.rpm from Releases, then sudo dnf install ./wox-linux-amd64.rpm |
| openSUSE | .rpm |
Download wox-linux-amd64.rpm from Releases, then sudo zypper install ./wox-linux-amd64.rpm |
| macOS / Linux / Windows | Manual | Download the latest stable package from Releases and run it directly |
Documentation
Contributing
Contributions are welcome through issues, discussions, and pull requests.
Sponsors
| Free code signing on Windows provided by SignPath.io, with certificates from SignPath Foundation. |
|---|
Project Activity
File: screenshots/README.md
APP
AI Chat
Setting
Fallback Search
Auto Theme
File: wox.core/common/README.md
Due to the GO's cyclic reference limitation, some common type definitions are defined in this package
File: wox.core/migration/README.md
Migration (one file per migration)
Wox uses an application-level migration runner (separate from Gorm AutoMigrate) for data / settings compatibility upgrades.
How it works
- Each migration is a Go file under
wox.core/migration/(same package:migration). - Each file registers itself via
init()+migration.Register(...). - Migrations run in lexicographic order of
ID(). - Applied/skipped migrations are persisted in SQLite table
migration_records(model:database.MigrationRecord).
Create a new migration
- Add a file like
wox.core/migration/mYYYYMMDD_short_name.go - Implement the interface:
type Migration interface {
ID() string
Description() string
Up(ctx context.Context, tx *gorm.DB) error
}- Register it:
func init() { Register(&myMigration{}) }Optional hooks
- If a migration only applies under certain conditions, implement:
type ConditionalMigration interface {
Migration
IsNeeded(ctx context.Context, db *gorm.DB) (bool, error)
}- If a migration needs filesystem actions after DB commit (e.g. rename legacy files), implement:
type PostCommitMigration interface {
Migration
AfterCommit(ctx context.Context) error
}File: wox.core/plugin/system/mediaplayer/woxmr/README.md
WoxMR (MediaRemote XS Bridge)
Why do we need WoxMR?
- On macOS 15+, Apple restricts the private MediaRemote framework: only processes with bundle ids starting with
com.apple.*may call it. - The Wox process is not
com.apple.*, so calls would be rejected even with dynamic loading from Go/CGO. - The system
/usr/bin/perlprocess has the bundle idcom.apple.perl, which is permitted to access MediaRemote. - Therefore we run MediaRemote inside the
com.apple.perlprocess and pass results back to Wox.
How it works
- We ship a tiny Perl XS module
woxmr.bundlethat is loaded and executed inside the Perl process. - In the XS module (ObjectiveโC), we dynamically load MediaRemote (dlopen + dlsym) and call:
MRMediaRemoteGetNowPlayingInfoMRMediaRemoteGetNowPlayingApplicationIsPlayingMRMediaRemoteGetNowPlayingApplicationPID
- We assemble Now Playing data (title/artist/album/duration/position/playing, plus appName/bundleIdentifier) and return JSON to Perl.
- Wox runs a small Perl adapter (adapter.pl) to get the JSON and then parses it.
Why not Go/CGO directly?
- Even with dynamic loading from CGO, the caller remains the Wox process (not
com.apple.*) and will be denied by the system. - Moving the callsite into
/usr/bin/perl(com.apple.perl) naturally bypasses the restriction with zero extra requirements on endโuser machines.
Why not an external framework?
- Avoid shipping a large private framework: simpler distribution, signing, and maintenance.
- We only ship a tiny
woxmr.bundle(XS) +WoxMR.pm+adapter.pl: small, stable, and maintainable.
Build & distribution
- Build happens only on a developer machine (requires Xcode CLT and system Perl).
- End users need no dependencies. Distribute:
resource/others/woxmr/woxmr.bundleresource/others/woxmr/WoxMR.pmresource/others/woxmr/adapter.pl
- The topโlevel Makefile exposes
woxmr-build:- It autoโcleans, builds for the current arch (arm64/x86_64), forceโsigns, and copies artifacts to the paths above.
- It is also invoked automatically by the overall
make build.
Runtime flow
- Wox runs adapter.pl:
/usr/bin/perl resource/others/woxmr/adapter.pl get
- adapter.pl uses
WoxMRto load and execute the XS code inside Perl:- The XS code accesses MediaRemote and returns a JSON string.
- Wox parses the JSON and displays the Now Playing information.
File: wox.plugin.nodejs/README.md
Wox Plugin SDK for TypeScript/JavaScript
TypeScript type definitions and SDK for developing Wox plugins in TypeScript/JavaScript.
Quick Start
Installation
npm install wox-pluginBasic Plugin
This example returns QueryResponse, so the plugin's plugin.json should setMinWoxVersion to 2.0.4 or newer. Return Result[] directly if you need the
same plugin build to run on older Wox releases.
import { Plugin, Context, Query, QueryResponse, Result, NewContext, WoxImage } from "wox-plugin"
class MyPlugin implements Plugin {
private api: PublicAPI
async init(ctx: Context, initParams: PluginInitParams): Promise<void> {
this.api = initParams.API
await this.api.Log(ctx, "Info", "MyPlugin initialized")
}
async query(ctx: Context, query: Query): Promise<QueryResponse> {
const results: Result[] = []
for (const item of this.getItems(query.Search)) {
results.push({
Title: item.name,
SubTitle: item.description,
Icon: { ImageType: "emoji", ImageData: "๐" },
Score: 100,
Actions: [
{
Name: "Open",
Icon: { ImageType: "emoji", ImageData: "๐" },
IsDefault: true,
Action: async (ctx, actionCtx) => {
await this.openItem(item)
}
}
]
})
}
return { Results: results }
}
}Key Components
Plugin Interface
Every plugin must implement the Plugin interface:
interface Plugin {
init: (ctx: Context, initParams: PluginInitParams) => Promise<void>
query: (ctx: Context, query: Query) => Promise<QueryReturn>
}Returning Result[] directly is deprecated. The Node.js host still accepts it
for compatibility with older Wox releases. Use QueryResponse only whenplugin.json declares MinWoxVersion >= 2.0.4 so results, refinements, and
layout hints are carried together.
When a plugin needs to control the preview width or grid layout, setQueryResponse.Layout.ResultPreviewWidthRatio or QueryResponse.Layout.GridLayout.
The older resultPreviewWidthRatio and gridLayout metadata features are
deprecated because they can only describe static plugin or command defaults.
Query Models
- Query: User query with search text, type, selection, environment
- QueryType:
INPUT(typing) orSELECTION(selected content) - Selection: Text or file paths selected by user
- QueryEnv: Environment context (active window, browser URL)
Result Models
- Result: Search result with title, icon, preview, actions
- ResultAction: User action on a result
- ResultActionType:
EXECUTE(immediate) orFORM(show form) - ResultTail: Additional visual elements (text or image)
- UpdatableResult: Result that can be updated in UI
Image Types
Supported image types:
absolute: Absolute file pathrelative: Path relative to plugin directorybase64: Base64 encoded image with data URI prefix (data:image/png;base64,...)svg: SVG string contenturl: HTTP/HTTPS URLemoji: Emoji character
// Emoji icon
{ ImageType: "emoji", ImageData: "๐" }
// Base64 image
{ ImageType: "base64", ImageData: "data:image/png;base64,iVBORw0..." }
// Relative path
{ ImageType: "relative", ImageData: "./icons/icon.png" }Public API
Methods for interacting with Wox:
- UI Control:
showApp(),hideApp(),isVisible(),notify() - Toolbar Msg:
ShowToolbarMsg(),ClearToolbarMsg(),OnEnterPluginQuery(),OnLeavePluginQuery() - Query:
changeQuery(),refreshQuery(),pushResults() - Settings:
GetSetting(),SetSetting(),OnSettingChanged(); legacySaveSetting()remains available but is deprecated - Logging:
log() - i18n:
getTranslation() - Results:
getUpdatableResult(),updateResult() - AI:
llmStream() - MRU:
onMruRestore() - Callbacks:
onUnload(),onDeepLink() - Commands:
registerQueryCommands() - Clipboard:
copy()
Actions
Actions are operations users can perform on results:
ResultAction({
name: "Copy",
icon: { ImageType: "emoji", ImageData: "๐" },
isDefault: true,
hotkey: "Ctrl+C",
action: async (ctx, actionCtx) => {
await this.copyToClipboard(actionCtx.contextData)
}
})Settings
Define settings for your plugin:
SetSetting() requires Wox >= 2.4.0 and accepts a single SetSettingOption. SetIsLocal: true when a value must stay on the current device and remain outside
Cloud Sync. Use legacy SaveSetting() only when the same plugin build must run
on Wox releases before 2.4.0.
const settings: PluginSettingDefinitionItem[] = [
{
Type: "textbox",
Value: {
Key: "apiKey",
Label: "API Key",
Suffix: "",
DefaultValue: "",
Tooltip: "Enter your API key",
MaxLines: 1,
Validators: []
} as PluginSettingValueTextBox,
DisabledInPlatforms: [],
IsPlatformSpecific: false
},
{
Type: "checkbox",
Value: {
Key: "enabled",
Label: "Enable Feature",
DefaultValue: "true",
Tooltip: ""
} as PluginSettingValueCheckBox,
DisabledInPlatforms: [],
IsPlatformSpecific: false
}
]Style is deprecated and should not be used for new settings. Wox owns setting
spacing and control widths so plugin settings remain visually consistent.
AI/LLM Integration
Stream responses from AI models:
const conversations: AI.Conversation[] = [
{ Role: "system", Text: "You are a helpful assistant.", Timestamp: Date.now() },
{ Role: "user", Text: "Hello!", Timestamp: Date.now() }
]
await api.LLMStream(ctx, conversations, (data: AI.ChatStreamData) => {
if (data.Status === "streaming") {
console.log("Chunk:", data.Data)
} else if (data.Status === "finished") {
console.log("Complete:", data.Data)
}
})Plugin Metadata
Plugins must declare metadata in a plugin.json file:
{
"ID": "com.myplugin.example",
"Name": "My Plugin",
"Author": "Your Name",
"Version": "1.0.0",
"MinWoxVersion": "2.0.4",
"Runtime": "nodejs",
"Entry": "main.js",
"TriggerKeywords": ["my"],
"Description": "My awesome Wox plugin",
"Website": "https://github.com/user/myplugin",
"Icon": "https://example.com/icon.png",
"QueryRequirements": {
"AnyQuery": [
{
"SettingKey": "apiKey",
"Validators": [{ "Type": "not_empty" }],
"Message": "i18n:my_plugin_api_key_required"
}
],
"QueryWithoutCommand": [],
"QueryWithCommand": {
"download": [
{
"SettingKey": "downloadPath",
"Validators": [{ "Type": "not_empty" }]
}
]
}
}
}Query Flow
- User triggers Wox and types trigger keyword (e.g., "my query")
- Wox calls
plugin.query()with:query.TriggerKeyword = "my"query.Command = ""query.Search = "query"
- Plugin returns
QueryResponsewhenMinWoxVersionis at least2.0.4 - Wox displays results sorted by score
For More Information
- Wox Documentation: https://github.com/Wox-launcher/Wox
- Plugin Examples: https://github.com/Wox-launcher/Wox.Plugin.Nodejs
File: wox.plugin.python/README.md
Wox Plugin Python
This package provides type definitions for developing Wox plugins in Python.
Requirements
- Python >= 3.8 (defined in
pyproject.toml) - Python 3.12 recommended for development (defined in
.python-version)
Installation
# Using pip
pip install wox-plugin
# Using uv (recommended)
uv add wox-pluginUsage
This example returns QueryResponse, so the plugin's plugin.json should setMinWoxVersion to 2.0.4 or newer. Return list[Result] directly if you need
the same plugin build to run on older Wox releases.
from wox_plugin import Query, QueryResponse, Result, Context, PluginInitParams, WoxImage
class MyPlugin:
async def init(self, ctx: Context, params: PluginInitParams) -> None:
self.api = params.API
async def query(self, ctx: Context, query: Query) -> QueryResponse:
# Your plugin logic here
results = []
results.append(
Result(
title="Hello Wox",
sub_title="This is a sample result",
icon=WoxImage.new_emoji("๐"),
score=100
)
)
return QueryResponse(results=results)
# MUST HAVE! The plugin class will be automatically loaded by Wox
plugin = MyPlugin()Returning list[Result] directly is deprecated. The Python host still accepts
it for compatibility with older Wox releases. Use QueryResponse only whenplugin.json declares MinWoxVersion >= 2.0.4 so results, refinements, and
layout hints are carried together.
When a plugin needs to control the preview width or grid layout, setQueryResponse.layout.result_preview_width_ratio orQueryResponse.layout.grid_layout. The older resultPreviewWidthRatio andgridLayout metadata features are deprecated because they can only describe
static plugin or command defaults.
Saving Settings
set_setting() requires Wox >= 2.4.0 and accepts a SetSettingOption. Setis_local=True when a value must stay on the current device and remain outside
Cloud Sync. The older save_setting() method remains available for plugins
targeting Wox releases before 2.4.0, but is deprecated for new integrations.
Query Requirements
Plugins can declare settings that must be configured before Wox calls query():
{
"QueryRequirements": {
"AnyQuery": [
{
"SettingKey": "apiKey",
"Validators": [{ "Type": "not_empty" }],
"Message": "i18n:my_plugin_api_key_required"
}
],
"QueryWithoutCommand": [],
"QueryWithCommand": {
"download": [
{
"SettingKey": "downloadPath",
"Validators": [{ "Type": "not_empty" }]
}
]
}
}
}License
MIT