I really like using cursor 3, but I was a bit bummed that it doesn’t run in the background. I need to use my infra to run builds etc, so using the cloud agents was not an option for me.
To get around that, I vibe-coded a background agent skill that has kind of worked so far. Would love to hear if other people have tried something similar and how it’s gone.
name: background-agent-handoff
description: Launches a headless agent run with --print --output-format stream-json --trust --yolo, records the session id and repo-local handoff state, summarizes worker logs into a markdown checkpoint, and prepares both resume and interactive takeover prompts. Use when the user explicitly asks to hand off work to a background or headless agent, run the agent CLI independently, resume a prior headless agent run, or continue a headless run inside the current interactive Cursor harness.
Background Agent Handoff
Use this skill when
- The user explicitly asks for a background or headless
agentrun. - The user wants to hand off a task, delegate work to the
agentCLI, or resume a prior headless run. - The user wants to read what a headless worker already did and continue the task in the current interactive session.
- The goal is to let a worker run independently, then return with a resumable state file.
Do not use this skill for normal foreground work.
Defaults
- Launch headless with
agent --print --output-format stream-json --trust --yolo. - Create a dedicated session id with
agent create-chatand store it in the handoff file. - If the user specifies a model, pass
--model <model>. - Store handoff state in the repo at
.cursor/agent-handoffs/<handoff-id>/.
Run from the target repo root. If needed, pass --workspace <repo-path>.
Directory layout
For each handoff, create:
.cursor/agent-handoffs/<handoff-id>/
handoff.md
attempt-1.log
attempt-2.log
Use a stable id like 20260407-fix-benchmark-timeout.
Start a new handoff
- Restate the delegated task as a concrete, self-contained instruction.
- Check for an already-running equivalent
agentjob before starting another one. - Create
.cursor/agent-handoffs/<handoff-id>/. - Run
agent create-chatand capture the returned session id. - Write
handoff.mdfrom the template below withStatus: running. - Launch the headless worker and capture stdout and stderr to
attempt-1.log. - Record the exact launch command in
handoff.md.
If agent create-chat fails or returns an empty id, stop and fix that first. Do not start an untracked run.
Command pattern:
chat_id="$(agent create-chat)"
agent --resume "$chat_id" --print --output-format stream-json --trust --yolo [--model MODEL] "FULL TASK PROMPT" > ".cursor/agent-handoffs/<handoff-id>/attempt-1.log" 2>&1
When running from Cursor, prefer starting the command in the background and polling it instead of waiting for the whole run synchronously.
Summarize the worker state
When the worker finishes, stalls, or the user asks for status:
- Read the latest attempt log.
- Use another agent to summarize only what is supported by that log.
- Update
handoff.mdwith the summary, blockers, touched files, and copy-paste-ready prompts for both headless resume and headed takeover. - Keep the raw log file; the markdown summary is a checkpoint, not a replacement.
The summary exists for humans, fresh agents, and the current interactive harness. The session id exists so a later headless run can continue the same chat with --resume.
Use a summary prompt like this:
Summarize this headless agent log for a follow-on agent. Be factual and do not infer unstated results.
Return markdown with these sections:
- Goal
- What it tried
- Files or areas touched
- Current state
- Errors or blockers
- Recommended next step
- Resume prompt
- Headed takeover prompt
If the run is still active, mark the summary as partial.
Resume a handoff
- Read
.cursor/agent-handoffs/<handoff-id>/handoff.mdfirst. - Prefer the stored session id and reuse the
Resume promptsection as the next prompt. - Include the original task, the last known state, and any blockers that must be addressed next.
- Launch a new attempt log such as
attempt-2.log. - Update
handoff.md:
- set
Statusback torunning - increment
Current attempt - append the new command
- replace
Latest summaryafter the new run is summarized
If the stored session id is unavailable, create a fresh chat and seed it from the Resume prompt.
Resume command pattern:
agent --resume "<session-id>" --print --output-format stream-json --trust --yolo [--model MODEL] "RESUME PROMPT FROM handoff.md" > ".cursor/agent-handoffs/<handoff-id>/attempt-N.log" 2>&1
Continue in headed mode
Use this when the user wants the current interactive Cursor agent to take over a headless run.
- Read
.cursor/agent-handoffs/<handoff-id>/handoff.md. - Read the latest
attempt-N.logif the summary is missing, stale, or too vague. - Use the
Headed Takeover Promptsection as the starting context for the current harness. - Continue the task directly in the current session instead of launching another headless run.
- Update
handoff.mdto note that the task moved to interactive ownership and summarize what happened next.
Do not assume the interactive harness can directly attach to the headless chat session id. Treat handoff.md plus the latest log as the bridge.
Handoff template
Use this structure for .cursor/agent-handoffs/<handoff-id>/handoff.md:
# Background Agent Handoff: <handoff-id>
## Metadata
- Status: running
- Task: <original delegated task>
- Model: <default or explicit model>
- Session ID: <agent create-chat output>
- Workspace: <repo path>
- Started: <timestamp>
- Current attempt: 1
## Commands
```bash
<exact launch command>
```
## Logs
- `attempt-1.log`
## Latest Summary
- Pending.
## What It Tried
- Pending.
## Files Or Areas Touched
- Pending.
## Errors Or Blockers
- Pending.
## Recommended Next Step
- Pending.
## Resume Prompt
```text
Continue the delegated task below.
Original task:
<original task>
Latest known state:
<summary from latest attempt>
Next step:
<single concrete next action>
```
## Headed Takeover Prompt
```text
Continue this task in the current interactive Cursor session.
Original task:
<original task>
What the headless agent already tried:
<factual summary from the latest attempt>
Current state:
<current known state>
Blockers or open questions:
<blockers>
Next step to take now:
<single concrete next action>
```
## Final Outcome
- Pending.
Rules
- Never delete prior attempt logs.
- Never invent progress that is not visible in the log or artifacts.
- Always keep
handoff.mdusable for both headless resume and interactive takeover. - Prefer one handoff directory per delegated task, with additional
attempt-N.logfiles for retries or resumes.