pluginart is a CLI plus Go, Python, and TypeScript runtimes for building language-agnostic plugin systems. Hosts manage plugins from pluginart.toml. Plugins run as binaries, Docker containers, or remote TCP services. All calls use a FlatBuffers-based wire protocol with contract-hash verification at handshake time.
go install github.com/dlahoza/pluginart/cmd/pluginart@latest
brew install flatbuffersRuntime packages are published as:
- Go:
github.com/dlahoza/pluginart/pkg/runtime - PyPI:
pluginart - npm:
pluginart
The schema defines payload tables and method names. Generated clients give host code method wrappers. The host runtime starts, health-checks, restarts, calls, and shuts down plugins. Go, Python, and TypeScript generation hide the pluginart RPC envelope while still using FlatBuffers payload builders.
pluginart gen bindings --target host --lang go --schema examples/schema/echo.fbs --out examples/host-go/plugins
pluginart gen bindings --target plugin --lang go --schema examples/schema/echo.fbs --out examples/plugin-go/plugin
cd examples/plugin-go && go build -o plugin-go .
cd ../host-go && go run .Go hosts use runtime.NewManagerFromConfig("pluginart.toml") and generated clients that wrap manager.Call.
pluginart gen bindings --target host --lang python --schema examples/schema/echo.fbs --out examples/host-py/plugins/echo
pluginart gen plugin --lang python --name echo --schema examples/schema/echo.fbs --out examples/plugin-py
pip install pluginart flatbuffers
python examples/host-py/main.pyPython hosts use:
from pluginart import PluginManager
from plugins.echo.echo_client import echoClient
with PluginManager.from_config("pluginart.toml") as manager:
client = echoClient(manager, "echo")
response = client.Echo(builder, echo_request_offset)pluginart gen bindings --target host --lang typescript --schema examples/schema/echo.fbs --out examples/host-ts/plugins/echo
pluginart gen plugin --lang typescript --name echo --schema examples/schema/echo.fbs --out examples/plugin-ts
cd examples/plugin-ts && npm install && npm run build
cd ../host-ts && npm install && npm run build && npm startTypeScript hosts use:
import { PluginManager } from 'pluginart';
const manager = await PluginManager.fromConfig('pluginart.toml');
await manager.start();
const client = new EchoClient(manager, 'echo');
const response = await client.Echo(builder, echoRequestOffset);
await manager.shutdown();type |
Host behavior | Transport default |
|---|---|---|
binary |
Execs path, injects PLUGIN_SOCKET or PLUGIN_ADDR, waits for READY |
Unix socket |
docker |
Runs docker run, injects PLUGIN_ADDR, waits for READY in logs |
TCP |
remote |
Dials address directly |
TCP |
Config-driven lifecycle is available in Go, Python, and TypeScript runtimes.
The repository examples also include repeat plugins in Go, Python, and TypeScript that run through Docker mode. Build them from the repository root before running any host example:
docker build -f examples/plugin-repeat-go/Dockerfile -t pluginart-repeat-go:local .
docker build -f examples/plugin-repeat-py/Dockerfile -t pluginart-repeat-py:local .
docker build -f examples/plugin-repeat-ts/Dockerfile -t pluginart-repeat-ts:local .Each host example calls the binary echo plugins and the Dockerized repeat plugins through the same pluginart.toml lifecycle.
Pluginart has a dedicated benchmark suite in bench. It measures runtime overhead with raw payloads and no generated schema code, so the results focus on framing, calls, manager lookup, handshake, and plugin server dispatch.
The suite covers host manager calls, direct protocol client calls, and plugin server dispatch for Go, Python, and TypeScript. Each runtime is tested against its own benchmark plugin. CI runs every case for 10 seconds and uploads the benchmark output as an artifact.
Latest local 100x run on an Apple M5:
| Go benchmark | Payload | ns/op | MB/s | B/op | allocs/op |
|---|---|---|---|---|---|
| host manager | 10 | 45702 | 0.22 | 131 | 5 |
| host manager | 1000 | 40364 | 24.77 | 1138 | 5 |
| host manager | 10000 | 42732 | 234.01 | 10355 | 5 |
| protocol client | 10 | 35368 | 0.28 | 126 | 5 |
| protocol client | 1000 | 35118 | 28.48 | 1134 | 5 |
| protocol client | 10000 | 36048 | 277.41 | 10350 | 5 |
| plugin server | 10 | 29444 | 0.34 | 126 | 5 |
| plugin server | 1000 | 34707 | 28.81 | 1139 | 5 |
| plugin server | 10000 | 38572 | 259.26 | 10357 | 5 |
| Python benchmark | Payload | ns/op | MB/s | Peak heap/op | Retained heap/op |
|---|---|---|---|---|---|
| protocol client | 10 | 28662 | 0.33 | 10 B | 4 B |
| protocol client | 1000 | 30949 | 30.81 | 50 B | 14 B |
| protocol client | 10000 | 51771 | 184.21 | 410 B | 104 B |
| plugin manager | 10 | 45067 | 0.21 | 10 B | 4 B |
| plugin manager | 1000 | 35494 | 26.87 | 50 B | 14 B |
| plugin manager | 10000 | 30645 | 311.19 | 410 B | 104 B |
| plugin server | 10 | 20280 | 0.47 | 10 B | 4 B |
| plugin server | 1000 | 22591 | 42.21 | 50 B | 14 B |
| plugin server | 10000 | 25730 | 370.63 | 410 B | 104 B |
| TypeScript benchmark | Payload | ns/op | MB/s | Peak heap/op | Retained heap/op |
|---|---|---|---|---|---|
| protocol client | 10 | 63272 | 0.15 | 7043 B | 1261 B |
| protocol client | 1000 | 56728 | 16.81 | 5610 B | 337 B |
| protocol client | 10000 | 66761 | 142.85 | 5597 B | 105 B |
| plugin manager | 10 | 45313 | 0.21 | 6028 B | 354 B |
| plugin manager | 1000 | 43971 | 21.69 | 5705 B | 90 B |
| plugin manager | 10000 | 48949 | 194.83 | 5717 B | 3 B |
| plugin server | 10 | 51640 | 0.18 | 4921 B | 96 B |
| plugin server | 1000 | 38360 | 24.86 | 4940 B | 0 B |
| plugin server | 10000 | 47253 | 201.82 | 5207 B | 90 B |
Run the suite locally:
go test -tags bench ./bench/go -run TestBench -bench Benchmark -benchmem -benchtime=10s -count=1
go test ./pkg/protocol -run '^$' -bench BenchmarkHandleConnServer -benchmem -benchtime=10s -count=1
.venv/bin/python bench/python/run_bench.py --duration 10s --json bench-results/python.json
node --expose-gc bench/typescript/dist/run-bench.js --duration 10s --json bench-results/typescript.json- Getting started
- CLI reference
- Config reference
- Schema guide
- Python host guide
- TypeScript host guide
- Wire protocol
- Releasing
| Version | Status | Scope |
|---|---|---|
v0.1 |
Shipped | Go runtime foundation: FlatBuffers call envelope, framing, handshake, contract-hash verification, Unix/TCP transports, binary and remote plugin lifecycle, Go schema/client/plugin generation, and getting-started docs. |
v0.2 |
Shipped | Python and TypeScript runtimes, Python/TypeScript host and plugin generation, Docker plugin mode, config validation, full protocol docs, reusable plugin server helpers, and example hosts/plugins across Go, Python, and TypeScript. |
v0.3 |
Planned | Resilience: circuit breakers, per-call deadlines and cancellation, and batching. |
v0.4 |
Planned | Observability: W3C trace context propagation and OpenTelemetry integration. |
v0.5 |
Planned | Transport hardening: compression negotiation with LZ4/ZSTD and TLS support for remote mode, including mutual TLS options. |
v0.6 |
Planned | Performance: shared-memory fast path, runtime object pooling, and sender write coalescing. |
The current release is v0.2.2. Field-level request/response builders, plugin registry/marketplace support, and languages beyond Go, Python, and TypeScript are not currently in scope.