> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# Marathon: long-running agent tasks (CLI)

Marathon runs an Agent across multiple sessions from your terminal with the `runtype` CLI. It streams output in real time and gives the Agent local file tools and a verification-command tool. It also compacts context automatically, pauses at checkpoints, and saves resumable state on disk.

By default, a marathon moves through three phases: research, planning, and execution. In the planning phase, the Agent writes a plan to `.runtype/marathons/<task>/plan.md` in your project. The execution phase then carries out that plan. To replace these phases with your own milestones, use a [playbook](#use-playbooks).

## Before you begin

Complete these steps before you start a marathon:

* Install the Runtype CLI with `npm install -g @runtypelabs/cli`.
* Sign in with `runtype login`. For other sign-in options, see [Authentication](/developer-guides/getting-started/authentication).
* Open a terminal in the root of the project that the Agent works on. The local file tools can reach only files inside the directory where you run the command.

## Start a marathon

To start a marathon with a goal, run the following command:

**`Start a marathon`**

```bash title="Start a marathon"
runtype marathon <agent-id-or-name> -g "Refactor the auth module and add tests"
```

Replace `<agent-id-or-name>` with the Agent ID or name. Replace the goal text with the work that you want the Agent to complete. The `runtype agents task` command accepts the same arguments and flags.

To find an Agent by name, the CLI compares the name, without regard to case, against your 50 most recently created Agents. If none of them matches, the CLI creates a new Agent with that name and saves the selected model and tools on it. To avoid creating an Agent by mistake, pass the Agent ID, which starts with `agent_`.

Use the following flags to control the marathon:

* `--max-sessions <session-count>`: Set the session cap. The default is `50`.
* `--max-cost <amount-usd>`: Set a cost cap in USD.
* `--model <model-id>`: Override the Agent's configured model.
* `--planning-model <model-id>` and `--execution-model <model-id>`: Set the model for the research and planning phases, or for the execution phase.
* `--fallback-model <model-id>`: Set a model to use when the primary model fails.
* `--max-tokens <token-count>` and `--temperature <temperature>`: Override the per-session output-token budget and sampling temperature. Set the temperature from `0` to `2`. The CLI applies these values to every phase. Playbook milestones can override them per phase.
* `-t, --tools <tool-name...>`: Enable built-in tools, such as `exa` or `firecrawl`.
* `--sandbox <provider>`: Enable sandboxed code execution. Set `<provider>` to `runtype-sandbox`, `daytona`, `cloudflare-worker`, or `quickjs`.
* `--no-session-search`: Turn off search over earlier session output. By default, the Agent can call `search_session_history` to look up output from earlier sessions.
* `--no-auto-compact`: Turn off automatic context compaction. To change when compaction starts, set `--compact-threshold` to a percentage, such as `90%`, or to a token count.
* `--checkpoint-timeout <seconds>`: Set how long a checkpoint waits before Marathon continues. For more information, see [Use checkpoints](#use-checkpoints).
* `--track`: Sync progress to an `agent-task` record named after the task, so that you can follow the run in the dashboard.
* `--json`: Print the final result as JSON.
* `--name <task-name>`: Set the task name for state files. The default is the Agent ID.
* `--resume [message]`: Continue from saved state, optionally with a new message.
* `--session <task-name>`: Select a saved task by name. Use it with `--resume`.
* `--fresh`: Start a new run and ignore saved state for the task.
* `--state-dir <path>`: Store state files in a different directory.

Replace each angle-bracket value in a flag with the value for your task. For the full list of flags, run `runtype marathon --help`.

> **Note**
>
> `--fallback-model` and a playbook's `fallbackModels` change the Agent's saved error-handling configuration. The fallback chain stays on the Agent after the marathon ends and applies to the Agent's other runs. For more information, see [Error handling](/user-guide/agents/creating-and-configuring-agents#error-handling).

When the marathon ends, the CLI prints a summary with the final status, the session count, the total cost, and the path to the state file.

### Where Marathon stores state

Marathon stores state in `~/.runtype/projects/<hash>/marathons/`. The `<hash>` value identifies the project. The directory contains a `<task>.json` snapshot and a `<task>.tree.jsonl` session tree. It also contains a `<task>.events/` directory for raw stream events, and a `<task>/outputs/` directory where Marathon saves large tool outputs to keep them out of the model context. Keep `<task>/outputs/` with `<task>.json` and `<task>.tree.jsonl` when you move or back up a marathon task.

The task plan is in your project at `.runtype/marathons/<task>/plan.md`, not in the state directory.

## Local tools

Marathon gives the Agent the following local tools:

* `read_file`, `list_directory`, `search_repo`, `glob_files`, and `tree_directory`: Read and explore project files.
* `write_file` and `edit_file`: Create and change files. Marathon saves a checkpoint of each file before the Agent changes it.
* `restore_file_checkpoint`: Restore a file from its checkpoint.
* `read_offloaded_output`: Read a large tool output that Marathon saved to `<task>/outputs/`.
* `run_check`: Run a verification command, such as a test or lint command. For the commands that it accepts, see [Verification commands](#verification-commands).
* `search_session_history`: Search output from earlier sessions.
* `run_sandbox_code` and `deploy_sandbox`: Run code and deploy a preview in a sandbox. These tools are available only when you pass `--sandbox`. `deploy_sandbox` requires the `runtype-sandbox` or `daytona` provider.

The file tools can reach only paths inside the directory where you started Marathon. A symlink that points outside that directory is also blocked. They also block the `.git` and `.runtype` directories and sensitive files, such as `.env` files and private keys. The Agent can still write its plan file. A blocked path returns an `Access denied` error to the Agent.

## Steer a running Agent

While Marathon streams an Agent session, press **Enter** to open the steering composer. Use the following keys in the composer:

* Press **Enter** to queue your message. The current session wraps up at the next tool call, and Marathon delivers the message at the start of the next session.
* Press **Tab** to switch delivery between `next turn` and `after all work`. A follow-up message runs after the task would otherwise finish.
* Press **Esc** to close the composer and keep your draft.

The CLI displays queued-message counts while messages wait. In the planning phase, the Agent can write only to the plan file. A steering message that requests an immediate write takes effect after the plan is updated.

To stop the current session, press **Esc** twice while the Agent works. The session stops immediately. Marathon preserves observed cost and progress and creates a `stopped` checkpoint. It restores queued steering messages and the composer draft in the checkpoint input. Edit the input and press **Enter** to continue, or press **Enter** with empty input to exit. Resume a stopped task with `--resume`.

## Use checkpoints

By default, Marathon pauses at a checkpoint after each session and at the end of the task. At a checkpoint after a session, Marathon continues automatically after 10 seconds if you don't type anything. The checkpoint at the end of the task waits for your input. At a checkpoint, press **Enter** to continue, enter a message to steer the next session, or enter a slash command.

To change how long Marathon waits before it continues, set `--checkpoint-timeout <seconds>`. The `runtype marathon --help` output lists `--no-checkpoint` and `--no-local-tools`, but neither flag has an effect: checkpoint pauses and the local file tools stay on.

Use the following commands at a checkpoint:

* `/model`: Change the model for subsequent sessions.
* `/tools`: Toggle local tools on or off.
* `/sandbox <provider>`: Switch the sandbox provider. Enter `/sandbox` with no provider to turn off the sandbox.
* `/reflect`: Write guidance that asks the Agent to reassess its approach before the next session.
* `/tree`: Browse session branches and switch between them.
* `/fork`: Branch the conversation from an earlier message.
* `/copy`: Copy the session JSON to the clipboard.
* `/copy-trimmed`: Copy the session JSON with large payloads trimmed.
* `/open`: Open the state file.
* `/stop`: Stop the marathon and save state.
* `/help`: Show all commands and shortcuts.

Replace `<provider>` with a sandbox provider from the `--sandbox` flag.

> **Note**
>
> The help panel and the command menu also list `/plan`, `/status`, and `/revert`. These commands have no effect at a checkpoint. Marathon sends the text to the Agent as a steering message. To read the plan, open `.runtype/marathons/<task>/plan.md` in your project.

## Manage session branches

Marathon records the conversation in `<task>.tree.jsonl` as a tree with parent links. Use `/fork` to branch from an earlier user message, or use `/tree` to switch to another checkpoint.

Use these commands to navigate session branches:

* Enter `/fork` and select a user message on the current branch. Enter a new instruction to create a branch from that message. The next session uses history truncated at that message, and the original branch remains in the tree.
* Enter `/tree` and select a checkpoint to switch branches. The next session continues from that checkpoint and its branch history. The tree view marks the current head. It labels entries that are not messages, such as saved artifacts and compaction summaries, as metadata.

## Resume a marathon

To resume a saved task with its full history, run the following command:

**`Resume a marathon`**

```bash title="Resume a marathon"
runtype marathon <agent-id-or-name> --name <task-name> --resume
```

Replace `<agent-id-or-name>` with the Agent ID or name and `<task-name>` with the task name.

Marathon opens a resume checkpoint before the next session. Use it to steer the task, switch branches, or change settings.

The session and cost caps include the sessions and cost from earlier runs of the task. For example, a task that stopped at 50 sessions has no sessions left when you resume it with the default `--max-sessions` of `50`. To continue it, pass a higher `--max-sessions` value. If the task stopped at the cost cap, pass a higher `--max-cost` value.

If you pass `--resume` without `--name` or `--session`, Marathon offers the most recent task. In a script or CI job, always pass `--name` with `--resume`, or pass `--fresh`.

### When a marathon ends

The summary at the end of a run shows one of these statuses:

* `complete`: The Agent finished the task.
* `max_sessions`: The run reached the session cap. Resume with a higher `--max-sessions` value.
* `budget_exceeded`: The run reached the cost cap. Resume with a higher `--max-cost` value.
* `stalled`: Several sessions in a row ended without a tool action. Change the goal or the model, and then resume.
* `paused`: The run stopped before it finished, for example because you stopped it. Resume it with `--resume`.
* `error`: The run failed. The summary shows the last error.

### Troubleshoot resume errors

The following errors are the most common reasons that a start or resume fails:

* `Local marathon state already exists at <path>. Use --resume to continue it or --fresh to start over.`: Saved state exists for the task, and the terminal can't show the resume prompt. Pass `--resume` or `--fresh`.
* `--resume without --name or --session is ambiguous in non-interactive mode.`: Pass `--name <task-name>` with `--resume`.
* `Cannot use --resume and --fresh together.`: Pass only one of the two flags.
* `No state files found to resume.`: No saved task exists in the state directory. Run without `--resume` to start a new task, or check `--state-dir`.

## Use playbooks

Use a playbook to replace the default Marathon workflow of research, planning, and execution with milestones that define instructions, models, completion rules, and runtime guardrails. To run a playbook named `release-notes`, use the following command:

**`Run a playbook`**

```bash title="Run a playbook"
runtype marathon <agent-id-or-name> -g "Write release notes for the repository changes" --playbook release-notes
```

The CLI checks playbook paths in this order:

1. An exact file path.
2. `.runtype/marathons/playbooks/<playbook-name>.yaml`, `.yml`, `.json`, `.ts`, or `.mts` in the current project.
3. The same paths under `~/.runtype/`.

Replace `<playbook-name>` with the value that you pass to `--playbook`.

### Define milestones

The CLI runs milestones in order. The following YAML defines a two-milestone playbook:

**`release-notes.yaml`**

```yaml title="release-notes.yaml"
name: release-notes
policy:
  allowedWriteGlobs: ['docs/releases/**']
  requirePlanBeforeWrite: true
milestones:
  - name: research
    model: claude-haiku-4-5
    instructions: |
      Review the repository changes.
      Then write a short outline to the plan file: {{planPath}}
    completionCriteria:
      type: evidence
      minReadFiles: 2
    transitionSummary: 'Outline done. Moving to {{nextPhase}}.'
  - name: write
    model: claude-sonnet-5
    fallbackModels: [claude-opus-5]
    instructions: |
      Write the release notes under docs/releases/ following the outline.
    recovery:
      afterEmptySessions: 1
      message: Write a file under docs/releases/ now.
    canAcceptCompletion: true
```

Use these fields to configure each milestone:

* `instructions`: Define the prompt for the milestone. Support `{{key}}` interpolation from run state, such as `{{planPath}}`, which resolves to the task's plan file.
* `toolGuidance`: Add guidance lines to the prompt's tools section.
* `model` and `fallbackModels`: Set the milestone's model and its fallback chain for errors and stall escalation. Marathon saves the fallback chain to the Agent.
* `maxTokens` and `temperature`: Set the output-token budget and sampling temperature from `0` to `2`. These fields take precedence over the CLI flags and top-level defaults.
* `fallbackOnEmpty`: Enable fallback models when the model returns no visible text after a successful request. The default is off. Set `fallbackModels` to provide a fallback chain.
* `completionCriteria`: Define when the milestone advances.
* `recovery`: Add a message after the configured number of consecutive empty sessions. The default is `2`.
* `transitionSummary`: Add a message when the milestone completes. Use `{{nextPhase}}` to reference the next phase.
* `canAcceptCompletion`: Set this field to `true` on the final milestone to accept the Agent's `TASK_COMPLETE` signal. Without an accepting milestone, the loader warns and the run can end only by stalling or exhausting its budget.

Set these fields at the playbook level:

* `policy`: Narrow runtime behavior.
* `stallPolicy`: Configure recovery, model escalation, and stalled-run thresholds.
* `maxTokens` and `temperature`: Set defaults for milestones without their own values. CLI flags take precedence.
* `fallbackOnEmpty`: Enable empty-output fallback for milestones without their own setting.
* `plugins`: Load custom hook modules.

### Set completion criteria

Choose a built-in completion criterion or a hook reference:

* `evidence`: Advance after the Agent reads at least `minReadFiles` files. The default is `1`.
* `sessions`: Advance after at least `minSessions` sessions run in the milestone. The default is `1`.
* `planWritten`: Advance after the Agent writes its plan artifact.
* `never`: The milestone never advances. The run ends only when the Agent sends `TASK_COMPLETE` and the milestone sets `canAcceptCompletion: true`.
* Hook reference: Set `type` to a completion hook reference for custom logic.

### Set policies

Use the `policy` block to narrow runtime behavior. A playbook policy can't override global safety denials, so paths such as `.env` files and private keys remain blocked. Marathon adds the policy rules to the Agent's tool guidance.

Use the following fields in the `policy` block:

* `allowedReadGlobs`: Block reads outside matching paths.
* `allowedWriteGlobs`: Block writes outside matching paths. The plan file remains allowed.
* `blockedTools`: Block named tools.
* `blockDiscoveryTools`: Block the discovery tools `search_repo`, `glob_files`, `tree_directory`, and `list_directory`.
* `requirePlanBeforeWrite`: Require the plan before non-plan writes.
* `requireVerification`: Require a passing verification command before Marathon accepts `TASK_COMPLETE`. The Agent runs the command with the `run_check` tool.
* `outputRoot`: For creation tasks, limit new files to a directory.

### Verification commands

The `run_check` tool accepts one non-destructive check command at a time. It accepts commands that match these patterns:

* `pnpm`, `npm`, `yarn`, or `bun` followed by `test`, `lint`, `build`, `check`, or `typecheck`, directly or through `run`.
* `pnpm exec`, `npm exec`, `yarn exec`, or `bun exec` followed by `tsc`, `vitest`, `eslint`, `prettier`, or `jest`.
* `vitest`, `jest`, `pytest`, `eslint`, `ruff`, `mypy`, or `tsc`.
* `playwright test`, `prettier --check`, `cargo test`, `cargo check`, `go test`, `deno test`, `deno check`, or `git diff --check`.
* `make` or `just` followed by `test`, `lint`, `build`, `check`, or `typecheck`.

The tool rejects pipes, `&&`, `;`, redirects, and command substitution. It also rejects commands such as `rm`, `curl`, `git push`, and package installs. A script command, such as `pnpm test`, is also rejected when `package.json` has uncommitted changes or the project isn't a Git repository. The same rule applies to `make` with its Makefile and to `just` with its justfile. Each command times out after 120 seconds by default, and the Agent can raise the timeout to 600 seconds.

A rejected command can't satisfy `requireVerification`. If the Agent's verification is blocked for two sessions in a row, Marathon waives the requirement for the rest of the run.

### Configure stall handling

Use `stallPolicy` to react when consecutive sessions perform no tool actions. A text-only session counts as empty. Use the following fields to configure the response:

* `nudgeAfter`: Inject a recovery message into the next session after the configured number of consecutive empty sessions.
* `escalateModelAfter`: Switch the milestone to its next fallback model and restart after the configured number of consecutive empty sessions.
* `stopAfter`: Mark the run as stalled after the configured number of consecutive empty sessions. The default is `3`.

Milestone `recovery` messages and `stallPolicy` use the same counter. A session that contains text but no tool action still increments the counter.

### Reference hooks

Use a registered hook name in any behavior slot instead of inline content. The `builtin:` namespace exposes hooks from the default workflow. Use these hooks to reuse one behavior without redefining it.

The following YAML uses built-in hooks for instructions, completion, and interception:

**`hooked-playbook.yaml`**

```yaml title="hooked-playbook.yaml"
milestones:
  - name: research
    instructions: builtin:research-instructions
    completionCriteria: { type: builtin:research-complete }
    intercept: builtin:research-guard
```

The following table lists each behavior slot and the built-in hooks that it accepts:

| Slot                      | Level     | Built-in hooks                                                                                           |
| ------------------------- | --------- | -------------------------------------------------------------------------------------------------------- |
| `instructions`            | Milestone | `builtin:research-instructions`, `builtin:planning-instructions`, `builtin:execution-instructions`       |
| `toolGuidance`            | Milestone | `builtin:research-tool-guidance`, `builtin:planning-tool-guidance`, `builtin:execution-tool-guidance`    |
| `completionCriteria.type` | Milestone | `builtin:research-complete`, `builtin:planning-complete`                                                 |
| `canAcceptCompletion`     | Milestone | `builtin:research-accept-completion`, `builtin:execution-accept-completion`                              |
| `transitionSummary`       | Milestone | `builtin:research-transition-summary`, `builtin:planning-transition-summary`                             |
| `recovery`                | Milestone | `builtin:research-recovery`, `builtin:planning-recovery`, `builtin:execution-recovery`                   |
| `intercept`               | Milestone | `builtin:research-guard`, `builtin:planning-guard`, `builtin:execution-guard`                            |
| `forceEndTurn`            | Milestone | `builtin:research-force-end-turn`, `builtin:planning-force-end-turn`, `builtin:execution-force-end-turn` |
| `classifyVariant`         | Playbook  | `builtin:classify-task-variant`                                                                          |
| `bootstrap`               | Playbook  | `builtin:repo-bootstrap-discovery`                                                                       |
| `candidateBlock`          | Playbook  | `builtin:best-candidate-block`                                                                           |

The loader rejects unknown hooks and hooks used in the wrong behavior slot while it loads the playbook.

### Load plugins

To add custom hooks to a YAML playbook, list JavaScript modules in its `plugins` field. Use paths relative to the playbook. Each path must resolve inside the playbook directory.

> **Warning**
>
> Plugins run with your user privileges when the playbook loads, and verification commands run with the same privileges. Load only playbooks that you trust.

The following YAML loads a custom hook module:

**`release-notes.yaml`**

```yaml title="release-notes.yaml"
plugins:
  - ./marathon-hooks.mjs
```

The module exports a recovery hook:

**`marathon-hooks.mjs`**

```javascript title="marathon-hooks.mjs"
export default function register({ registerWorkflowHook }) {
  registerWorkflowHook('acme:strict-recovery', {
    kind: 'recovery',
    fn: () => 'Stop narrating. Your next response must contain a tool call.',
  })
}
```

Register hooks under a namespace that you choose, such as `acme:`. Reference the hook from a behavior slot, such as `recovery: acme:strict-recovery`.

### Write a TypeScript playbook

Create a playbook as a TypeScript module with a `.ts` or `.mts` extension. The CLI loads it at runtime without a build step. TypeScript playbooks accept plain functions in every behavior slot, so you can define custom logic without a plugin or hook registration.

The following TypeScript module defines a playbook:

**`.runtype/marathons/playbooks/my-task.ts`**

```typescript title=".runtype/marathons/playbooks/my-task.ts"
import { definePlaybook, type RunTaskStateSlice } from '@runtypelabs/sdk'

export default definePlaybook({
  name: 'my-task',
  stallPolicy: { nudgeAfter: 1, stopAfter: 4 },
  milestones: [
    {
      name: 'build',
      instructions: (state: RunTaskStateSlice) => `Build it. Plan: ${state.planPath}`,
      recovery: (state) =>
        `You went ${state.consecutiveEmptySessions ?? 0} sessions without a tool call. Write a file now.`,
      canAcceptCompletion: true,
    },
  ],
})
```

The `definePlaybook` helper comes from `@runtypelabs/sdk`. Install the package as a devDependency to get editor types. You can also export a plain object with the same shape without installing the package. To register named hooks, export a factory that receives `{ registerWorkflowHook }`.

## Next steps

Continue with these guides:

* [What are Agents?](/user-guide/agents/what-are-agents): understand the Agent that you pass to `runtype marathon`.
* [Creating and configuring Agents](/user-guide/agents/creating-and-configuring-agents): build and configure an Agent, including its fallback models.
* [Agent tools](/user-guide/agents/agent-tools): configure tools for the Agent.
* [Manage agents as code](/user-guide/agents/manage-agents-as-code): version-control Agent definitions.
* [Timeouts and long-running work](/user-guide/flows/timeouts-and-long-running-work): compare Marathon with other ways to run long work.
* [Runtype CLI reference](/developer-guides/getting-started/cli-reference): install the `runtype` CLI and look up each command group.