DEV Community

Jordan Huang
Jordan Huang

Posted on

FAQ: Five Myths About Agent State on a Remote Server

Did your agent just claim that file exists?
Did you inspect the server, or only the chat?

I keep seeing one mix-up on free stacks.
A model talks while a remote shell runs.
Too many workflows fuse those two hosts.

Those two pieces are not the same machine.
They do not share memory, cwd, or lifetime.

This FAQ busts five claims that keep circulating.
Each myth gets a check you can run yourself.

I will skip latency theater and fake pass rates.
I want host facts the chat cannot invent quietly.

What this article is not

This is not a model beauty contest.
This is not a cloud pricing lecture either.

I will not quote quotas I cannot verify.
I will not name models I did not pin.

I will show a receipt for process state.
You can run it on any Linux-like host.

The split I actually use

A coding agent has two surfaces, always.

  1. The model: tokens, plans, and confident summaries.
  2. The server: processes, files, env, and exit codes.

Free model access does not glue those surfaces.
A free server option does not either.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

I mention MonkeyCode only as one place this split shows up.
You can apply the same checks on any remote box.

The product is not the lesson here.
The two-host mental model is the lesson.

Myth 1: The model's context is the disk

Claim: the agent listed the file, so it exists.

Why does this spread so fast among us?
The chat looks like a terminal session.
It is not a terminal. It is narration.

Corrected model: listings are claims until stat agrees.
Ask the server. Do not ask the narrator.

Try this receipt. Treat it as an example until you run it.

# example: prove a path without asking the model
set -euo pipefail
TARGET="${1:-./app.py}"
hostname
pwd
whoami
if [ -e "$TARGET" ]; then
  stat -c '%n %F %s %y' "$TARGET"
else
  echo "MISSING $TARGET"
  exit 1
fi
Enter fullscreen mode Exit fullscreen mode

What should you trust from that output?
Hostname, path, size, and mtime. Not recap prose.

Would you merge a PR on a chatbot's memory?
Then stop merging reality from a file list in prose.

Quick miss patterns

  • The model reprints a path from an older turn.
  • The path is relative, and cwd already moved.
  • ls ran on a different host than cat.

I do not argue with the summary after that.
I rerun stat and keep the stdout.

Myth 2: Installs survive because the tab is open

Claim: I already pip installed it in this chat.

Why does this spread on laptops first?
Site-packages linger for months on a personal disk.
Many remote sandboxes reset when the session dies.

Corrected model: packages live in a filesystem, not a thread.
A new container can look like amnesia. It is not.

Example check, unexecuted until you run it:

# example: record interpreter identity, not vibes
python3 - <<'PY'
import sys, sysconfig
print("executable", sys.executable)
print("version", sys.version.split()[0])
print("purelib", sysconfig.get_path("purelib"))
print("prefix", sys.prefix)
PY
python3 -m pip show requests || echo "requests: not installed"
Enter fullscreen mode Exit fullscreen mode

Save that output next to your session notes.
Compare it after every reconnect. Diff beats memory.

Still sure the old venv is sitting there?
Then the second run will match the first receipt.

What I refuse to trust

  • "Dependencies are already there."
  • "It imported fine in the last reply."
  • "The tool call said Success."

Success of a past process is not current state.
Current state is sys.prefix plus an import probe.

Myth 3: CWD is wherever the last prompt pointed

Claim: we are in /app because I said cd /app.

Why does this spread inside agent loops?
Humans treat chat as one long shell session.
Many loops spawn a fresh process per tool call.

Corrected model: cwd is per process, not per narrative.
cd in a dead shell does not move the next one.

# example: pin cwd instead of describing it
printf 'expected_cwd=%s\n' "$(pwd)"
readlink -f .
ls -ld .
NONCE="state-$(date -u +%Y%m%dT%H%M%SZ)-$$"
echo "$NONCE" > .agent-nonce
pwd > .agent-cwd
echo "nonce=$NONCE"
Enter fullscreen mode Exit fullscreen mode

The next command must print the same nonce.
If it cannot, you changed hosts or directories.

I ask one rude question after every cd.
Did a new process inherit that directory, really?

A tiny workflow I reuse

  1. Write a nonce in the directory you care about.
  2. Hide the nonce from the model's prompt.
  3. Ask the agent to print cwd and the nonce file.
  4. Compare bytes. Do not compare vibes.

If the nonce is missing, stop the task.
You are debugging the host, not the feature.

Myth 4: A background job lives with the conversation

Claim: the server is still running; I can see the chat.

Why does this spread in IDE-shaped workflows?
Editors keep processes beside the buffer you see.
A browser tab is not a process supervisor.

Corrected model: jobs need pid, parent, and a heartbeat.
Chat presence is not a keep-alive for nohup.

# example: start a job you can actually find
mkdir -p /tmp/agent-jobs
python3 - <<'PY' >/tmp/agent-jobs/heartbeat.log 2>&1 &
import os, time
from pathlib import Path
pid_path = Path("/tmp/agent-jobs/heartbeat.pid")
pid_path.write_text(str(os.getpid()))
while True:
    Path("/tmp/agent-jobs/heartbeat.ts").write_text(str(time.time()))
    time.sleep(2)
PY
echo "pid=$(cat /tmp/agent-jobs/heartbeat.pid)"
ps -p "$(cat /tmp/agent-jobs/heartbeat.pid)" -o pid,ppid,etime,cmd
Enter fullscreen mode Exit fullscreen mode

Later, do not ask "is it running?" in English.
Read the pid file. Then run ps. Then read the timestamp.

If ps is empty, the job is dead.
The chat being open does not revive it.

Heartbeat rules

  • A pid file without ps is a tombstone.
  • A frozen timestamp is a hung loop, not health.
  • A new pid after reconnect is a different job.

I keep those three lines in the runbook.
They catch more lies than another retry prompt.

Myth 5: This host is basically your laptop

Claim: same user, same home, same tools as local.

Why does this spread the moment SSH looks familiar?
The prompt rhymes with a machine you already trust.
Free remote boxes often differ in user, arch, and init.

Corrected model: identity is a tuple you print every session.
Hostname, uid, home, kernel, and a writable probe path.

# example: host identity card
echo "host=$(hostname)"
echo "user=$(id -un) uid=$(id -u)"
echo "home=$HOME"
echo "kernel=$(uname -srm)"
echo "pwd=$(pwd)"
touch .agent-write-test && echo "write=ok" || echo "write=fail"
command -v git python3 node docker 2>/dev/null | sort
Enter fullscreen mode Exit fullscreen mode

Mismatch on any line means you assumed the wrong box.
I treat that as a stop, not a shrug.

Would you deploy with the wrong hostname in logs?
Then do not debug with the wrong host in your head.

Artifact: a one-page decision table

Use this before you believe an agent summary.

Claim in chat Command that can confirm Pass means Fail means
File exists stat on the exact path inode facts printed path missing or wrong host
Package installed pip show / import probe same interpreter as before different prefix or missing dist
We cd'd nonce file in that directory nonce matches last receipt new cwd or new machine
Job still up ps plus heartbeat timestamp pid alive and ts moving pid gone or ts frozen
Same machine hostname + uid + kernel tuple matches your notes you hopped environments

Print the table. Fill it once per session.
Do not fill it from memory. Fill it from stdout.

A 15-minute test plan

Label this unexecuted until you actually run it.

  1. Open a remote shell. Ignore the model for ten minutes.
  2. Run the identity card. Save stdout to receipt-1.txt.
  3. Create the nonce file. Record the nonce string.
  4. Ask the agent where it is. Do not show it the receipt.
  5. Compare its story to receipt-1.txt. Mark every miss.
  6. Disconnect. Reconnect. Run the identity card again.
  7. Diff receipt-1.txt against receipt-2.txt.

What usually breaks first on a remote box?
Cwd. Then packages. Then background pids.

What almost never breaks first in the chat?
The model's confidence. That stays high for free.

When the receipts disagree

Start with host identity, not with the feature branch.
If hostname changed, every later claim is suspect.

Then check cwd with the nonce file.
Only then look at the application file you care about.

Last, check the job heartbeat if anything is long-running.
Do not reverse that order. You will debug ghosts.

I keep the order on a sticky note.
Host, cwd, file, process. Then the agent may speak.

Limitations

These checks need a real shell on the execution host.
A chat-only playground cannot prove disk.

They also assume Unix-like commands exist.
Windows agents need different receipts. Do not copy blindly.

I am not claiming any free server is durable.
I am not claiming any free model is deterministic.

I did not measure uptime. I did not publish SLAs.
If you need those numbers, get them from primary docs.

This workflow will not replace CI.
CI still owns the merge gate. Receipts only debug agents.

Clock skew can make timestamps look "stale" wrongly.
Prefer pid liveness plus a moving heartbeat, together.

Who should not use this approach

Do not park production secrets on a free shared host.
Do not run regulated workloads on an unreviewed box.

Do not use this if you cannot open a real shell.
The whole point is independent evidence.

Do not use this as a substitute for pinning images.
A receipt is a snapshot, not an immutable deploy.

If you need a laptop, use a laptop.
A remote free server is a different contract.

Corrected mental model

Stop asking the model to narrate the machine.
Ask the machine. Then let the model comment.

Two hosts. Two clocks. Two failure modes.
One receipt that both of you must respect.

I still use agents. I just stopped believing their cwd.

If you run the nonce check, paste the hostname line.
Skip the model's recap. I already know it will sound sure.

Top comments (0)