Kill the worker.
The agent keeps going.
A support-digest agent works through a week of fictional tickets for several minutes. Every model and tool call is a checkpointed workflow step, its memory lives in a Chalk Volume, and its waits are durable timers that survive restarts. Kill its worker mid-step and watch it pick up where it left off.
Start a run, then kill its worker
Press Start a live run and the agent reviews twelve tickets in three batches, waiting two minutes between batches. Press Kill the worker at any point: the next ticket step exits its worker process after the model call, before saving its note, and the run picks up that step again on a fresh worker. A live run takes about seven minutes and is rate-limited; recorded runs replay in about a minute.
Why the run survives
Long agents fail in the middle: a pod is evicted, a deploy rolls, a tool times out. Built on Chalk Workflows, the agent loses at most the one step that was in flight.
Every step is a checkpoint
Each model call and tool call is a workflow task. The orchestrator records its result the moment it finishes, so the run never redoes a finished step.
Kill it, it keeps going
When a worker dies mid-step, that attempt times out and runs again on a fresh worker. The run carries on from the last finished step, not from the start.
Memory in a Volume
Notes, a scratchpad, the report and a lessons file live in a Chalk Volume. The report is written from those files, and the next run starts by reading the lessons.
An agent loop, made durable
Write the agent as an async @workflow and make each model or tool call a @task. Keep memory in a Volume so any step, on any worker, can read what earlier steps wrote.
Deployed workflow workers are in preview and ship in upcoming chalkcompute and chalkpy releases. Talk to us to try them in your environment today.
See the workflows demo →# /// script
# dependencies = ["chalkcompute", "chalkpy[workflows]"]
# ///
import asyncio
from chalk.workflows import task, workflow
@workflow
async def support_digest(run_key: str, ticket_ids: list[str]) -> dict:
lessons = await recall_lessons(run_key)
for start in range(0, len(ticket_ids), 4):
for ticket_id in ticket_ids[start : start + 4]:
# Each call is a checkpoint: finished steps never run again.
await review_ticket(run_key, ticket_id, lessons)
# A durable timer. No worker holds it, and it survives restarts.
await asyncio.sleep(120)
return await write_report(run_key)Agents that run for minutes or days
Research, triage and monitoring agents do real work over long stretches. They should pay for the work, not for the waiting, and never start over.
Waits that cost nothing
asyncio.sleep in a workflow is a durable timer held by the orchestrator, not a thread on a worker. It survives restarts, and the worker scales to zero between runs.
Deploy the file as a worker
deploy_workflow_worker turns agent.py into a scale-to-zero worker group. It starts when a run is queued and stops shortly after the last one finishes.
Retries per step
Set retries, retry_delay and timeout on each @task. A rate-limited tool or a lost worker costs a retry of one step, not the whole run.
Models through the gateway
The agent calls its model through the Chalk model gateway, so keys, usage and traces stay in your environment.
Memory you can inspect
Every Volume write is a new version. Read any file the agent wrote, or roll the memory back, from the SDK.
Plain async Python
The agent is an async function that calls tasks. Test it in-process, then deploy the same file as a worker.
Run your agents next to your data
Talk to an engineer about running durable agents on scale-to-zero workers in your cloud.