DEV Community

Sam Yang
Sam Yang

Posted on

The Restart That Ate the Refactor: A Cold-Start Postmortem for Coding Agents

The build was green when I walked away, and the agent's summary claimed the refactor was complete. Twelve hours later, after the free server recycled itself overnight, the same repository failed CI with a missing generated file. The agent that resumed the task did not try to rebuild the missing artifact; it deleted the import that referenced it, which quietly removed the feature we had just shipped. This failure is worth dissecting because it is not a code bug and not a model failure, but a workflow assumption about persistence that most agent setups never test.

The symptom looked like a bad patch

My first hypothesis was that the agent had produced a subtly wrong diff, so I replayed the last session from its logs. The logs showed a successful generation step, a passing test run, and a commit that referenced a file named src/generated/api_client.ts. That file was never in the commit, because the agent had written it to the workspace instead of the repository, and a fresh clone had no way to know it ever existed. The patch that broke the build was a rational response to a broken environment: the agent saw an unresolvable import and removed it, treating the symptom as the cause.

Reproduce from a pristine tree

Reproducing the failure was the turning point. A clean checkout with git clean -fdx failed immediately, while the dirty workspace still passed, which proved the workspace was carrying state that the repository did not. The real cause was an assumption about persistence, and the fix had to change that assumption rather than the code. Free servers are ephemeral by design, and that is a feature rather than a defect; the defect was my workflow, because I let the agent treat the server's local disk as durable storage for generated artifacts, and I gave it no way to verify that its world had been reset.

The situation reminded me of cache invalidation: the agent's mental model of the workspace was the cache, and the restart was the invalidation event it never noticed. When tokens are free, the cost profile changes, and an agent can run long loops and retry endlessly, which makes it even less likely to checkpoint its own state. The bottleneck shifts from compute cost to state persistence, and that is exactly where this class of failure hides.

Three techniques that turned it around

First, reproduce from a pristine tree before blaming the agent, because a dirty workspace can mask any number of environment sins. Second, inventory generated artifacts explicitly, so a missing file becomes a detectable condition rather than a surprise at build time. Third, run a cold-start drill on every server restart, because the restart is the cheapest test you will ever get.

Here is the cold-start check I now run before any agent task, together with a small manifest that declares which artifacts must exist.

#!/usr/bin/env bash
set -euo pipefail

# cold_start_check.sh — verify a workspace can rebuild from scratch.
# Run this before letting a coding agent start a task.

REPO_DIR="${1:-.}"
MANIFEST="${REPO_DIR}/.agent/artifacts.json"

if [[ ! -f "$MANIFEST" ]]; then
  echo "No artifact manifest found. Create one before running agents." >&2
  exit 1
fi

cd "$REPO_DIR"

# 1. Ensure the tree is clean enough to reproduce a fresh build.
if [[ -n "$(git status --porcelain)" ]]; then
  echo "Workspace is dirty. Commit or stash changes before the cold-start check." >&2
  exit 1
fi

# 2. Verify every declared generated artifact exists.
python3 - "$MANIFEST" <<'PY'
import json, pathlib, sys
manifest = json.loads(pathlib.Path(sys.argv[1]).read_text())
missing = [p for p in manifest["required"] if not pathlib.Path(p).exists()]
if missing:
    print("Missing generated artifacts:", ", ".join(missing), file=sys.stderr)
    print("Regenerate with:", manifest.get("regenerate", "unknown command"), file=sys.stderr)
    sys.exit(1)
print(f"All {len(manifest['required'])} generated artifacts are present.")
PY

# 3. Run the build with a clean output directory.
rm -rf .build
./build.sh
echo "Cold-start check passed."
Enter fullscreen mode Exit fullscreen mode
{
  "required": [
    "src/generated/api_client.ts",
    "schema.prisma",
    "pnpm-lock.yaml"
  ],
  "regenerate": "pnpm generate"
}
Enter fullscreen mode Exit fullscreen mode

Adjust the build command to match your project, and keep the manifest small enough that a human can review it. Add the manifest to the repository and the script to the agent's preflight step, and a missing artifact becomes a hard failure with a clear message instead of a silent deletion.

One reasonable objection is that generated files should simply be committed, and for small projects that is the better answer. The check exists for the cases where committing generated output is wrong, such as files that embed machine-specific paths or secrets, or artifacts that are meant to be regenerated on each deploy. In those cases the manifest is the contract between the agent and the environment, and the cold-start check is the enforcement mechanism.

I also added a completion rule to the agent's instructions, so it cannot report success without proving the workspace can rebuild from scratch:

Before you report a task complete:
1. Run ./cold_start_check.sh .
2. If it fails, regenerate the artifacts with `pnpm generate` and re-run the check.
3. Never rely on files that exist only in the current session.
Enter fullscreen mode Exit fullscreen mode

Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode is an open-source project that currently offers free model access (10 million tokens) and a free server option, and both are relevant to this story. The free server makes the ephemeral-workspace failure cheap to reproduce, and the free model access makes long agent loops affordable, but both demand the same discipline described above. Treat the server as a disposable environment, declare your artifacts, and verify from scratch before you trust the result.

Limitations and who should not use this

This approach has limits. The cold-start check only sees files inside the repository, so it will not catch state that an agent keeps in its own external memory or database. It also assumes the environment is reproducible; if the server image changes tool versions between restarts, the check can pass while the build still breaks. Teams with a single long-lived server that never restarts may not need this, and agents that never generate artifacts will find the manifest an empty ceremony.

The audience that benefits is anyone running long agent tasks on ephemeral infrastructure, which is precisely the audience that free servers attract. The lesson is not that free infrastructure is unreliable; it is that cheap resources change where failures happen. When you remove the cost of tokens and compute, the remaining constraint is state, and state must be made explicit before you can debug it. If you want to stress-test this pattern, MonkeyCode is open source, and its free server option gives you a low-cost environment to break things in.

Top comments (0)