Sign inSign up

plotwork/selfhost

By plotwork

•Updated about 7 hours ago

The Plotwork engine as one container: MCP and the drawing API, no outbound request.

Image
Developer tools
Monitoring & observability
0

296

plotwork/selfhost repository overview

⁠Plotwork self-hosted engine

The Plotwork⁠ diagram engine as one container, for teams whose diagram text must stay inside their own network. Your AI agents and services send it a few lines of text and get back clean, laid-out SVG diagrams: architecture and flow diagrams, sequence diagrams, database schemas, Gantt charts, mind maps, C4, and 20 more kinds.

  • MCP over Streamable HTTP at /mcp, for Claude Code, Cursor, VS Code and any MCP client
  • REST drawing routes under /v1, the same paths and bodies as the hosted Plotwork API
  • Health check at /healthz

No accounts, no hosting, no telemetry, and no outbound request. Diagram text is worked on in memory and never stored or logged.

⁠Quick reference

Imageplotwork/selfhost, also ghcr.io/plotwork-official/plotwork-selfhost (same digest)
TagsA version such as 1.0.0 for production. latest follows stable releases, beta the previews
Platformslinux/amd64, linux/arm64
BaseDistroless Node 24, pinned by digest. No shell, no package manager
SizeAbout 55 MB
User65532, not root. Runs on a read-only root filesystem and writes nothing
Port3106
SignedSigstore signature, build provenance and SBOM on every image
Source and releasesgithub.com/plotwork-official/plotwork-selfhost⁠
Docsdocs.plotwork.dev/self-hosting⁠

⁠Run it

Make a token (at least 32 characters) and keep it in your secret store:

export PLOTWORK_TOKEN="$(openssl rand -hex 32)"

Start the container:

docker run -d --name plotwork \
  --read-only --cap-drop ALL --security-opt no-new-privileges \
  -p 127.0.0.1:3106:3106 \
  -e PLOTWORK_TOKEN \
  plotwork/selfhost:latest

Check it:

curl -s http://127.0.0.1:3106/healthz
⁠With Compose

An internal network has no route out, so the container cannot reach the internet even if something asked it to. Services that call Plotwork join the plotwork network and reach it at http://plotwork:3106. Put PLOTWORK_TOKEN in a .env file beside this one.

services:
  plotwork:
    image: plotwork/selfhost:latest
    restart: unless-stopped
    environment:
      PLOTWORK_TOKEN: ${PLOTWORK_TOKEN:?Set PLOTWORK_TOKEN in .env}
      PLOTWORK_WORKERS: '2'
    networks:
      - plotwork
    read_only: true
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    mem_limit: 1g
    pids_limit: 64

networks:
  plotwork:
    internal: true
⁠With Kubernetes

Start from examples/kubernetes.yaml⁠: two non-root, read-only replicas with health probes, a Service, and a NetworkPolicy with no egress. Create the token as a Secret:

kubectl apply -f kubernetes.yaml
kubectl -n plotwork create secret generic plotwork --from-literal=token="$(openssl rand -hex 32)"

⁠Connect an agent

Point any MCP client at http://<host>:3106/mcp with the header Authorization: Bearer <token>.

Claude Code

claude mcp add --transport http plotwork http://plotwork.internal:3106/mcp \
  --header "Authorization: Bearer $PLOTWORK_TOKEN"

Cursor (~/.cursor/mcp.json)

{
  "mcpServers": {
    "plotwork": {
      "url": "http://plotwork.internal:3106/mcp",
      "headers": { "Authorization": "Bearer ${env:PLOTWORK_TOKEN}" }
    }
  }
}

A service over REST

curl -X POST http://plotwork.internal:3106/v1/diagrams/render \
  -H "Authorization: Bearer $PLOTWORK_TOKEN" \
  -H "content-type: application/json" \
  -d '{"source": "flow \"Checkout\"\nnode web service \"Web\"\nnode db database \"Orders\"\nweb -> db"}'

VS Code and more are in the self-hosting guide⁠.

⁠Settings

Every setting is an environment variable, read once at start. A value the server cannot use stops it with a message that names the variable.

VariableDefaultMeaning
PLOTWORK_TOKENnoneBearer token for /mcp and /v1, at least 32 characters
PLOTWORK_HOST0.0.0.0 in the imageAddress to listen on
PLOTWORK_PORT3106Port to listen on
PLOTWORK_ALLOW_OPENunset1 serves without a token beyond loopback. Only where the network itself is the control
PLOTWORK_ALLOWED_ORIGINSnoneBrowser origins allowed to call, comma-separated
PLOTWORK_WORKERS2Worker threads that run layouts. One layout uses one thread for up to a second
PLOTWORK_QUEUE32Jobs that may wait for a worker before more are refused
PLOTWORK_TIMEOUT_MS30000Deadline of one job, waiting included
PLOTWORK_WORKER_MEMORY_MB512Heap limit of each worker
PLOTWORK_MAX_BODY_BYTES4194304Largest request body
PLOTWORK_MCP_RESULT_LIMIT44000Characters of an MCP drawing answer before its pictures are left out
PLOTWORK_TOOLSfullcore lists only the eight workflow tools, for open models with a small context
PLOTWORK_LICENSEnoneYour commercial licence key. Shown in /healthz as a fingerprint, never enforced

⁠Verify the image

cosign verify plotwork/selfhost:<version> \
  --certificate-identity-regexp '^https://github.com/plotwork-official/plotwork-selfhost/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

gh attestation verify oci://plotwork/selfhost:<version> --repo plotwork-official/plotwork-selfhost

Then push it into your own registry, so your hosts pull it from inside your network.

⁠Security

TopicThe serverYou
TransportPlain HTTPPut TLS in front: a reverse proxy, a service mesh or an ingress
AuthenticationOne static bearer token, compared in constant timeKeep it in a secret store, one per environment, and rotate it by restarting
Outbound networkMakes no request; fetch and socket clients are switched off in the processBlock egress anyway, with an internal network or a network policy
BrowsersRefuses an Origin not in PLOTWORK_ALLOWED_ORIGINSList only your own tools' origins
LimitsBody cap, bounded queue, a deadline on every job, a heap cap per workerSet container CPU and memory limits; about 250 MB at rest with two workers
LogsOne JSON line per request and per tool call, to standard output, never with diagram textShip them where you keep logs

Report a security problem to [email protected]⁠ with "Security" in the subject.

⁠What is not in it

Accounts, the portal, hosted diagram links, organisations, brand themes and custom icon packs are features of the hosted service at plotwork.dev⁠. read_diagram and compare_diagrams take SVG text or source here, not a hosted link, and drawings carry no viewUrl.

⁠Licence

Released under the Plotwork Self-Hosted Licence⁠. Free for:

  • individuals, for themselves
  • charities, non-profits, schools and research institutions, for non-commercial work
  • any organisation evaluating it for up to 30 days, not in production
  • organisations with fewer than 250 employees and contractors and less than USD 10 million in annual revenue

Any other organisation needs a commercial licence, the self-hosting add-on to Plotwork Enterprise⁠. The licence and every bundled component's licence are in the image under /licenses.

Plotwork is made by Buun Group⁠.

Tag summary

Content type

Image

Digest

sha256:36d31246d…

Size

56 MB

Last updated

about 7 hours ago

docker pull plotwork/selfhost