← All posts

My Agent Kept SSHing Into the Box It Was Already Running On

A Claude agent on the dev host kept wrapping every command in ssh user@dev — connecting back into the machine it was already standing on. Here's the one-line guard that fixed it.

  • agents
  • claude
  • ssh
  • automation
  • shell

I was watching a Claude agent do some cleanup on our dev box — the shared machine where we test things before they go live — and every single command it ran started the same way: ssh user@dev "...". SSH is the tool you use to run a command on another computer over the network. The problem was that the agent was already on dev. Its working directory was right there. It was picking up the phone to call the room it was standing in.

If you’re not an engineer, the picture is this: imagine an assistant sitting at your kitchen table who, every time you ask for a glass of water, drives to your house, unlocks the front door, walks to the kitchen, and then pours the water — even though they never left the table. That’s what this was. It worked. It was just absurd.

And it wasn’t free. Each fake remote call added a host-key prompt (SSH’s “are you sure you trust this machine?” nag), a bit of latency, and — the real killer — it mangled shell quoting. When you wrap a command in ssh "...", your quotes now have to survive two shells instead of one. Half the failures I was debugging weren’t logic bugs at all. They were quotes getting eaten by the round trip.

My first instinct was to yell at the prompt — add “don’t SSH into dev, you’re already on dev.” That patched the one case and taught the agent nothing. The next task, different host name, same mistake.

Here’s what I actually got wrong in my head: I assumed the agent knew where it was. It doesn’t. An agent has no innate sense of the machine it’s executing on. Every hostname you hand it looks equally far away. “dev,” “prod,” “the box in the closet” — all remote, all equally worth an SSH, because from inside the model there’s no felt difference between here and there.

So the fix isn’t a rule about dev. It’s giving the agent a way to answer “am I already here?” before it ever reaches for SSH.

The self-location guard give me the detail

Give the agent one cheap check and a rule that consumes it. Compare the target host against the box’s own identity before any remote call:

run_on() {
  target="$1"; shift
  if [ "$target" = "$(hostname -s)" ]; then
    "$@"                 # already here — run it locally
  else
    ssh "user@$target" "$@"
  fi
}

run_on dev ls -la /srv/app   # runs bare; no ssh, no double-quoting
run_on prod systemctl status # actually goes over the wire

hostname -s is the cheap self-location primitive. In the agent’s system prompt, the matching rule is one line: before any ssh, compare the target to hostname -s; if they match, run the command directly. Now the whole class of pointless round trips and double-shell quoting bugs disappears at the source instead of one prompt-patch at a time.

The general lesson I took away: any agent that issues shell or SSH commands needs an explicit “am I already here?” guard, because location is knowledge you have and it doesn’t. Don’t teach it the name of one host. Teach it to check its own before it treats anything as far away.