# stopping work (task.Stop)

> End a task and everything beneath it, including the model call it is in the middle of. Answers whether a live run was actually interrupted, as opposed to the stop being recorded for work that had not started yet. Who may stop work is who may update the task.

<!-- id: agent-task-stop · area: agent · stability: preview · html: https://osysharp.com/reference/agent/task-stop/ -->

## Summary        {#summary}

```osy syntax
var interrupted = task.Stop();
```

Marks the task and everything under it as `Cancelled`, and **trips the model call in flight** so the agent stops
now rather than after the answer it was already paying for.

## Signature      {#signature}

```osy syntax
task.Stop()   // → bool — true when a LIVE run was interrupted
```

The return value distinguishes two real outcomes: **stopped** (a run was executing and has been cut off) and **will
stop** (nothing was running yet, and the request is remembered so the next run ends immediately). A stop button that
conflates them tells the user "done" when the work is still going.

## Description    {#description}

### It stops the work, not just the record   {#actually-stops}

A task can be sitting inside a provider call that takes tens of seconds. `Stop()` cancels it: the call is abandoned,
the run unwinds, and nothing further is charged for that turn. The task's row is marked in the same operation, so a
[watcher](https://osysharp.com/reference/agent/task-watch/) ends and every list stops showing the task as running.

⚑ Both halves matter. Marking the row alone leaves the agent talking to the model; cancelling alone leaves every
screen claiming the work is still in progress.

### Does it stop child tasks too?   {#subtree}

A task driven by a [loop](https://osysharp.com/reference/agent/loop/) is the parent; the run doing the work is a child. `Stop()` therefore ends the
task **and everything beneath it** — stopping only the task you were handed would leave the agent running
underneath it.

⚠ Tasks that have already finished are left alone. A child that completed a second before the stop *did* complete,
and its record of that is worth more than a uniform status across the tree.

### `Cancelled` is not `Failed`   {#cancelled}

A stopped task ends as `Cancelled`. That is deliberately distinct from `Failed`: a failure is the work going wrong
and worth investigating, a stop is somebody deciding it should not continue. If they shared a state, every operator
abort would look like a defect on the one screen you scan for defects.

### Who can stop work   {#security}

**Stopping is an update.** Declare who may update the task and you have declared who may stop it:

```osy syntax
entity ReviewTask : AgentTask {
  security {
    allow read when IsAuthenticated;    // everyone signed in can WATCH
    allow update when IsApprover;       // …only an approver can STOP
  }
}
```

⚠ **Read and update are separate on purpose.** Watching work and ending it are different privileges, and an app that
lets everyone see a task usually does not mean everyone may kill it. A caller without `update` is refused with a
message naming the rule they need.

### What a watcher sees   {#watchers}

A stop appends a final step, so a [`Watch()`](https://osysharp.com/reference/agent/task-watch/) feed ends with a line saying what happened rather
than simply going quiet. A stream that stops producing is otherwise indistinguishable from one that finished
normally.

## Examples       {#examples}

```osy title="stopping-a-review" test app=agent-task-stop
using Osysharp.Agents;

[Principal] entity User {
  [Required, MaxLength(255)] string Email;
  security { allow read when IsAuthenticated; }
}

entity ReviewTask : AgentTask {
  security {
    allow read when IsAuthenticated;
    allow update when IsAuthenticated;
  }
}

/// Ends the work and says whether anything was actually interrupted.
string StopReview(Guid taskId) {
  var task = ReviewTask.Where(t => t.Id == taskId).FirstOrDefault();
  if (task == null) { return "no such task"; }

  return task.Stop() ? "stopped" : "nothing was running — it will not start";
}
```

## See also       {#see-also}
- [watching a task run (task.Watch)](https://osysharp.com/reference/agent/task-watch/) — following work while it runs, and seeing it end
- [the agent task log (AgentTask)](https://osysharp.com/reference/agent/task-log/) — the task itself: what caused it, when it ran, how it finished
- [the agent loop (app.Agent, Loop)](https://osysharp.com/reference/agent/loop/) — why a task and the run beneath it are two rows
