Skip to content
Get API Key

Guides

Stop work and keep history

Stop a task, take it back, archive a task or a worker, and learn how long a task's history is kept on each subscription.

Updated
View as Markdown

Work you gave sometimes needs to stop: a task goes the wrong way, a program has a bug, or a key leaked. This guide shows each way to stop, from the gentlest to the strongest, and then what is kept afterwards and for how long.

Each step shows curl, TypeScript and Python. Pick one and the page keeps it picked. The TypeScript and Python steps build one small program, so add each step's code to the same file.

Before you start

  • A key in LITTLE_WORKER_API_KEY. The Quickstart makes one, and API keys says more.
  • For curl: curl and jq.
  • For TypeScript: Node 22.18 or later, which runs a .ts file as it is. Save the program as stop.ts and run node stop.ts.
  • For Python: Python 3 and the requests library (pip install requests). Save the program as stop.py and run python3 stop.py.

The program makes a worker of its own to stop, so archiving it at the end costs you nothing. Archiving a worker cannot be undone, so do not point the last step at one you keep.

Step 1: Give a task that runs long

Make a worker, and give it a task that takes a while to write, so it is still working when you stop it:

curl https://core.thelittleworker.com/api/v1/workers \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  -H "content-type: application/json" \
  -d '{ "name": "Throwaway writer", "system": "You write long, careful drafts." }'
# Keep the worker's id as WORKER_ID, then:
curl https://core.thelittleworker.com/api/v1/tasks \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  -H "content-type: application/json" \
  -d '{
    "worker": "'"$WORKER_ID"'",
    "title": "Long essay",
    "initial_events": [
      {
        "type": "user.message",
        "content": [{ "type": "text", "text": "Write a 2,000 word essay on why a shop should open early." }]
      }
    ]
  }'

With curl, keep the ids of the worker and the task:

Shell
export WORKER_ID="worker_bf5ff997fca044b38dc1cc9ea5b60100"
export TASK_ID="task_01M5TTRJKWYAK3XHFX432K5MBV"

Step 2: Interrupt it

An interrupt, sent as a user.interrupt event (Send events), stops the work in hand. The model stops, the turn ends with a task.status_idle event whose stop_reason is end_turn, and the task stays open. Your next user.message starts a new turn. This is the gentlest way to stop, and the one to try first.

curl https://core.thelittleworker.com/api/v1/tasks/$TASK_ID/events \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  -H "content-type: application/json" \
  -d '{ "events": [{ "type": "user.interrupt" }] }'

# The task is idle a moment later:
curl -s https://core.thelittleworker.com/api/v1/tasks/$TASK_ID \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  | jq '{status, state, stop_reason}'

The answer to the interrupt is 200, with run_id naming the run it stopped. A moment later the task is idle, and state reads not_started with waiting_reason stopped:

JSON
{
  "status": "idle",
  "state": { "status": "not_started", "needs": null, "waiting_reason": "stopped" },
  "stop_reason": { "type": "end_turn" }
}

An interrupt stops the next step, not the last one. An email already sent, a post already made, a file already written and a form already submitted stay done. A step that was running when you interrupted may have finished: its worker.tool_result event has a status of succeeded, failed, cancelled or outcome_unknown. Read the events after an interrupt, and when a status is outcome_unknown, check the outside system. To refuse an action before it runs, make it ask first (Answer approvals from your program).

A task held at its own budget has no work in hand, so the interrupt is accepted and does nothing.

Step 3: Take a task back

Taking a task back is the strongest way to stop one task. It stops every run the task has not finished, closes the Allows and questions it waits on, and marks the task taken back, whatever its worker is doing. Give a second task, and take it back:

curl https://core.thelittleworker.com/api/v1/tasks \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  -H "content-type: application/json" \
  -d '{
    "worker": "'"$WORKER_ID"'",
    "title": "Another essay",
    "initial_events": [
      {
        "type": "user.message",
        "content": [{ "type": "text", "text": "Write a 2,000 word essay on why a shop should open early." }]
      }
    ]
  }'
# Keep its id as SECOND_ID, then take it back:
curl https://core.thelittleworker.com/api/v1/tasks/$SECOND_ID/withdraw \
  -X POST \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19"

The answer names what happened:

JSON
{
  "type": "task_withdrawal",
  "task_id": "task_01M5TTRK2N8Q7XH6D4B3C9ZYAE",
  "outcome": "withdrawn"
}

outcome is withdrawn, or done when the task had already finished: a finished task stays finished. Taking a task back twice answers withdrawn both times, so a retry is safe.

A task taken back is gone: reading it answers 404, and lists leave it out. It takes nothing more, and a task.status_terminated event is written for it. Use an interrupt when you may want to go on with the task, and take it back when you are done with it.

Step 4: Archive the task

Archiving keeps everything a task holds and hides it. An archived task takes no new message, and lists leave it out unless you ask for include_archived=true. It cannot be undone, and archiving twice changes nothing. It is how you tidy up a task you may want to read later.

curl https://core.thelittleworker.com/api/v1/tasks/$TASK_ID/archive \
  -X POST \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19"

Archiving is refused with 409 while the task has a run that has not ended, so interrupt it and wait for it to be idle first, as step 2 does. It is also 409 with workflow_run_open while a workflow run of the task is open. Ask the worker to stop the run, or take the task back.

Deleting a task removes its events and the files it made that you did not keep. It needs a key made with Can delete tasks, which Settings does not offer yet, so a key made there gets 403 with person_required. See Delete a task.

Step 5: Archive the worker

Archiving a worker hides it, and archives its routines. It cannot be undone, and a worker is never deleted. List archived workers too with GET /workers?include_archived=true.

The archive is refused with 409 and conflict_error while the worker has a queued, running or waiting run, so a task you queued is never left behind a worker that is gone. Interrupt or take back the worker's tasks, wait for them to stop, then archive. The run of the task you took back in step 3 may need a moment to wind down, so the program tries again:

curl https://core.thelittleworker.com/api/v1/workers/$WORKER_ID/archive \
  -X POST \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19"

The answer is the worker, with status archived and archived_at set.

Stop what starts new tasks

Stopping a task does not stop whatever gives the next one. These stop the source:

To stop Do this What it leaves
A routine that gives tasks POST /routines/{routine_id}/pause stops its schedule and its other starts. You can still run it by hand. POST /routines/{routine_id}/archive ends it for good. A task the routine already started goes on. Stop it with an interrupt or take it back.
A program that uses a key Choose Remove next to the key in Settings, then API Keys. A task the program already started goes on.

How long history is kept

A task's history is its runs, the messages the worker answered, its tool uses and results, its approvals, and the events of all of them. How long it is kept depends on the subscription:

Subscription History
Free 7 days. A piece of work is deleted once every run in it ended more than 7 days ago.
Any paid subscription Kept until you delete it.
A core on your own computer Kept. It never deletes history.

A workspace that moves from a paid subscription to the free one keeps what it had for 7 days first. Little Worker looks for old history every hour.

The deletion takes a piece of work with everything it did. It keeps your workers, tasks, routines, memory stores and their notes, password sets, saved files, email, receipts and your decisions. The task itself stays readable.

A file's scope on GET /files/{file_id} tells when it goes:

How the file was made scope When it is deleted
Uploaded with POST /files null Never by a purge. By DELETE /files/{file_id}, or at its expires_at if you set one.
Made by a task { "type": "task", "id": "task_..." } With the task's history, by a purge or by deleting the task.
Made by a task, then kept with POST /files/{file_id}/keep null Only by DELETE /files/{file_id}.

A file attached to a message in the app goes with that message. Files says more.

Read a task after a purge

A purge adds a history.purged event to each task it changed. Its before is the cutoff: history older than that time is gone.

JSON
{
  "type": "history.purged",
  "id": "event_0c4d6e8f1a3b4c5d9e7f2a1b3c5d7e9f",
  "task_id": "task_01M5TTRJKWYAK3XHFX432K5MBV",
  "sequence": "48",
  "processed_at": "2026-10-25T23:00:11.402Z",
  "before": "2026-10-18T23:00:11.402Z"
}
  • GET /tasks/{task_id}/events with no cursor, oldest first, starts with the newest history.purged, then the events that were kept. Ask for them alone with types[]=history.purged.
  • A page, after or Last-Event-ID from before that event, one that missed deleted history, is 400 with cursor_expired. List the task's events from the start again. after=0 never expires.
  • No webhook is sent for a purge. Keep your own copy of the events you need for longer than 7 days.

Next steps

Type a few words, like “give a task” or “errors”.