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.
Profiles & versions
A profile is one cluster: a plain file in ~/.plug/<name>.conf. plug picks
the profile automatically, so your daily command carries no -p.
Automatic selection
The installer normally creates a profile for you, named
after the cluster host it reads from your ssh get@<host> command, or as
you name it on that command (install my-cluster) - so the wizard below is really
just the fallback when no profile exists yet. Install from several clusters and each gets its
own profile.
- No profile → a short wizard asks for a name, the cluster host and the agent port (default
2222), saves the profile and uses it immediately. - One profile → used as is (plug prints which one, for transparency).
- Several profiles → interactive numbered choice - or skip the question with
-p <name>.
$ plug -s my-app:8080:3000 npm run start:dev
[plug] no profile in /Users/you/.plug - let's create one
profile name [default]:
cluster host: swarm-node.example.com
agent port [2222]:
[plug] profile "default" saved to /Users/you/.plug/default.conf
[plug] running your commandThe profile file
Created by the wizard, editable by hand - just a host and a port:
# ~/.plug/staging.conf
host = swarm-node.example.com
port = 2222What goes to the cluster vs direct (split-horizon)
plug decides per destination by the shape of the name:
- Single-label names (
pdfbox,mongodb) → the cluster, resolved cluster-side. - Dotted FQDNs (
api.github.com, a LAN host) → resolved and connected directly on your machine. localhostand127.0.0.1always stay local.
Several clusters at once
Run the same process against two clusters in parallel - each stays isolated:
plug -p prod -s my-app:8080:3000 npm run start # → cluster prod
plug -p staging -s my-app:8080:3000 npm run start # → cluster staging, side by side
The same service names resolve to the right backend in each. How plug keeps the two apart
differs by OS (a private resolver per launch on Linux, one tunnel per cluster attributed at
connect() on macOS and Windows): see
how plug tells them apart and the
coverage matrix.
Managing profiles
plug ls # list profiles: name host:port
plug test [profile] # check an agent is reachable (prints its version)
plug rn default prod # rename a profile (alias: plug mv)
plug rm staging # remove a profile
plug test connects to the agent and reports its version - handy to confirm a
cluster is reachable before running your app.
One-shot, without a profile
Point plug straight at a cluster with --host (and --port if it isn't
2222) - handy for a quick try or for CI. It overrides the selected profile for
that one run:
plug --host swarm-node.example.com --port 2222 -s my-app:8080:3000 npm run start:devVersions - the launcher model
plug is a small launcher, like nvm or rustup. The
binary on your PATH does almost nothing itself: on each run it asks the agent
which version it speaks, then executes that exact version from
~/.plug/versions/ - downloading it once from the cluster if missing.
- Each cluster runs its own version. A cluster on 1.1 and one on 1.3 both work - no in-place replacement, no upgrade churn on the binary you installed.
- Correct by construction. The CLI can never drift from the agent it talks to, because it literally runs the agent's version.
- Cheap. Cached binaries are a few MB each; the first connect to a new version pays one small download.
plug version # the launcher's own version
plug versions # launcher + every cached cluster version
The launcher itself almost never needs updating: the download protocol it speaks to the agent
(version + <os-arch>) is frozen - if it ever must change, just
reinstall it from the cluster.
Updating a cluster
New plug release? plug update walks that chain upstream: the agent moves
itself to the newest release, then the launcher refreshes itself from the agent and
re-applies its privilege. Live sessions ride the roll out - they reconnect onto the new agent
by themselves.
Moving itself means the deployment's tag is rewritten when it pins a release
- softwarity/plug:2.3.0 becomes softwarity/plug:2.4.0, majors
included. plug is infrastructure carrying your sessions, not an application dependency you
hold back for reproducibility; and re-resolving a pinned tag could only ever return the same
image, which made update a no-op exactly where it was needed. Each backend
applies it its own way: Swarm updates the service's image, Kubernetes patches the
Deployment's container image, and a plain container - which cannot recreate itself - pulls
the new image and hands you the one command that does.
plug update follows the tag the deployment already carries. To move a cluster to a
different one, name it: plug -p neo update tag takes the newest
release published, plug -p neo update latest the latest stream, and
plug -p neo update feat-09 a branch's tag at whatever it points to now - an exact
release (2.3.0) works too, downgrades included. The agent checks the tag exists on
the registry before repointing anything: aiming a deployment at a tag nobody published would
leave you with an agent that cannot pull.
A moving tag (latest, main, a branch) is left
exactly as it is and simply re-pulled: it already resolves to whatever its publisher last
pushed, and repointing it would override a deliberate choice. And when a pinned deployment is
already on the newest release, plug says so immediately instead of rolling the workload to
find out.
Being told a version is there
Once a day, in the background, a session checks whether the registry carries a release the cluster's agent does not, and says so the next time you run plug. What happens then is the profile's policy:
plug config -p neo # show that cluster's policy
plug config -p neo update=notify # default: tell you, and offer to apply
plug config -p local update=auto # apply it, on a cluster you govern
plug config -p shared update=none # never look, on one you do not
The policy belongs to the profile, not to the machine, because applying an
update rolls the cluster's agent, which every session on that cluster shares: you may govern
your own cluster and have no say over a shared one. notify asks only on a real
terminal, defaults to no and gives up after a few seconds; a script or a CI job sees the
message and never a question. A running command keeps the version it started with; the new
one is used at the next launch.
A deployment on a moving tag (latest, a branch) is compared by digest, since its
name never changes. When the registry is out of reach from your machine (a proxy, a VPN that
splits routes), plug asks the cluster, which reaches it.