The whitespace between your workflow tool and everything that talks to it.
wispy is a Python library and command-line client for the Workflow Server
Protocol (WSP) — a small JSON-RPC 2.0 protocol that lets workflow tools
(environment managers, task runners, test runners, and so on) expose their
capabilities to consuming tools through a uniform interface, in the same spirit
as the Language Server Protocol does for editors.
If you build a workflow tool, wispy lets you ship a WSP server with one
import. If you want to talk to one, the bundled wsp CLI gives you a working
client out of the box, plus a built-in fallback workflow tool backed by
venv so the CLI is useful before any tool is installed.
- Standard JSON-RPC 2.0 over LSP-style
Content-Lengthframing on stdio — any JSON-RPC client library can talk to a wispy server. - Two integration paths. Take a runtime dependency and register Python callables, or stay decoupled with a TOML/JSON config file that points at imports or external commands.
- Batteries-included CLI.
wspperforms the per-call lifecycle (initialize→ method →shutdown→exit) and translates JSON-RPC errors into well-defined exit codes. - Working fallback workflow tool. With no target configured,
wspmanages on-disk virtual environments throughenvironment/list,create,get,delete, andexecute, persisted across invocations. - Verified by property-based tests. The dispatcher, framing, lifecycle FSM,
registry, and error model are exercised under
hypothesis, with integration tests covering the full transport on top.
pip install wispywispy requires Python 3.10 or newer and has no runtime dependencies on
3.11+ (3.10 pulls in tomli for TOML parsing).
With nothing else configured, the CLI runs the in-process fallback workflow
tool, which uses venv to manage environments under
$WISPY_STATE_DIR (defaults to $XDG_STATE_HOME/wispy/fallback/ on POSIX,
%LOCALAPPDATA%\wispy\fallback\ on Windows).
# Create an environment.
wsp environment/create --name scratch --python-version 3.12
# List environments.
wsp environment/list
# Run a command inside one.
echo '{"id":"<env-id>","argv":["python","-V"]}' | wsp environment/execute --params-json -
# Delete it.
wsp environment/delete --id <env-id>import asyncio
from wispy import Capabilities, HandlerRegistry, run_stdio
def initialize(_params):
return Capabilities(
methods=tuple(registry.methods()),
protocol_version="0.1.0",
).to_jsonable()
def list_envs(_params):
return [
{"id": "default", "name": "default", "python_version": "3.12"},
]
registry = HandlerRegistry()
registry.register("initialize", initialize)
registry.register("shutdown", lambda _params: None)
registry.register("environment/list", list_envs)
raise SystemExit(asyncio.run(run_stdio(registry)))If you don't want a runtime dependency on wispy, ship a TOML file that
maps WSP methods to your CLI's subcommands. wispy renders the request
params into argv with {name}-style substitution and constructs the WSP
result per a per-method result mode.
# my-tool.toml
[handlers."environment/list"]
command = ["my-tool", "env", "show", "--json"]
result = "json"
[handlers."environment/create"]
command = ["my-tool", "env", "create", "{name}", "-p", "{python_version}"]
result = "template"
template = { id = "{name}", name = "{name}", python_version = "{python_version}", interpreter_path = "", installed_packages = [], extra = {} }
[handlers."environment/delete"]
command = ["my-tool", "env", "remove", "{id}"]
result = "template"
template = { id = "{id}" }
[handlers."environment/execute"]
command = ["my-tool", "run", "-e", "{id}", "--", "{argv}"]
result = "exec"Then any client can launch it with:
python -m wispy --config my-tool.tomlwsp knows how to drive that too:
wsp --config my-tool.toml environment/listSee Ship a Config_File for the full schema
and Adapt an existing CLI for a worked
example walking through how Hatch could expose its env subcommands as
a WSP server with no Python glue.
| Status | Meaning |
|---|---|
0 |
The call succeeded; the JSON result was written to stdout. |
1 |
The server returned a JSON-RPC error (other than method-not-found), or the call timed out. The error object is on stderr. |
2 |
Usage error, or the server reported -32601 (method unsupported). |
The full documentation lives in docs/ and is built with
Zensical. To preview it locally:
hatch run docs:serveTo build a static site:
hatch run docs:buildThe published site is at https://cjames23.github.io/wispy/.
# Run the test matrix in isolated environments.
hatch test
# Lint and type-check.
hatch check code
hatch check types
# Build the documentation locally.
hatch run docs:serveThe test suite uses property-based testing extensively (see
tests/property/) and is structured so that pure logic —
the JSON-RPC codec, the lifecycle FSM, the dispatcher, the registry, the error
model — is verified against universal properties before any I/O is wired in.
wispy is released under the MIT License.