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.

Troubleshooting

First reflex, always: plug doctor. It checks everything plug touches and prints the remedy next to each finding - and can open a pre-filled (redacted) GitHub issue if you want to report one. It also lists the sessions running on this machine that serve a name, with the command and the PID of each, and whether each name answers right now: through the cluster, and on your machine. See the CLI reference.

plug doctor

The agent container will not start

It prints what it is missing and exits: no Docker socket mounted, or no Kubernetes RBAC. That is deliberate. plug is deployed to plug services into the cluster, and creating a name takes that access - an agent that cannot do it would look healthy right up to your first -s. Add the mount (or apply plug-k8s.yaml) and redeploy; the message carries the exact stack-file lines.

-s starts instantly, then warns that nothing reached the name

The mapping is armed the moment your command starts - proving the path end to end takes as long as the cluster needs to schedule the name (seconds, sometimes a minute on a loaded Swarm), and that wait is not charged to your command. The proof runs in the background and only speaks up if it fails.

When it does, the name never carried traffic. Look cluster-side, where the message points: docker service ps plug-sp-<name> or kubectl get svc <name>. A signpost stuck in Preparing, a task restarting in a loop, or another workload holding the name all look like this. The session keeps running, so a name that comes up late still works, and plug doctor, from another terminal, says when it does.

One cause hides better than the others: if the cluster is driven by a continuous-deployment controller (Argo CD, Flux, Fleet), it puts the object back to its declared state minutes after plug repoints it - so the name stops serving your session without anything failing loudly, and when the deployed workload is running it answers in your place. CD & GitOps covers how to recognise it and what to configure.

If every launch sits at the slow end, the cause is usually the daemon rather than plug: a Swarm manager carrying a long history of dead tasks and stopped containers schedules noticeably slower. docker system prune and a restart bring it back down.

After switching between the deployed service and your session, the app lags behind

You stop a session and the deployed service takes the name back - or the other way around - and for a while the app answers errors, then comes back "by itself". Nothing is broken: somewhere between the caller and the name, a cache is holding on to the old address. This shows up mostly after several switches in a row, or after plug update rolled the agent. Callers that keep connections open - an API gateway, typically - hold on the longest.

Two ways out: wait a little (the cache expires on its own), or refresh the caller and reconnect instantly:

docker service update --force your-gateway

On Kubernetes this does not happen: the takeover repoints the existing Service, so the address behind the name survives the switch - see the Kubernetes page.

Your command crashed mid-session - is it plug?

When the process you launched dies on its own (a dev server tripping over its own build cache is a classic - an Angular one recovers with rm -rf .angular/cache), plug is just the messenger: it closes the session cleanly and the deployed service takes the name back. Telling them apart is easy - plug's own lines are prefixed [plug]; a stack trace from your runtime (node, java, python…) is your app's. Relaunch your command and the name is yours again.

"<name> is already exposed by another live session"

One name, one live session - so a second -s on a name someone is still serving is refused rather than silently taking it over. The usual culprit is a session of your own you can no longer see: closing an editor takes its terminal panes away without killing what ran in them, so the session stays alive, invisible, and reachable by no window. When the holder is one of yours, plug shows you what it is and offers to free it:

[plug] that name is served by another session of yours:
        PID 24939, started 12m ago
        dir: /home/you/projects/web
        cmd: -s web:8080:PORT npm run dev
[plug] stop it and take the name? [Y/n]:

Answering yes asks that session to stop - its command ends, the name is released and whatever it had parked is restored - then yours takes the name. The question is only asked when the recorded session really is the holder, so a stale record can never point it at an unrelated process; and only ever at a session of your own, since the record lives in your own ~/.plug.

With no terminal to ask on - a script, a CI job - nothing is stopped and the refusal is simply reported. Same when the holder is elsewhere: it is on another machine or another account, and the name frees itself when that session ends.

There is no permanent lock. A name is held only while its session's forward still answers, so a session killed outright frees it within seconds, and a laptop that sleeps frees it once the keepalive gives up. If that laptop comes back and you have taken the name meanwhile, its own teardown leaves yours alone.

My session is over and the deployed service has not come back

A takeover parks the deployed workload and the session's clean exit puts it back. The exit can fail to reach the agent - the likeliest moment is a network that has just gone, which is exactly when you hit Ctrl-C - and plug says so on the way out: "could not release <name> - anything this session parked is STILL parked".

Nothing to do. The agent sweeps once a minute, asks whether the session holding each parked workload still answers, and restores the ones whose session is gone. Give it a minute or two. If it stays parked past that, the agent is older than this behaviour and only its restart runs the sweep: kubectl rollout restart deploy/plug, or docker service update --force on Swarm - then plug update so it does not happen again.

Kubernetes with a GitOps controller (Argo CD, Flux): a takeover edits the Service, and a controller that self-heals will put its own version back under your session - the workload returns to normal, and your session stops receiving the name. That is the safe failure. To let takeovers hold, exclude spec.selector from the controller's diff for that Service.

A name that exists nowhere answers "unknown host"

That is intended (since 2.2): plug asks the cluster before answering, so a typo or a not-yet-deployed service fails fast and clearly, instead of timing out on a phantom address. If the name should exist, check the service is deployed - or served by a running -s session.