openusage-cli is a cross-platform HTTP daemon that executes OpenUsage plugins and exposes usage snapshots over local HTTP.
The project is implemented in Rust with tokio + rquickjs, and is designed for maximum compatibility with upstream openusage plugin contracts.
- Loads vendored plugin manifests and scripts from
vendor/openusage/plugins - Runs plugin
probe(ctx)in a QuickJS runtime compatible with OpenUsage host APIs - Exposes daemon HTTP endpoints:
GET /healthGET /v1/pluginsGET /v1/usageGET /v1/usage/{provider}POST /v1/probe
- Keeps an in-memory snapshot cache with periodic background refresh
- Publishes per-user daemon discovery files for local client auto-connect
To minimize divergence from upstream:
- Plugin engine files are copied from upstream into
src/plugin_engine/ - Upstream references are vendored into
vendor/openusage/:README.mdLICENSEplugins/**docs/plugins/api.mddocs/plugins/schema.mdsrc-tauri/src/plugin_engine/**
This allows using upstream plugins with minimal or zero changes.
Two AUR packages are available:
openusage-cli- stable release packageopenusage-cli-git- latestmainsnapshot
Install one of them with your AUR helper:
# stable
yay -S openusage-cli
# development (git)
yay -S openusage-cli-gitDownload the latest .deb from GitHub Releases, then install:
sudo apt install ./openusage-cli_<version>_<arch>.debDownload the latest .rpm from GitHub Releases, then install:
# Fedora / RHEL / Rocky / AlmaLinux
sudo dnf install ./openusage-cli-<version>-1.<arch>.rpm
# openSUSE
sudo zypper install ./openusage-cli-<version>-1.<arch>.rpmopenusage-cli query --host 127.0.0.1 --port 0If mode is omitted, query is used by default, so this is equivalent:
openusage-cli --host 127.0.0.1 --port 0Default bind port is 0 (random free port assigned by OS).
Commands:
query(default mode; one-shot JSON output, tries running daemon first)run-daemon(start daemon mode; defaults to background process + parent exit)show-default-config(print defaultconfig.yamltemplate to stdout)install-systemd-unit(create~/.config/systemd/user/openusage-cli.service)version(print version)help(print help)
Global flags (work with any command):
--log-level <error|warn|info|debug|trace>
Runtime flags (query, run-daemon):
--plugins-dir <path>(orOPENUSAGE_PLUGINS_DIR)--enabled-plugins <csv-globs>(orOPENUSAGE_ENABLED_PLUGINS, default:*)--port <port>(default:0= random free port)--app-data-dir <path>(orOPENUSAGE_APP_DATA_DIR)--plugin-overrides-dir <path>(orOPENUSAGE_PLUGIN_OVERRIDES_DIR)--refresh-interval-secs <seconds>(default:300)
run-daemon-only flags:
--existing-instance <error|ignore|replace>(default:error; controls behavior when a running daemon is already discovered)--service-mode <standalone|systemd>(default:standalone; mainly for service managers)--foreground[=true|false](optional value;--foregroundmeanstrue; default:false)--daemon-child(internal hidden flag used by process managers)
Default plugin auto-discovery order (when --plugins-dir is not set):
When running from source (openusage-cli from target/{debug,release}):
<repo_root>/vendor/openusage/plugins<repo_root>/plugins<executable_dir>/vendor/openusage/plugins<executable_dir>/plugins<prefix>/share/openusage-cli/openusage-plugins(derived from executable path)/usr/share/openusage-cli/openusage-plugins
When running as an installed binary (Linux/FHS layout):
<prefix>/share/openusage-cli/openusage-plugins(derived from executable path, e.g./usr/bin->/usr/share)/usr/share/openusage-cli/openusage-plugins
run-daemon --foreground keeps the daemon in foreground (useful for service managers or local debugging).
To help other local applications auto-discover the running daemon, openusage-cli publishes one runtime file per user:
daemon-endpoint- plain-text full daemon URL including scheme (for example,http://127.0.0.1:6737orhttp://[::1]:6737)
Path resolution for discovery files:
ProjectDirs::runtime_dir()/runtime(preferred)- fallback:
ProjectDirs::data_local_dir()/runtime - fallback when
ProjectDirsis unavailable:./.openusage-cli/runtime
Current filename inside that directory:
daemon-endpoint
Lifecycle behavior:
- File is written atomically after HTTP bind succeeds.
- File is removed on graceful shutdown.
- If daemon binds to
0.0.0.0or::, published endpoint is normalized to localhost for client connections. - When
--existing-instance=ignoreis set, discovery file publication is disabled.
Recommended client flow:
- Read
daemon-endpointfrom the discovery path. - Use its content as base URL.
- Call
GET /healthto verify liveness, then query other API endpoints.
- Config path is resolved via
ProjectDirs::from("com", "openusage", "openusage-cli")asconfig_dir()/config.yaml, with fallback to./.openusage-cli/config.yaml. - If the file is missing, daemon startup continues with CLI/env/default values (no auto-create).
- To print a full default config template with comments, run:
openusage-cli show-default-configopenusage-cli can load per-plugin override scripts from a separate directory.
- When running from source, default lookup is
<repo_root>/plugin-overrides, then<executable_dir>/plugin-overrides, then packaged paths. - When running installed binary, lookup is
<prefix>/share/openusage-cli/plugin-overrides, then/usr/share/openusage-cli/plugin-overrides. - Override filename patterns (first match wins):
<plugin-id>.js<plugin-id>.override.js<plugin-id>/override.js
Override scripts run after upstream plugin code is loaded and receive helper API in globalThis.__openusage_override:
pluginIdoriginalProbe(ctx)replaceProbe((ctx, originalProbe) => ...)wrapProbe((ctx, currentProbe, originalProbe) => ...)resetProbe()
Optional AST patch manifest (for patching internal non-exported plugin functions before eval):
globalThis.__openusage_ast_patch = {
functions: [
{ target: "loadAuth", with: "patchLoadAuth", mode: "wrap" },
{ target: "saveAuth", with: "patchSaveAuth", mode: "wrap" },
],
}
function patchLoadAuth(original, ctx) {
return original(ctx)
}
function patchSaveAuth(original, ctx, authState) {
return original(ctx, authState)
}When AST patching is enabled, the original function is renamed to __openusage_original_<target>, and your patch function is called via wrapper.
Example probe wrapper skeleton:
// plugin-overrides/codex.js
globalThis.__openusage_override.wrapProbe(function (ctx, currentProbe, originalProbe) {
// Later you can add custom API-key lookup from your own file here.
// You can call the original plugin behavior whenever needed:
return currentProbe(ctx)
})cargo testCurrent tests include:
- vendored plugin loading smoke test
- real runtime probe test for
mockplugin - compatibility harness that validates all vendored plugin scripts can register and run
probe(ctx)in a stubbed OpenUsage-like JS context without missing host APIs
Install helper cargo subcommands once:
cargo install cargo-deb cargo-generate-rpmBuild packages:
make deb
make rpm
# or both
make packagesPackage layout:
- Binary:
/usr/bin/openusage-cli - Upstream plugins:
/usr/share/openusage-cli/openusage-plugins - Override plugins:
/usr/share/openusage-cli/plugin-overrides
Cargo.tomlkeeps a fixed dev version (0.0.0) on branches.- Production release version comes from the git tag (
vX.Y.Z) in GitHub Actions. - The release workflow validates tag format, injects tag version into
Cargo.tomlfor packaging, and exportsOPENUSAGE_BUILD_VERSIONso the binary reports the tagged version. - To avoid tag typos locally, use:
make release-tag VERSION=0.2.0
git push origin v0.2.0