Client/server mode¶
Tryke can run as a persistent server that caches test discovery while using fresh Python worker processes for each logical run. A client — typically an editor plugin — spawns tryke server as a child process and speaks JSON-RPC over its stdin/stdout, the same model language servers use.
Starting the server¶
On startup, the server:
- Prepares the worker pool
- Runs initial test discovery
- Starts watching the filesystem for changes
It then reads requests from stdin and writes responses and notifications to stdout. Closing stdin shuts the server down cleanly.
Protocol¶
The server speaks JSON-RPC 2.0 over stdin/stdout with newline-delimited messages: one JSON object per line, terminated by \n. This is not LSP's Content-Length-header framing — plugins should split on newlines, not parse content-length headers.
Request/response¶
Available methods¶
| Method | Description |
|---|---|
ping |
Liveness check, returns "pong" |
discover |
Re-scan for tests, returns the test list |
did_change |
Client-initiated change signal; refreshes discovery before the next run |
run |
Execute tests with optional filters, streams results |
Streaming notifications¶
During a test run, the server emits notifications (no id field) interleaved with responses on stdout:
{"jsonrpc": "2.0", "method": "run_start", "params": {"tests": [...]}}
{"jsonrpc": "2.0", "method": "test_complete", "params": {"result": {...}}}
{"jsonrpc": "2.0", "method": "run_complete", "params": {"summary": {...}}}
File changes trigger a discover_complete notification with the updated test list.
Debugging by hand¶
Because the transport is plain stdio, you can poke the server from a shell:
The server answers on stdout and exits when the pipe closes.
Filesystem watching¶
The server watches all .py files in the project (respecting .gitignore) with a 50ms debounce. When files change:
- The batch is dedup'd against each path's last-seen
(mtime, size)so editor tail events that don't actually change the file (metadata fsync, swap-file cleanup, format-on-save with identical output) are dropped before any work happens - The import graph is incrementally updated
- A
discover_completenotification is emitted
File changes only update discovery. Every run request starts fresh worker subprocesses regardless of whether source files changed, so repeated runs also re-execute import-time code in brand-new Python interpreters.
Editor integration¶
Server mode is designed for editor plugins. Two official integrations exist:
- Neovim: neotest-tryke
- VS Code: tryke-vscode
A typical workflow:
- The editor plugin spawns
tryke serveras a child process and owns its stdio - The plugin sends a
discoverrequest to populate the test explorer - When you run a test, the plugin sends a
runrequest - Results stream back as
test_completenotifications for real-time progress - File changes automatically update the test list via
discover_complete - On editor exit, the plugin closes the server's stdin (or kills the child) to stop it
See the editor integration guide for setup instructions.
Why server mode¶
Without the server, every tryke test invocation pays for Python startup and test discovery. With a long-lived server:
- Every run is isolated — fresh Python processes re-execute imports and cannot leak module state from an earlier run
- Discovery is cached — only changed files are re-scanned