---
title: "How a task runs"
description: "What happens between your request and a closed task, and the limits that stop a run. Read it to know why OMS stops when it does."
url: https://barestate.xyz/docs/concepts/how-a-task-runs
---

# How a task runs

> What happens between your request and a closed task, and the limits that stop a run. Read it to know why OMS stops when it does.

Every task has three parts: a requirements file, a worktree, and a budget. The model does the work in the worktree, but it doesn't get to decide when the work is finished. A separate checker does that by testing the requirements.

## The loop

![Your request creates a task worktree with requirements and a budget. The model edits files, then calls propose_done, which moves the requirement from active to proposed. The independent checker runs on a fresh offline Surfpool chain. A fail sends it back to active for another attempt if budget remains. A pass lets the session settle. OMS stops and asks you on repeated_failure, when the budget is used up, or at the attempt cap, which defaults to 5.](https://barestate.xyz/docs/images/diagrams/task-loop-light.svg)

*The model proposes with propose_done. The independent checker decides: a pass settles the session, a fail returns the requirement to active while budget remains.*

### You describe the work

OMS creates a task with a requirements file and a managed Git worktree. The bare `oms` command uses a persistent starter workspace under `~/.oms/starter`.

### The model edits files

The model reads and edits files in the task worktree and runs commands in the sandbox. Its file tools reach only regular files inside the task root.

### The model proposes that it is done

The model's only completion tool is `propose_done`, which moves the active requirement from `active` to `proposed`. It can't close a requirement itself.

### The checker runs

If a proposal is pending when the session is about to settle, the independent checker runs first. See [The independent checker](https://barestate.xyz/docs/concepts/independent-checker).

### The result decides what happens next

A pass lets the session settle. A fail gives the model one more attempt if budget remains. If the checker is unavailable or still running, OMS stops rather than letting the session settle without a verdict.

## What stops a run

OMS stops and asks you when the same failure repeats twice in a row (`repeated_failure`), when the budget is used up, when attempts reach the cap (the default is 5), or when the state is malformed.

The checker adds a limit of its own: it reopens a requirement at most 3 times, and after that the requirement is `blocked`.

A verifier that throws, returns a malformed result, or can't read the contract counts as unavailable, and unavailable stops the run. The checker's feedback passes through a redactor before the model sees it. If the redactor fails, OMS withholds the feedback.

## Budget and usage

OMS keeps a durable journal. Before each model request it reserves tokens and spend, and afterward it settles the difference. If it can't confirm an outcome, the reserved amount stays charged, and a replay after a crash keeps it that way.

These are the defaults shown by `oms --help`:

| Cap | Default |
|---|---|
| Tokens | 2,000,000 |
| API spend | $5 |
| Time | 30 minutes |
| Output tokens per response | 32,768 |

A normal launch is interactive and has no idle expiry. Pass `--bounded` to apply the caps to the whole session. Calls on a ChatGPT subscription are counted at catalog-equivalent prices, not your invoice. `/usage` and `/status` show the numbers.

## When a request fails

A dropped stream, a 5xx or an overload counts as transient. OMS charges it at its reserved bound, then retries the turn within the remaining budget. Any other failure stays unknown, is never free, and blocks further dispatch. OMS also refuses hidden retries inside the model SDK, so every retry shows up in the budget.

## Long conversations

When messages pass 60% of the input cap, OMS replaces the oldest tool results with one-line stubs and drops old assistant reasoning, oldest first, until messages are under 40%. The two newest tool results always stay, and calls and arguments are never changed. The transcript on disk keeps everything.

## Related

**[Work until a check passes](https://barestate.xyz/docs/guides/work-until-it-passes)**
Use `/goal`, `/verify` and `/status`.

**[CLI reference](https://barestate.xyz/docs/reference/cli)**
Flags for bounded runs, sandbox and approval.
