An .epack v1 file is a ZIP container with UTF-8 POSIX relative member names.
It contains exactly one manifest.json, one integrity.json, a license file,
optional backend wheels, optional frontend/ resources, and build metadata.
Every regular member except integrity.json is listed in
integrity.json.files by its SHA-256 digest. Unlisted, missing, duplicate,
case-colliding, encrypted, symbolic-link, unsafe Windows or path-traversing
members are rejected. V1 packages are unsigned; packages carrying signature
material are rejected until a verifiable signature profile is defined.
The manifest contract is defined by manifest-v1.schema.json. Runtime checks
add constraints not expressible in the schema:
- permission and command names must be unique;
workspace.writeandworkspace.readcannot both be declared;- commands, health checks and services require exactly one artifact with the
pluginrole; - WebUI-only plugins can omit backend artifacts, and CLI-only plugins can omit
webui; source-wheeluses apy3wheel tag;pyc-wheeluses an exact declared CPython tag and matching bytecode magic;- command, health-check and service entry modules must load from the installed backend;
webui.entrynames an HTML file belowfrontend/, with no source maps or links;- a plugin declares at least one command, WebUI page, health check, or service.
Plugin commands use this ABI:
def main(argv, context):
return 0argv excludes the executable name. context is
env.plugins.sdk.RuntimeContext. Returning None means success; an integer is
used as the process exit status.
Plugin WebUI declarations use this shape:
{
"webui": {
"entry": "frontend/index.html",
"icon": "chart-no-axes-combined",
"frontend_sdk": ">=1.0.0,<2.0.0",
"keep_alive": false,
"launch_requirements": {
"all": [
{"type": "file", "pattern": "rtconfig.py"},
{"any": [
{"type": "directory", "pattern": "test_*"},
{"type": "file", "pattern": "test_*.md"}
]}
]
}
}
}keep_alive is optional and defaults to false. When set to true, Env keeps
the plugin iframe mounted while navigating between WebUI pages, preserving
browser-local page state. It is released when the plugin is disabled, upgraded,
uninstalled, or the WebUI exits.
Instead of a registered icon identifier, webui.icon may reference a bundled
image:
{
"icon": {"type": "png", "path": "frontend/icon.png"}
}Only svg and png assets below frontend/ are accepted. Env verifies that
the declared file is present in the package and serves it through the same
tokenized plugin asset prefix used by the WebUI.
launch_requirements is optional and describes files or directories that must
exist below the current WebUI workspace for the plugin to appear in the left
navigation. pattern is a safe POSIX-relative path or glob. A file or
directory node matches only that type; all, any and not combine nodes.
The plugin remains available from the plugin center when requirements are not
satisfied, so users can inspect or open it without changing the manifest.
Plugins that provide a long-running local HTTP/WebSocket backend may declare a supervised service:
{
"service": {
"entry": "package.service:create_service",
"health_path": "/health",
"start_timeout": 15
}
}The entry is called as entry(context, host, port) in a child process. context
is an env.plugins.sdk.RuntimeContext, and the callable must return an ASGI
application (or an object with an app attribute):
def create_service(context, host, port):
return appEnv starts the service on the first backend request, checks health_path, binds
it to a random loopback port, and proxies requests from
/plugins/<id>/backend/. Plugin asset pages may use the tokenized
/plugin-assets/<token>/<id>/backend/ equivalent returned by the WebUI session
API. The tokenized prefix is bound to the plugin ID. health_path must be an
absolute safe HTTP path, and start_timeout must
be an integer from 1 to 60 seconds. The service runner uses Uvicorn, so
uvicorn and its runtime dependencies must be available as backend dependency
wheels. The process is stopped when the plugin is disabled, upgraded,
uninstalled, or the WebUI exits.
Frontend files are prebuilt. Env installs them in the same version transaction as backend wheels and serves only the active, enabled, authorized version.
The host context is versioned and may include httpBase, websocketBase and a
list of transport features. Env does not interpret plugin business messages;
future device, tool and debugger protocols are plugin-owned extensions.