Cursor Background Agents Without Tears
We’re using Cursor to go all in—not just for AI-assisted coding, but to move faster, work smarter, and collaborate seamlessly.
It’s become a core part of our development stack—whether we’re iterating on new MVPs, shipping updates to live customer projects, or exploring fresh ideas. Cursor’s background agents let us run AI-generated prompts in the cloud, apply structured code changes, and create pull requests automatically—all without touching our local dev environments.
It’s fast. It’s flexible. You can even update a prompt and refactor a module from your mobile phone.
And because agents run in the background—executing changes for you—they’re especially powerful for solo founders and small teams trying to move without friction.
But then—after setting up a new Python project and configuring a custom Dockerfile—your Cursor background agent refuses to start in the cloud, even though the exact same image builds flawlessly on your local machine.
You debug. You swear. Locally, it works. But somewhere in the cloud, the build fails with a Debian APT error about the future. Literally.
This is one of those subtle but painful interruptions that slows your shipping velocity—and erodes momentum.
If you’ve run into "InRelease is not valid yet" errors while building Docker-based agents, this post is for you.
We’ll walk through how I fixed it for a real Python/FastAPI project —using Cursor background agents.
From Zero to Custom: Why We Defined a Dockerfile
Out of the box, Cursor background agents don’t require a custom Dockerfile. You can get started quickly with a default environment—perfect for many Node, Python, or TypeScript projects that don’t need special system-level dependencies. Cursor takes care of provisioning the VM, installing your project’s dependencies, and running the agent in the background so the AI can execute your prompts and submit pull requests.
But for more complex setups, that default environment can fall short.
In our case—working on Storyteller, a FastAPI-based audio application—we needed tighter control. The project uses:
- Python 3.11 + FastAPI
- Audio stack:
ffmpeg
,pydub
, etc. - Text-to-speech (via ElevenLabs), which relies on system-level audio tooling
- Headless dependencies (like
xvfb
) for proper audio handling in CI and background environments
The role of environment.json
We also wanted a base image that was lean, non-root, and wouldn’t bake our app code or Python dependencies into the image itself (those get installed per repo state at runtime).
That’s where the .cursor/environment.json
file comes in.
This file controls how the agent is built and started. It lets you:
- Specify a custom Dockerfile and build context
- Define install commands for Python (or any) dependencies
- Start services or servers like
uvicorn
- Expose ports for web UIs or APIs
- Define terminals for common interactive commands
Here’s a simplified example:
{
"agentCanUpdateSnapshot": true,
"name": "fastapi-env",
"build": { "dockerfile": "./Dockerfile", "context": ".." },
"install": "pip install -r requirements-dev.txt",
"start": "uvicorn app.main:app --host 0.0.0.0 --port 8000",
"ports": [{ "name": "web", "port": 8000 }],
"terminals": [
{
"name": "FastAPI dev server",
"command": "uvicorn app.main:app --host 0.0.0.0 --port 8000",
"description": "Starts the API server"
}
]
}
Creating your custom Dockerfile
If you're looking to define a custom Dockerfile for your own agent, Cursor provides a short guide that explains the key principles:
- Start with a lightweight base image
Use something minimal likepython:3.11-slim
to keep builds fast and images small. - Avoid copying your application code
Cursor will clone the repo separately when the agent runs—don’t bake it into the image. - Create a non-root user
This prevents permission issues and aligns with best practices for running dev tools securely. - Set
WORKDIR
to that user’s home directory
Ensures consistency and avoids writing to system directories. - Preinstall system dependencies
Install tools likecurl
,git
,ffmpeg
, orxvfb
as needed—these won’t change frequently and should live in the base image. - Leave Python dependencies to
environment.json
Let the agent install those dynamically using theinstall
field.
The Error That Broke the Background Agent Startup (But Not Locally)
Once our custom Dockerfile and environment.json
were in place, we expected everything to “just work.”
And locally, it did. The image built cleanly. No surprises.
But when Cursor’s background agent tried to start—running that same Dockerfile in the cloud—the VM failed during its initial setup phase. The logs revealed a very specific Debian APT error:
E: Release file for http://deb.debian.org/debian/dists/bookworm-updates/InRelease is not valid yet (invalid for another 5d ...)
E: Release file for ... is not signed.
At first glance, this looks like a signing or network issue—but it's actually a timestamp validation failure.
What’s really happening:
- When the background agent VM boots up, it runs
apt-get update
to install system dependencies. - Debian’s APT system performs strict time checks on package metadata, using headers like
Date
andValid-Until
. - If the VM’s system clock is slightly behind the timestamp on the Debian mirror, APT treats the metadata as “from the future.”
- It then refuses to use the repository and exits with code 100.
This was not a bug in our Dockerfile or environment config. It was a case of clock skew between Cursor’s cloud VM and the Debian server it pulled packages from.
- Local builds worked — because our machines had clocks synced with the mirror.
- Remote agents failed — because the cloud VM’s clock was slightly off.
And since Cursor relies on background agents to run code updates and create pull requests, a failed agent means the AI can’t even begin processing your prompt. No PR, no change, no progress.
The Fix: A Dockerfile That Builds Reliably, Every Time
To make the build resilient, we did three things:
1. Pin to a Stable Debian Image
Avoid “testing” or time-sensitive mirrors (e.g., trixie
). Use something solid:
FROM python:3.11-slim-bookworm
2. Install All System Dependencies Early
We include everything needed for audio + headless workflows:
apt-get install -y --no-install-recommends \
ca-certificates curl ffmpeg git wget xvfb build-essential
3. Configure APT to Ignore Clock Skew
This was the magic:
# Global APT config: tolerate skew and retry
RUN printf '%s\n' \
'Acquire::Check-Valid-Until "false";' \
'Acquire::Check-Date "false";' \
'Acquire::Retries "5";' \
> /etc/apt/apt.conf.d/99-clock-skew.conf
This disables strict time checks during apt-get update
, and adds retries for flaky mirrors. You’ll rarely hit this again.
The Final, Battle-Tested Dockerfile
After chasing false leads and debugging frustrating clock skew errors, this is the Dockerfile that finally made everything click. It handles system setup cleanly, avoids brittle APT behavior, and ensures your Cursor background agent boots reliably—locally or in the cloud—every single time.
FROM python:3.11-slim-bookworm
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
printf '%s\n' \
'Acquire::Check-Valid-Until "false";' \
'Acquire::Check-Date "false";' \
'Acquire::Retries "5";' \
> /etc/apt/apt.conf.d/99-clock-skew.conf
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates curl ffmpeg git wget xvfb build-essential \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -ms /bin/bash ubuntu
USER ubuntu
WORKDIR /home/ubuntu
ENV PATH="/home/ubuntu/.local/bin:${PATH}"
RUN python -m pip install --user --upgrade pip
Summary
In this post, we share how we use Cursor background agents—cloud-based VMs that execute AI-assisted coding prompts and create pull requests—to move faster, offload processing, and collaborate flexibly (even from a phone).
While setting up a custom Dockerfile for a FastAPI + audio project, our agents failed to start remotely with a Debian “InRelease not valid yet” error. The culprit? Clock skew between the VM and Debian mirrors, causing APT to reject package metadata as “from the future.”
The solution was a battle-tested Dockerfile:
- Pinned to a stable Debian base image
- Installing all system dependencies upfront
- Configuring APT to ignore strict date checks and retry on errors
- Running under a non-root user with a clean Python environment
The result: background agents that boot reliably every time, restoring the invisible magic of AI-assisted development.
Subscribe to our newsletter.
Be the first to know - subscribe today
Member discussion