Docker installation
Install the self-contained Linux AMD64 or ARM64 image and run the PtcRunner CLI, Viewer, and stdio launcher without a build toolchain.
Images are published as ghcr.io/andreasronge/ptc_runner starting with the
first root release after the container publication workflow lands. Older
releases are not backfilled. The image does not contain runtimes used by
external MCP servers.
Pull and verify the image
Use an exact version tag for deployments:
version=VERSION
image="ghcr.io/andreasronge/ptc_runner:$version"
docker pull "$image"
docker run --rm "$image" --versionReplace VERSION with a three-part release version such as 0.14.0. The release
workflow creates each exact version tag once and refuses to replace one. GHCR
does not enforce that policy as registry-level tag immutability, so pin the
pulled repository digest and verify its attestation in automated deployments.
There are no moving latest or MAJOR.MINOR tags; PtcRunner is 0.x and breaking
changes are expected.
Each image has signed GitHub build provenance. Verification requires GitHub CLI authentication and a registry login, including for a public image:
gh auth refresh --scopes read:packages
gh auth token | docker login ghcr.io \
--username "$(gh api user --jq .login)" --password-stdin
gh attestation verify "oci://$image" \
--repo andreasronge/ptc_runner \
--signer-workflow \
andreasronge/ptc_runner/.github/workflows/container-release.yml \
--source-ref "refs/tags/v$version" \
--deny-self-hosted-runnersThe added read:packages scope allows Docker to authenticate to GHCR. A classic
personal access token carrying read:packages can be used instead.
Run a project
Map the container process to the host user so owner-only credentials remain readable and project artifacts remain writable. Supply a writable home for runtime-local files:
docker run --rm \
--user "$(id -u):$(id -g)" \
--env HOME=/tmp \
--volume "$PWD:/work" \
"$image" init /work/hello-ptc
docker run --rm \
--user "$(id -u):$(id -g)" \
--env HOME=/tmp \
--volume "$PWD:/work" \
"$image" run /work/hello-ptc/ptc-project.jsonThe generated project keeps traces and command envelopes under its mounted
.ptc directory, so --rm does not discard them. Do not run this form from a
root shell: a root host UID would also select root inside the container and
discard the image's non-root default. Without --user, the image runs as its
built-in ptc user with UID and GID 10001.
Mount host configuration and dotenv files only where the project expects them.
PTC's --env-file appears after the image name and is distinct from Docker's
option of the same name:
docker run --rm \
--user "$(id -u):$(id -g)" \
--env HOME=/tmp \
--volume "$PWD:/work" \
"$image" run /work/hello-ptc/ptc-project.json \
--env-file /work/hello-ptc/.envRemote model and credential-based MCP providers work normally. A stdio MCP
server runs inside the container namespace: its executable and runtime must be
Linux-compatible and present in the image or an explicit mount. In particular,
the published image does not add Node.js or npx. Build a derived image when a
local MCP server needs another runtime. The runtime-included frontend also does
not initiate interactive MCP OAuth authorization; authorize through a
supported embedding host or use a provider that can execute non-interactively.
Open a REPL
Allocate a terminal for interactive editing and history:
docker run --rm -it \
--user "$(id -u):$(id -g)" \
--env HOME=/tmp \
--volume "$PWD:/work" \
"$image" replOpen the Viewer
The Viewer binds to the container's loopback unless explicitly told otherwise, which a published port cannot reach. Bind the wildcard only inside the container and keep the host publication on loopback:
viewer_token="$(openssl rand -hex 32)"
docker run --rm \
--user "$(id -u):$(id -g)" \
--env HOME=/tmp \
--env PTC_VIEWER_TOKEN="$viewer_token" \
-p 127.0.0.1:4123:4123 \
-v "$PWD:/work" \
"$image" viewer /work/hello-ptc/ptc-project.json \
--listen 0.0.0.0 --port 4123Open http://localhost:4123/?live_token=$viewer_token#/live. The page removes
the token from the visible URL after bootstrapping and uses it for Live reads
and mutations. The Runs trace browser itself remains unauthenticated.
Writing -p 4123:4123 instead exposes that unauthenticated trace browser to the
network. The 127.0.0.1: prefix is the host-side security decision.
Build from a checkout
Maintainers can build and verify one local platform without publishing it:
scripts/build_container_image.shThe script produces ptc:dev, runs the standalone verification inside the
image, probes the finished image without adding packages, and confirms it runs
as a non-root user.