DEV Community

Jordan Huang
Jordan Huang

Posted on

Does Closing the Tab Kill the Job?

You closed the browser tab. Did the job actually die?
Most people guess. Then they lose the diff.

Free models invite that guess. Free servers make it worse.
The tab looks like a workstation. It is not.

Why an FAQ, not a tour

I keep seeing the same six claims.
They sound thrifty. They wreck resume logic.

This is a myth-busting FAQ. Claims first. Evidence second.
Then a corrected mental model. Then a script you can run.

I will not invent latency numbers. I will not name mystery GPUs.
You should not either. Measure the contract, not the brochure.

Where the two free pieces fit

You need two cheap ingredients. A model endpoint. A remote shell.
That pair is how people rehearse agent loops without a budget fight.

MonkeyCode currently offers free model access and a free server option.
I treat that pair as a practice worker, not as a laptop clone.

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

I am not claiming quotas, hardware, or forever-free status.
Those change. The job contract does not.

Q1. "The model is free, so skip the job ID."

Does a zero invoice create identity? It does not.
A free completion is still a call. A call is not a run.

Without a job ID you cannot resume. You cannot attach artifacts.
You also cannot tell two refactors apart tomorrow.

  • Claim: price replaces bookkeeping.
  • Evidence: you cannot grep a bill for a missing folder.
  • Corrected model: the model is a function inside a job.
# proposed/job.yaml — local contract, not a vendor API
job_id: "2026-09-05-refactor-auth"
prompt_sha256: "pending"
workspace_sha256: "pending"
artifact_dir: "./artifacts/2026-09-05-refactor-auth"
heartbeat_path: "./artifacts/2026-09-05-refactor-auth/heartbeat.txt"
endpoint: "${MODEL_URL}"
Enter fullscreen mode Exit fullscreen mode

Write the file before the first prompt. Always.

Q2. "A free server is just a slower laptop."

Is the box in your backpack? Can you pull the plug?
A laptop has one user and one Ctrl-C.

A free remote box is rented capacity. It may preempt you.
It may recycle the disk. It may keep running after logout.

  • Claim: remote equals local, only slower.
  • Evidence: local kill is synchronous. Remote kill is a rumor.
  • Corrected model: treat the box as a worker, not a desk.

Ask one rude question before you paste secrets.
Who else can read this home directory?

If you cannot answer, do not paste them.

Q3. "Closing the tab is Ctrl-C."

On a laptop, closing the terminal usually stops the process.
On a remote worker, the browser is only a viewport.

The shell may survive. The model call may finish.
The patch may land with nobody watching.

  • Claim: UI lifetime equals process lifetime.
  • Evidence: ps after reconnect often still shows the command.
  • Corrected model: the tab is a camera. The job is the subject.

Proposed check after every disconnect:

# proposed — run on the remote worker, not in the chat
ps -ef | grep -E 'python|node|cargo' | grep -v grep
ls -lt artifacts/*/heartbeat.txt 2>/dev/null | head
Enter fullscreen mode Exit fullscreen mode

If ps is empty and artifacts are empty, the job died.
If ps is empty and artifacts exist, the job finished unattended.
If ps is busy, the tab lied. The worker did not.

Q4. "The model remembers the workspace."

Does the endpoint mount your disk? Usually no.
It sees tokens you send. Nothing else.

Reconnect does not restore a mind. It restores a socket.
If you skip the snapshot, the next prompt is amnesia with confidence.

  • Claim: conversation memory equals repository state.
  • Evidence: a new session cannot git diff unless you give it files.
  • Corrected model: you ship context. The model does not keep a checkout.

Proposed snapshot before every model call:

# proposed snapshot — label it with the job_id
JOB=2026-09-05-refactor-auth
mkdir -p "artifacts/$JOB"
git rev-parse HEAD > "artifacts/$JOB/head.txt"
git status --porcelain > "artifacts/$JOB/status.txt"
git diff > "artifacts/$JOB/worktree.diff"
shasum -a 256 "artifacts/$JOB/worktree.diff" > "artifacts/$JOB/workspace.sha256"
Enter fullscreen mode Exit fullscreen mode

Send the snapshot hash in the prompt header.
Do not send "as we discussed" as a substitute.

Q5. "Polling keeps the free session warm."

Will a tight loop buy you persistence? It buys you throttling.
It also hides real heartbeats behind noise.

Warmth is not a protocol. A heartbeat file is.
If the worker is alive, it can touch a file every thirty seconds.

  • Claim: request spam equals liveness.
  • Evidence: spam hits the model. It may not hit the job.
  • Corrected model: liveness is a file mtime, not a token stream.
# proposed heartbeat writer — run beside the agent, not instead of it
JOB=2026-09-05-refactor-auth
while true; do
  date -u +%Y-%m-%dT%H:%M:%SZ > "artifacts/$JOB/heartbeat.txt"
  sleep 30
done
Enter fullscreen mode Exit fullscreen mode

Read that file from your laptop. Do not poll the model to ask if it is "still there."

Q6. "The chat transcript is the audit log."

Can you git blame a chat bubble? No.
Can legal replay a scrolling panel? Also no.

Chat is a scratch pad. Artifacts are the record.
If the only copy lives in the UI, you do not have a copy.

  • Claim: tokens are an audit trail.
  • Evidence: UIs truncate, reorder, and drop tool traces.
  • Corrected model: logs, diffs, and exit codes live on disk.

Minimum record I keep per job:

  1. job.yaml — identity and endpoint placeholder.
  2. head.txt plus worktree.diff — what the model saw.
  3. model.stdout — raw text, not a screenshot.
  4. exit.code — one integer, no poetry.

If any file is missing, the job is anecdotal.
Anecdotes do not survive Monday.

Artifact: a contract checker you can run

This script is proposed and unexecuted here.
Copy it. Point it at a job directory. Read the exit code.

It does not call a model. That is the point.
The contract must fail even when inference is free.

#!/usr/bin/env python3
"""proposed/check_job_contract.py — verify a job, not a chat."""
from __future__ import annotations

import hashlib
import sys
from datetime import datetime, timezone
from pathlib import Path

REQUIRED = (
    "job.yaml",
    "head.txt",
    "status.txt",
    "worktree.diff",
    "heartbeat.txt",
    "model.stdout",
    "exit.code",
)


def sha256(path: Path) -> str:
    h = hashlib.sha256()
    h.update(path.read_bytes())
    return h.hexdigest()


def main(argv: list[str]) -> int:
    if len(argv) != 2:
        print("usage: check_job_contract.py artifacts/<job_id>", file=sys.stderr)
        return 2

    root = Path(argv[1])
    missing = [name for name in REQUIRED if not (root / name).exists()]
    if missing:
        print("missing:", ", ".join(missing))
        return 1

    raw = (root / "heartbeat.txt").read_text().strip()
    beat = datetime.strptime(raw, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
    age = (datetime.now(timezone.utc) - beat).total_seconds()
    if age > 120:
        print(f"stale heartbeat: {age:.0f}s")
        return 1

    exit_txt = (root / "exit.code").read_text().strip()
    if exit_txt not in {"0", "1"}:
        print("exit.code must be 0 or 1")
        return 1

    digest = sha256(root / "worktree.diff")
    print(f"ok job={root.name} diff={digest[:12]} age={age:.0f}s exit={exit_txt}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
Enter fullscreen mode Exit fullscreen mode

Run shape, still proposed:

python3 proposed/check_job_contract.py artifacts/2026-09-05-refactor-auth
echo $?
Enter fullscreen mode Exit fullscreen mode

Green means the worker left evidence. Red means you had a conversation.
Conversations are cheap. Evidence is the gate.

Decision table: laptop, free worker, or neither

Use this before you paste a repo.

Situation Laptop Free remote worker Do not run here
Throwaway refactor, public sample Yes Yes, if artifacts sync back Anywhere without job.yaml
Secrets in .env Maybe, local disk only No Any shared home directory
You must resume after a dropped tab Yes, if process survives Yes, if heartbeat plus artifacts exist Chat-only sessions
You need an SLA Maybe, your machine No "Free" anything
You will swap models mid-job Yes Yes, endpoint is a variable Hard-coded model names in scripts
Regulated data Follow your policy No Mystery workers

The table is the whole product pitch I trust.
Free inference does not move a row left. Free shells do not either.

Limitations, said plainly

This contract does not schedule jobs. It does not checkpoint GPUs.
It does not prove the model was truthful. It only proves you kept files.

Heartbeat mtime can lie if the clock jumps. Snapshot hashes miss untracked binaries.
A green checker can still ship a bad patch. Humans still review diffs.

Who should not use this approach:

  • Anyone treating a free worker as production capacity.
  • Anyone storing customer data on a shared disk.
  • Anyone who needs guaranteed uptime from a free box.
  • Anyone who thinks a chat export replaces exit.code.

If you need those guarantees, rent a box you control.
Then keep the same contract. The myths do not get truer when you pay.

The mental model I want stuck on your wall

The model is a function. The server is a worker.
The tab is a camera. The job is a directory.

Free does not collapse those four nouns.
It only removes the invoice from the first two.

So close the tab if you want. Then ask the only question that matters.
Is the directory still there, and did check_job_contract.py exit zero?

If you run the checker on a free worker this week, tell me which claim broke first.

Top comments (0)