The scariest part of a long AI task is not necessarily failure. It is silence.
A person can finish chores, errands, dinner, and half a day of real life, come back, and still see the agent “working.” At that point two explanations are equally plausible:
- It is diligently running a giant test suite.
- It stopped somewhere hours ago.
A spinner cannot reliably distinguish those cases. A gap in commits cannot either: testing, investigation, generation, comparison, or external waits may legitimately produce no material artifact for a while.
That is why long-running AI needs something separate from intelligence: observability.
1. The answer: if a task may run for more than several minutes, expose its current state
For long-running agents, a final report is not enough. It is useful to expose an intermediate state that another person can read.
You do not need a message every minute saying “still alive.” You need enough information to answer:
- What is it doing now?
- What is already finished?
- What remains?
- Is it testing?
- Is it blocked?
- When was liveness last confirmed?
- When did something materially change?
One practical configuration is to refresh a heartbeat when no visible artifact appears for about 10 minutes, and treat a heartbeat older than 20 minutes as STALE_UNKNOWN, not automatically as “stopped.”
The distinction matters. Silence means “we do not know” before it means “it failed.”
2. Why commit history alone is not enough
Git commits are excellent evidence of material change, but weak evidence of current liveness.
A one-hour regression suite may produce zero commits while everything is healthy. Conversely, committing a meaningless heartbeat file every ten minutes makes the history noisy without proving useful progress.
Keep two concepts separate:
Heartbeat = current state Material change = evidence that code, contracts, artifacts, or verification actually changed
Separate timestamps such as lastHeartbeatAt and lastMaterialChangeAt make a state like “no commit for 30 minutes, but TESTING heartbeat five minutes ago” easy to understand.
The goal is not more commits. The goal is to make silence interpretable.
3. What should be recorded?
A useful long-running run record includes:
runId: unique identity for the runstate: RUNNING, BLOCKED, COMPLETED, STALE_UNKNOWN, and so onphase: READING, IMPLEMENTING, TESTING, VERIFYING, etc.workingOn: the concrete item being worked onstartedAtlastHeartbeatAtlastMaterialChangeAtbranch / baseSha / headSha / PRcompletedMilestones / remainingMilestonesblockerstestsnextCheckpoint
With this, a six-hour job is no longer “some mysterious six-hour blob.” It can be read as:
IMPLEMENTING → TESTING → INTEGRATING → VERIFYING
A brilliant black box is still a black box. That becomes stressful surprisingly quickly.
4. Testing is where heartbeats matter most
Long tests often look exactly like a frozen agent.
Before a long test, record:
phase = TESTING- suite name
- scope
- an objective count such as
84 / 127, if a fixed denominator exists - whether any failure has appeared
Avoid made-up percentages such as “82% complete” for design or debugging. Nobody knows what the remaining 18% means.
Percentages are useful only when the denominator is objectively fixed:
- 84 / 127 tests
- 3 / 5 acceptance gates
“Implementation is 82% done” is the AI equivalent of “I’m almost there” from someone who may still be at home.
5. Read “did it stop?” in stages
One practical heartbeat policy classifies freshness like this:
| Heartbeat age | Interpretation |
|---|---|
| 0–10 minutes | CURRENT |
| 10–20 minutes | HEARTBEAT_OVERDUE |
| More than 20 minutes | STALE_UNKNOWN |
STALE_UNKNOWN is not FAILED.
Then inspect, in order:
- the current progress record
- Check / Status signals
- branch / PR activity
- latest commit
- inference only as a last resort
A stale heartbeat followed by a fresh PR often means the agent kept working and merely forgot the status update.
Yes, AI can have the equivalent of: did the job, forgot the timesheet.
6. Progress-management mistakes to avoid
Do not commit heartbeat-only files to main
It pollutes history, creates writer conflicts, and may trigger unnecessary CI or deployment. Use a mutable lightweight surface such as an issue comment, Check, Status, or a non-production ops area.
Do not add a new comment for every heartbeat
A single mutable record per run is easier to read than a chronological landfill of “still running” comments.
Do not equate silence with failure
If the heartbeat is merely stale, use STALE_UNKNOWN. Reserve failure for affirmative failure evidence.
Do not leak secrets into progress logs
No API keys, tokens, passwords, private URLs, raw private chats, personal data, or confidential file contents. Progress logs need operational state, not a data breach festival.
Do not stop safe work because the observability channel broke
If the preferred progress API fails, degrade gracefully to another sink and continue work that can safely continue.
7. A practical template
State: RUNNING
Phase: TESTING
Run ID: agent-20260916-long-task
Started: 10:00
Last heartbeat: 14:05
Last material change: 13:42
Branch: feat/long-task
Head SHA: abc1234
PR: #123
Working on:
- regression tests
Completed:
- runtime implementation
- contract update
Remaining:
- regression completion
- merge verification
- production readback
Blockers:
- none
Tests:
- 84 / 127 passed so far
- no failure observed
Next checkpoint:
- finish regression, then integration
This is enough to turn “did it stop?” into “okay, it is testing.”
Progress visibility is not primarily about pressuring the agent. It prevents humans from unnecessarily restarting, interrupting, or issuing duplicate instructions.
8. Summary: design intelligence and visibility separately
Long-running AI requires distinctions that short chats often hide:
- no commit ≠ stopped
- heartbeat ≠ material progress
- stale heartbeat ≠ failure
- one blocker ≠ global stop
- silence during testing ≠ asleep
If an AI can work for six hours, a person should not have to watch it for six hours.
The better design is simple: when you check, you can immediately tell where it is.
The ideal long-running agent is not one that talks continuously.
It works quietly—but when you look, its current location is obvious.

