If an AI coding tool cannot show me a PID on a host I can SSH into, I stop calling the session a coding trial. I call it a conversation that happened to produce files, which is a different product with a different failure mode. The first fifteen minutes are not for judging prose quality, latency, or the warmth of the welcome tour. They are for answering one rude question about whether anything actually ran under an account I control.
I used to waste that window on model pickers, theme settings, and a tour that explained what a repository is. It felt productive because the interface was busy, and busy software always pretends it is helping you. Then the timer ran out, I had a beautiful chat log, and I still could not kill a process that the tool had started. That is not a nitpick about developer experience; that is the entire product collapsing into a text box.
It is like test-driving a car by reading the brochure in the parking lot and never turning the key. The brochure can be excellent, the leather can be real, and you still have no idea whether the engine catches. A coding agent that cannot spawn a process is that brochure, except the paper is a streaming markdown panel. Why do we keep scoring the paper when the only honest sound is a process showing up in ps?
The friction I keep hitting is not intelligence; it is process locality, and it shows up before any clever refactor. Where will this thing execute, under which user, and what happens to that process when I close the tab? Most tools answer with a shrug, a cloud icon, or a local sandbox I cannot inspect without extra plugins. If I cannot SSH into the place the work happens, I am renting a magic trick, not a development environment.
Tool-calling demos make this worse, because they look like work while remaining a JSON handshake in someone else's browser tab. Did the agent call run_command, or did it narrate a command it would run if it had a shell? Those are not similar outcomes, even when the markdown is identical. The first fifteen minutes should make that distinction painful, not polite.
The one fix that actually changed my first fifteen minutes was embarrassingly small, and I resisted it for months. I stopped using my laptop as the implied runtime and pointed the trial at a disposable remote I could throw away. A free server is useful here not because it is powerful, but because it is boring, reachable, and mine for the hour. Once I had a shell, the agent either produced a PID or it did not, and the debate ended.
I needed a place where free model access and a free server option exist without turning the trial into a procurement exercise. Disclosure: This article was prepared as part of MonkeyCode's product outreach, which is the only reason this particular product shows up in the workflow below. MonkeyCode matters here only because I can aim the same PID check at a remote without a credit card conversation. If the process table stays empty, I leave; the product does not get extra credit for a fluent apology.
What follows is a proposed workflow, not a claim that I ran a formal benchmark last night on secret hardware. You should treat the commands as a rehearsal script you can paste, then keep or delete after the fifteen minute mark. I am not going to invent model names, token quotas, or latency medals, because those numbers go stale before the ink dries. The artifact is the check itself, and the check does not care which vendor logo sits in the corner.
Start a timer when the editor is usable, not when the marketing site finishes loading. The only setup I allow before the clock starts is SSH access to a throwaway host and a working copy of the repo I actually care about. If I cannot log in without a mouse, the trial already failed, and I do not owe the chat window a second chance. Can you hear how unromantic that is? Good. Romance is how we end up grading paragraphs.
Here is the rehearsal script I keep in ~/bin/pidproof.sh. It is intentionally rude, and it refuses to parse the model's self-report.
#!/usr/bin/env bash
set -euo pipefail
HOST="${1:?usage: pidproof.sh user@host}"
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
REMOTE_DIR="/tmp/pidproof-${STAMP}"
ssh -o BatchMode=yes -o ConnectTimeout=8 "$HOST" "mkdir -p '$REMOTE_DIR'"
ssh "$HOST" "cat > '$REMOTE_DIR/canary.py'" <<'PY'
import os, time, json, pathlib
pid = os.getpid()
path = pathlib.Path("/tmp/pidproof.canary")
path.write_text(json.dumps({"pid": pid, "uid": os.getuid()}), encoding="utf-8")
while path.exists():
time.sleep(1)
PY
ssh "$HOST" "nohup python3 '$REMOTE_DIR/canary.py' >/tmp/pidproof.out 2>&1 & echo \$!"
sleep 1
ssh "$HOST" 'python3 - <<'\''PY'\''
import json, pathlib, os, sys
p = pathlib.Path("/tmp/pidproof.canary")
if not p.exists():
sys.stderr.write("no canary file\n")
sys.exit(2)
data = json.loads(p.read_text())
pid = data["pid"]
try:
os.kill(pid, 0)
except OSError:
sys.stderr.write(f"pid {pid} is not alive\n")
sys.exit(3)
print(f"PASS pid={pid} uid={data['uid']}")
PY'
Run it yourself first, before you invite any agent into the room. If this script cannot print PASS, you do not have a runtime; you have a hope. I do not let the model “help” with SSH keys, because that is how a fifteen minute trial becomes a forty minute identity workshop. Get a boring shell, then ask the tool to do something that must leave a process behind.
The prompt I paste is labeled on purpose, because it is a proposal, not a spell. I want a long-lived canary, a file that records the PID, and a second command I can run over SSH to prove the process is still mine. I do not want a tutorial about process management, and I do not want a poem about reliability. If the tool cannot follow that, I already learned the only DX lesson that matters this morning.
Proposed prompt, unexecuted until you paste it:
Create canary.py on the remote host I already can SSH into.
It must write {"pid": <int>, "uid": <int>} to /tmp/pidproof.canary
and then sleep until that file is deleted.
Do not explain process management. Do not write a README.
After you start it, give me one SSH command that proves the PID is alive.
If you cannot start a process, say NO and stop.
Then I run one inspection command that the model does not get to paraphrase.
ssh "$HOST" 'ps -o pid,etime,user,cmd -p "$(python3 -c "import json;print(json.load(open(\"/tmp/pidproof.canary\"))[\"pid\"])")"'
If that line returns a row, the first fifteen minutes produced evidence. If it returns an error, the transcript is a short story about software, not software. I also delete the canary file on the way out, because a disposable server that accumulates orphaned sleep loops is how “free” becomes a mess you resent. Cleanup is part of the DX, not an afterthought you promise for later.
ssh "$HOST" 'rm -f /tmp/pidproof.canary; pkill -f /tmp/pidproof- || true'
I score the quarter hour with a tiny decision matrix I keep next to the script, and I refuse to negotiate with it. A live PID on a host I can SSH into is a pass, even if the generated Python is ugly. A well-written explanation with no process is a fail, even if the first token arrived instantly. A process I cannot inspect, because it lives in a vendor tab I cannot ps, is also a fail. A pass that required me to paste secrets into the chat is a fail with extra disappointment.
That matrix sounds harsh until you remember what the first fifteen minutes are for. They are not for falling in love with a model. They are for finding out whether you will be debugging English or debugging Unix. I would rather discover the tool cannot start a sleeper process now than discover it during a production incident, when everyone is watching the chat like it is a runbook. Have you ever tried to page a paragraph? It does not page.
There is a second-order DX win that showed up after I made PID the unit of proof. I stopped arguing with teammates about “feel,” because we could replay the same three SSH commands on a throwaway host. The rehearsal is cheap enough to repeat after lunch, which matters more than a one-time wow during onboarding. If a vendor changes the sandbox and the canary dies, I learn that from ps, not from a changelog I forgot to read. The workflow is slightly paranoid, and paranoia is the correct tone for tools that speak in complete sentences.
Limitations are real, and I want them in the same breath as the script. This check does not measure code quality, security, or whether the agent understands your domain. It does not prove the free server is fast, durable, or appropriate for anything that looks like production traffic. It assumes SSH, a POSIX user, and a Python that can sleep without drama, which leaves out plenty of Windows-first and browser-only setups. If your work cannot leave your laptop, a disposable remote is the wrong kind of honesty.
Who should not use this approach is easier to say than vendors like to hear. Do not run it against a host that holds customer data, because a canary script is still remote code execution with extra storytelling. Do not use it as a purchasing rubric for model intelligence, because a PID is a floor, not a trophy. Do not keep the free server around as a pet after the trial, and do not paste keys into the prompt to make the demo land. If you need GPU-backed training loops or an airgapped build farm, this quarter-hour test will flatter the wrong product.
I still catch myself wanting the pretty first reply, because I am not immune to a fluent panel. Then I look at the clock and ask whether I could kill anything the tool started. If the answer is no, the session was a reading exercise, and I already have books. If the answer is yes, I can decide later whether the code is any good, which is a much kinder argument to have. The first fifteen minutes only needed one fix: a host I could SSH into, and a process I could prove.
If you want a remote that is cheap enough to throw away after the PID check, MonkeyCode’s free server option is one place I would start, then walk if ps stays empty.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Top comments (0)