Run a local process as if it were inside your cluster: prefix any command
with plug and it resolves the cluster DNS and reaches the cluster services like
any workload of the stack - no code change, no proxy configuration in your app. One
tiny agent container on the cluster side, one static CLI on yours. Docker, Swarm, Kubernetes
and OpenShift.
CLI reference
Every plug command on one page, each linking to the section that details it.
Running a command
One invocation shape, two stances - a process either serves a name in the cluster or is a pure client of it (one or the other, never neither):
plug [-p profile] -s my-app:8080:3000 npm run start:dev # a service: the cluster calls it by name
plug [-p profile] -c psql -h postgres # a pure client: DB tools, one-off scriptsDetails in Getting started; mechanics in How it works.
plug exits with your command's status. One exception: when the cluster ends the session on
purpose (a gateway's administrator closing it, your key withdrawn, your membership revoked),
plug stops your command as Ctrl-C would, says who ended it and why, does not reconnect, and
exits with 77.
Commands
| command | what it does | details |
|---|---|---|
plug ls |
list profiles (name, host:port) | Profiles |
plug test [profile] |
check an agent is reachable, print its version | Profiles |
plug doctor [-p profile] [--fix] |
health-check everything plug touches, remedy next to each finding; lists the live
sessions of this machine that serve a name, under their profile, and checks each name
answers end to end, from the cluster to your process; --fix applies the
safe repairs; offers a pre-filled (redacted) GitHub issue
|
Getting started |
plug mounts |
from another terminal: the volumes the live sessions on this machine have mounted, with the local path of each. Most are the automatic ones a takeover places under a session directory, so this is where to find a workload's data to open it in an editor or a file browser | |
plug update [-p profile] [<tag>] [--force] |
the agent refreshes itself from its registry, then this launcher from the agent.
A tag switches the channel the deployment follows -
tag for the newest release, latest for the latest stream, or a
branch tag such as feat-09. A release older than the one the
cluster runs is refused unless --force says the rollback is meant.
The agent checks the tag exists before
repointing anything.
|
Getting started |
plug -p <profile> requests |
on a cluster that admits by approval: the keys waiting to be let in, numbered; the ones you pick are accepted. A member's command, like the two below | Admission by approval |
plug -p <profile> accept <key> |
accept one key, by the 12 characters the newcomer's plug printed | Admission by approval |
plug -p <profile> members |
the members, numbered; the ones you pick are revoked, after a confirmation each | Admission by approval |
plug -p <profile> revoke <key> |
revoke one member, by the key members shows: the form a script runs |
Admission by approval |
plug rn <old> <new> |
rename a profile (alias: mv) |
Profiles |
plug rm <profile> |
remove a profile | Profiles |
plug version [-p profile] |
bare: this launcher's version; with a profile (or -H): that cluster
agent's version - one bare value, script-friendly
|
Versions |
plug versions |
the whole picture: launcher, cached cores, and each profile's agent version | Versions |
plug about |
what plug is, in a few lines | About |
plug uninstall |
remove plug from this machine (binary, cache, profiles - it lists, you confirm) | |
plug mcp |
an MCP server over stdio, for an AI coding agent (Claude Code, Cursor,
Copilot). What an agent lacks is not the ability to run plug -s …, it is
knowing what to run and reading what came of it. The server answers with structure: the
profiles this machine knows, doctor check by check with the remedy, a
workload's environment (env_of, secret-looking values masked unless asked),
whether a name exists in the cluster, the agent's own report. One entry in the editor's
MCP config - {"command": "plug", "args": ["mcp"]} - covers
every profile, whatever version each cluster runs: the server is the launcher, and the
launcher already follows each cluster's agent. Per-agent setup on the
MCP page.
|
Options
| option | what it does | details |
|---|---|---|
-p, --profile <name> |
use profile ~/.plug/<name>.conf (created on first use) |
Profiles |
-H, --host <host> --port <port> |
point at a cluster directly, no profile (default port 2222) |
Profiles |
-s, --serve <name:cluster-port:local-port> |
serve this process under a cluster name for the session (repeatable; a deployed owner of
the name is parked, then restored). local-port may be a
name instead of a number - plug then picks a free port per session and
writes it into your command wherever {NAME} appears
|
Getting started |
-c, --client |
pure consumer - nothing named, no port reserved on the agent | Getting started |
--no-env [A,B] |
do not hand your command the environment of the workload it replaces.
By default a -s that takes over a deployed service gives your command that
service's variables, secrets included, and the cluster's value wins over
whatever the shell or a .env left inherited - so the process behaves as in the
cluster. --no-env alone turns projection off; --no-env A,B holds
A and B back to your local value (the escape for a test database),
projecting the rest. On Kubernetes this reads the parked pod with exec; see the
pods/exec rule in plug-k8s.yaml, and plug doctor
says when a cluster lacks it.
|
|
--env-of <name> |
hand your command the environment of that deployed workload instead,
without parking it: a -c one-off script run with a service's own
credentials (plug -c --env-of orders-svc python job.py), or a
-s that borrows the variables of the service it talks to rather than of
the one it replaces. Same rules as the default: secrets included, your own variables
winning, --no-env A,B still leaving keys out. A bare --no-env
beside it is refused, it would say two things at once.
|
|
--mount <spec> |
put one of the workload's volumes at a path here, live, read-write,
for the session - a Docker volume, a bind, a PersistentVolumeClaim. By default every
data volume of the workload a -s takes over (or --env-of names) is mounted
without this flag: under the session's temp directory, at its cluster path, the variables naming
it repointed - the process finds its data where its environment says. --no-mount
turns that off, --no-mount=/a,/b leaves those out. --mount is the
explicit form, at the exact path: --mount /data is its /data at /data;
--mount data:/srv/data its volume "data" at /srv/data;
--mount api:/data:/srv/data names the workload. The mount point (or,
when it does not exist yet, its nearest existing parent) must be yours: plug mounts
with privilege and only where you could have written unprivileged. Unnamed, it is the
-s one or the --env-of one. Repeatable. Nothing is installed:
the agent starts a helper beside the workload (its own image, the volume mounted)
and plug mounts it through the tunnel with the SMB client your OS ships with -
mount_smbfs on macOS as you, the cifs module on Linux through mount(2).
The helper runs without privilege, with the workload's own uid and gid, so files are
written as the workload writes them. A session that dies has its helper reaped by
the agent within the minute and its mount cleaned by the next run or
plug doctor --fix. Kubernetes: the helper pod is pinned to the workload's
node (ReadWriteOnce is one node, not one pod); the RBAC needs pods
create/delete, re-apply plug-k8s.yaml. The helper is the same
everywhere (it listens on 1445; on Kubernetes its Service answers on 445), which on
OpenShift and OKD satisfies the restricted SCC with nothing to grant. On Windows a mount lands on a drive
letter (an automatic one takes a free letter from Z down; --mount /data:Y:
names one), the variables repointed at it the same way. With --dockerrun
the container gets the volume at its exact cluster path.
|
|
--dockerrun |
run the container as the cluster member instead of the process:
plug -c --dockerrun docker run --rm my-image. Your image is not modified and
nothing is rebuilt; -s and -c mean what they always mean. plug
holds the data path in a sidecar container and runs yours in its network namespace, so
--network, -p and --dns belong to the sidecar and
are refused on your line. docker run only, in the foreground - a detached
container would outlive the network it was given. This machine needs no privilege: docker
grants them inside the sidecar
|
Getting started |
-h, --help |
show the built-in help (this page, condensed) |
Rarely needed
plug down- tear down plug's background state now (it does so by itself ~30 s after the last session; this is the impatient path). It is never needed to pick up a new version - closing your sessions is - and a resolver left stale by a datapath that died is repaired byplug doctor --fix.plug install-service/plug remove-service- Windows only: create/remove the datapath service (one elevated run; the installer already does it).plug init- run the profile wizard explicitly (it runs by itself when no profile exists).PLUG_DOCKER_IMAGE- the image--dockerruntakes its Linux plug binary from. Defaults to the publishedsoftwarity/plugmatching your CLI; set it when running a plug built from source, whose version was never published.PLUG_DOCKER_NETWORK- the docker network from which your agent is reachable, when the agent is itself a container rather than a host on your network.