> ## Documentation Index
> Fetch the complete documentation index at: https://www.plungeai.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflows

> A workflow is a file of tasks that oceancode runs in a fixed order: which agent does what, which tasks run at once, where a check or your approval stops the run. No model picks the next step. Five ship with oceancode — Spec, Build, Review, Secure and Research — beside Goal and Race, and you can …


A workflow is a file of tasks that oceancode runs in a fixed order: which agent does what, which tasks run at once,
where a check or your approval stops the run. No model picks the next step. Five ship with oceancode — **Spec**,
**Build**, **Review**, **Secure** and **Research** — beside Goal and Race, and you can write your own or have the
agent write one.

## A workflow and a mode

A work mode decides how agents work together on your prompt ([23](/oceancode/work-modes)). There are two kinds:

- A **way of working** (`kind: mode`: Model, Auto, Solo, Delegate, Pair, Orchestrate) shapes the lead's ordinary
  turn: which sub-agents it may call, whether it edits, which limits apply. You talk to the lead as usual.
- A **workflow** (`kind: workflow`) takes the turn's place. **Every prompt you send is one run**: the prompt becomes
  the run's input (`{input}`), the turn answers at once (`spec ×3 — started run <id>`), the tasks run in the
  background, and the result comes back into the session when the run ends
  (`crates/ocean-session/src/run/workflow/goal.rs:57`).

Under a workflow a follow-up question, or `/workflow new`, starts a run too. To talk to the agent again, switch back:
`F4` → Model, or `/mode default`.

## Picking one

`F4` or `/mode` opens the picker (*How should the agents work?*). The list has three parts: the six ways of working;
after a `── workflows ──` divider the built-in workflows Spec, Build, Review, Secure, Research, Goal and Race; after
`── custom ──` your own files, modes and workflows alike, by name. The highlighted entry's picture and cost are on the
right and its description under the list.

| Key | What it does |
|---|---|
| `Enter` | Run this workflow for this session's prompts. |
| `d` | Make it the current agent's default (`agents.<id>.mode` in your user `oceancode.json`). |
| `e` | Copy a built-in to edit: a workflow to `.oceancode/workflows/<id>-copy.yaml`, a mode to `.oceancode/modes/<id>-copy.yaml`, renamed `<id>-copy` and labelled `<Label> (copy)`. |
| `n` | Close the picker and put `/workflow new ` in the prompt, before anything you had typed (see [Writing your own](#writing-your-own)). |
| `Esc` | Close without a change. |

Typed forms: `/mode spec` sets this session's workflow and `/mode default` clears it. `"mode": "spec"` in
`oceancode.json`, or `agents.<id>.mode`, makes one the default ([02](/oceancode/configuration)).

## The five

### Spec — research, then a spec you approve

```
        you: task
 ┌────────▼────────┐
 │ Brief · general │
 └────────┬────────┘
   ┌──────┼──────┐
 ┌─▼──┐ ┌─▼──┐ ┌─▼───┐
 │code│ │docs│ │prior│  explore ×3
 └─┬──┘ └─┬──┘ └─┬───┘
   └──────◇──────┘ validate · review ↺ ≤ 2
 ┌────────▼────────┐
 │ Spec ✎ · general│ → .oceancode/plans/
 └────────┬────────┘ ◇ you approve
```

1. **brief** (`general`) restates the task: the goal in one sentence, what is in and out of scope, the questions a
   spec must answer. No code.
2. **research**: three `explore` agents at once, evidence as `path:line` only — **code** (where it is handled, what
   it calls, which tests cover it), **docs** (the rules that apply: `CLAUDE.md`, `AGENTS.md`, `docs/`), **prior**
   (a feature shaped like this one, its tests, its guide page).
3. **validate** (`review`, a verdict) opens every `path:line` and passes only when each says what the scout claims.
   On a failure the three scouts correct their evidence against the findings and validate checks again; two passes at
   most.
4. **spec** (`general`) writes the spec in the plan-file shape — Goal · Research findings · Approach · one fenced
   `todo` block, one buildable step per row · Verification per to-do · Open questions — and saves it as
   `.oceancode/plans/<date>-spec-<run>.md`.
5. **approve**: a question card shows the spec. **Approve** goes on; **Stop** ends the run `blocked · not approved`,
   and the file stays.
6. **report** (`general`): three lines — where the spec is, how many to-dos, and that Build with that path builds it.

Cost ≈ 3–5×. Needs an interactive session. Limits: 4 at once, 20 per turn, depth 1.

### Build — to-dos from the spec, build, tests, review

```
        you: spec path
 ┌─────────▼─────────┐
 │ To-dos · general  │ → the builder's list
 └─────────┬─────────┘
 ┌─────────▼─────────┐
 │ Build ✎ · builder │◀──┐◀──┐
 └─────────┬─────────┘   │   │
           ◇ tests ──fail┘   │ ↺ ≤ 3
 ┌─────────▼─────────┐       │
 │ Review · review   │──fix──┘ ↺ ≤ 2
 └─────────┬─────────┘
           ▼ report · general ──▶ you
```

1. **plan** (`general`) reads the spec your prompt names, else the newest file in `.oceancode/plans/`, and replies
   with its path and its `todo` block (adding a verification line to any row without one). It edits nothing.
2. **build** (`builder`) gets those rows as its to-do list and carries them out in order, running every check the
   spec names. While rows are open it is resumed, three times at most; a row still open fails the run.
3. **tests**, three passes at most: your `test_command` runs, and on a failure `builder` fixes the cause, never the
   test. After the third pass the run goes on with the last result, which review and the report read.
4. **review**, two passes at most: `review` tries to refute the change against the spec — did every row land, is
   anything outside the spec, can every new test fail? — and `builder` fixes those findings, nothing else.
5. **report** (`general`): the files changed, the commands with their pass lines, what is open.

Cost ≈ 2–5×. Needs `test_command` in `oceancode.json`; runs headless. Limits: 4 at once, 30 per turn, depth 2 (the
builder may call a helper such as `explore`).

### Review — three lenses, a judge, a verdict

```
          you: the change
      ┌──────────┼──────────┐
┌─────▼─────┐┌───▼────┐┌────▼────┐
│correctness││ scope  ││  tests  │ review ×3
└─────┬─────┘└───┬────┘└────┬────┘
      └──────────┼──────────┘
             ┌───▼───┐
             │ judge │ merges, evidence only
             └───┬───┘
                 ▼ verdict ──▶ you
```

1. **lenses**: three `review` agents at once, each answering a verdict — **correctness** (it reads the diff, staged
   and unstaged, and the code it touches: the wrong assumption, the missing case, the error path), **scope** (does
   the change do what was asked and only that?), **tests** (can each test fail, does one cover each new branch, is
   any check only claimed?).
2. **verdict** (`judge`): approve, request changes or block in one line, then the findings as `path:line`, worst
   first, without duplicates or anything uncited.

Your prompt names the change and what was asked. Nothing edits. Cost ≈ 3–4×. Runs headless. Limits: 3 at once, 10
per turn, depth 1.

### Secure — threat model, four lenses, a verdict

```
        you: change
 ┌────────▼────────┐
 │ Surface·explore │ inputs, secrets, sinks
 └────────┬────────┘ review ×4 with
   ┌──────┼───────┬──────┐ security-audit
┌──▼───┐┌─▼────┐┌─▼───┐┌─▼────┐
│secret││inject││authz││supply│
└──┬───┘└─┬────┘└─┬───┘└─┬────┘
   └──────┼───────┴──────┘
      ┌───▼───┐
      │ judge │──▶ approve · changes · block
      └───────┘
```

1. **surface** (`explore`) maps the change's attack surface without judging it: every input from outside, secret or
   credential, auth or tenant check, shell, SQL or HTML sink and external call, as `path:line`.
2. **lenses**: four `review` agents at once, each given the `security-audit` skill and answering a verdict —
   **secrets** (keys in code, logs or responses, weak crypto, bad randomness), **injection** (shell, SQL, path
   traversal, templates, unsafe deserialization, XSS: each input traced to its sink), **authz** (authentication,
   authorization and tenant boundaries), **supply** (a new dependency, a changed lockfile, a download or install
   step, an external call the change does not explain).
3. **verdict** (`judge`): approve, request changes or block, then each finding as `path:line` with its exploit path,
   keeping only findings a lens cited with more than 80 % confidence.

Nothing edits. Cost ≈ 4–6×. Runs headless; the lenses want the `security-audit` skill ([Requirements](#requirements)).
Limits: 4 at once, 10 per turn, depth 1.

### Research — a sweep, verified claims, a cited report

```
       you: question
 ┌────────▼────────┐
 │ Plan ≤ 4 asks   │
 └────────┬────────┘
   ┌──────┼──────┐
 ┌─▼──┐ ┌─▼──┐ ┌─▼──┐ researchers, read-only
 │ q1 │ │ q2 │ │ q3 │ claims with sources
 └─┬──┘ └─┬──┘ └─┬──┘
   └──────◇──────┘ verifiers re-check
 ┌────────▼────────┐ every claim
 │ Report · cited  │──▶ you
 └─────────────────┘
```

Research has no tasks of its own: it runs the built-in script `deep-research` (`workflow: deep-research`), which
splits your question into independent ones (four by default), sends one read-only researcher per question for claims
with their sources, has every claim re-checked against its source, and writes a report that cites only what
survived. Its runs are listed as `deep-research`.

Cost ≈ 4–8×. Runs headless. It sets no limits: the workflow bounds apply (`workflows.max_concurrent_agents`,
`workflows.agent_budget`, [02](/oceancode/configuration)).

### Goal, Race and Pipeline

Goal (loop until proven done) and Race (attempts, a judge ranks, you pick) are the two older workflows; they are
described in [23](/oceancode/work-modes#the-modes). Pipeline (spec, your approval, build, review) left the picker: Spec and
Build do its two halves with more checks. It is still built in, and `"mode": "pipeline"` in `oceancode.json` still
runs it; `/mode pipeline` is refused, as `/mode` takes only the picker's ids.

## While it runs

- **The badge.** The prompt's top border names the workflow and how many agents its first parallel task runs —
  `spec ×3`, `build`, `review ×3`, `secure ×4`, `research` — and, while a run is active, the task it is on:
  `spec ×3 · validate` (`crates/ocean-protocol/src/diagram.rs:841`).
- **The transcript row.** `Workflow spec: <your prompt>  [brief ✓ · research ● …]` follows the tasks as they start
  (`✓` done, `●` running) and ends as `Workflow spec done in 2m: …`, `failed`, `cancelled` or `paused`.
- **The dock.** Its Workflows section (`Workflows 1`) lists each running run with its agents beneath it; open an
  agent's row to watch it ([19](/oceancode/pager#watching-a-sub-agent)).
- **Workflow Runs.** `/workflow runs` opens the runs pane (a text overview in minimal mode); `/workflow pause`,
  `resume` and `stop` control a run, and a paused or stopped run keeps its journal, so it can be resumed.
- **Question cards.** An `approve` task puts a card in the prompt's place: *Approve?*, the result it shows (Spec's
  spec), and the options Approve and Stop. A `pick` task (Race) lists the attempts in the judge's order with its
  reasons, and None. `1`–`9` choose ([19](/oceancode/pager#question-cards)).
- **The hand-back.** When the run ends, its status and its last task's output land in the session as a `<workflow>`
  message, and the agent is woken to read it, so the session's next answer is the run's result. A workflow that
  cannot run here answers your prompt at once with the reason and starts nothing.

## Requirements

| Workflow | Needs | Headless |
|---|---|---|
| Spec | an interactive session, for the approve card | no |
| Build | `test_command` in `oceancode.json`, for the tests | yes |
| Review | nothing more | yes |
| Secure | nothing more; the `security-audit` skill, see below | yes |
| Research | nothing more | yes |
| Goal | nothing more | yes |
| Race | a git project, `test_command`, an interactive session for the pick | no |

Every workflow needs workflows on (`workflows.enabled`, the default). An interactive session is one that can show you
a question card (the pager, an editor); a headless one (`oceancode run`, a client without cards) cannot. A workflow
whose need is unmet answers the prompt with the reason — `spec needs an interactive session`, `build needs a
test_command in oceancode.json` — and Auto never picks it (`crates/ocean-session/src/run/mode.rs:123`).

**Secure's skill.** Each of Secure's four lenses names the skill `security-audit`. oceancode ships no skill bodies:
it finds this one where it finds every skill ([09](/oceancode/capabilities)) — the project's `.oceancode/skills/` or
`.claude/skills/` (this repository ships `security-audit` in its root `.claude/skills/`), or your
`~/.oceancode/skills/` or `~/.claude/skills/` (`crates/ocean-capabilities/src/discover.rs:74`). Its `SKILL.md` body
goes in front of each lens's prompt. Without it each lens gets one line instead —
`(Skill "security-audit" was not found; go on without it.)` — and runs on its prompt alone
(`crates/ocean-session/src/run/workflow/host.rs:626`).

## Auto and workflows

Under Auto, Jev picks a mode for each prompt from those that can run here, the workflows among them; each option
shows its summary and its `when_to_use` (Spec: "a task needs a spec before anything is built"). When Jev cannot
answer, the rules pick, and five rules on the prompt's first word come before the four of [Auto](/oceancode/work-modes#auto)
(`crates/ocean-protocol/src/auto_route.rs:31`):

1. `spec`, `specify`, `design` → Spec;
2. `build`, `implement`, when the prompt also names `.oceancode/plans/` or the word `spec` → Build;
3. `review` → Review;
4. `secure`, `security`, `audit` → Secure;
5. `research`, `compare`, `investigate` → Research.

The first word counts whole and in any case. A rule whose workflow cannot run here is passed over, so a headless
`design the cache` falls through to the other rules. The badge says who decided: `auto → review · rules: asks for a
review`. Auto decides per prompt, so only the prompts it gives a workflow start a run.

## Writing your own

A workflow is one YAML file, `.yaml` or `.yml`:

- `.oceancode/workflows/<name>.yaml` in the project: every session and everyone who works in the repository gets it.
- `~/.config/oceancode/workflows/<name>.yaml` (the user config directory): yours, in every project.

A way of working (`kind: mode`) goes in a `modes/` folder beside it instead, which also still reads JSONC (`*.jsonc`,
`*.json`, with `flow` written out and no `kind`). The folders are watched: a saved file is listed under
`── custom ──` at once. A file is skipped, with the reason in the engine log, when its name is taken (a built-in; a
workflow script's name: a `.rhai` beside it with the same stem, any `.rhai` whose `meta.name` it is, or the built-in
scripts `deep-research`, `goal`, `pipeline` and `diagram`), when it is the other kind for its folder, or when an
earlier file holds its name (the project's wins). A
file that does not parse or validate is left out, and the `workflow` tool's unknown-diagram error names it with the
reason (`crates/ocean-app/src/modes.rs:36`).

### Three ways to start

- **Copy one.** `e` on a built-in in the picker writes `.oceancode/workflows/<id>-copy.yaml`.
- **Ask for one.** `/workflow new <what it should do>` (or `n` in the picker) asks the agent to write it. It follows
  the `workflow-author` skill, which this repository ships in its root `.oceancode/skills/workflow-author/`; in
  another project, copy the skill into that project's `.oceancode/skills/` or your `~/.oceancode/skills/`. The agent
  writes the YAML, checks it with the `workflow` tool (`source: {type: "yaml", yaml}` with `validate_only: true`),
  fixes what the check names (three rounds at most), then saves it with `save: {scope: "project"}` or `"user"`.
- **Write it.** `oceancode workflow schema` prints the JSON Schema of a workflow or mode file.

The check reads the file as the catalog does, validates it against the agents this session knows, checks what the
session can run, then runs it once on a stand-in host: every question takes its first option, every command exits 0,
every verdict passes (`crates/ocean-session/src/run/workflow/launcher_yaml.rs:73`). A save does the same, asks you
once for the file, and writes it. It is refused when the file exists and `replace: true` is not set, when the name is
taken (a built-in, a workflow script, a pager `/workflow` op — `new`, `runs`, `pause`, `resume`, `stop`, `save` — or a
file listed from elsewhere), outside the two workflow folders, and when a line looks like it holds a key (`sk-`,
`AKIA` or `Bearer ` followed by 16 or more key characters, or `-----BEGIN`;
`crates/ocean-session/src/run/workflow/launcher_yaml.rs:104`). A workflow is shared text: it never holds a key, and a
command takes its secrets from the environment it runs in.

To run a saved workflow: `/mode <name>` and a prompt, or the `workflow` tool with
`source: {type: "name", name: "diagram"}, args: {diagram: "<name>", task: "<the input>"}`.

### The file

```yaml
kind: workflow                 # workflow (tasks, or a script) or mode (the lead's turn)
name: lint-review              # the id: the file's stem, /mode lint-review, the badge
label: Lint review             # the picker's title
description: lint, three lenses, a verdict
when_to_use: a change exists and the linter must pass first
agents: { review: {}, judge: { model: openai/gpt-5 } }
tasks: []                      # the tasks, in order (next section)
limits: { at_once: 3, per_turn: 10, depth: 1 }
picture: []                    # lines drawn in the picker
cost: "≈ 3–4×"
```

| Key | What it holds |
|---|---|
| `kind` | Required in YAML: `workflow` or `mode`. It must agree with `flow`. |
| `name` | Required: `^[a-z][a-z0-9-]*$`, the key for `/mode`, the config's `mode`, the badge and the file's stem. |
| `label` | Required: the picker's title. |
| `description` | The picker's line and the text under the list. `summary`, when set, is a shorter line beside the label; one of the two is required. |
| `when_to_use` | One sentence; Jev reads it under Auto. |
| `flow` | Leave it out: `script` for a workflow, `lead` for a mode (`auto` is Auto's alone). |
| `agents` | Every agent a task names, each with options: `model` and `effort` (pins, see [Models](#models)), `isolate: copy` (the agent works in its own copy of the project: needs git, never inside a loop; every writing agent in a `parallel` needs it), `max` (at most this many at once), `keep` (a mode's lead resumes the same child). |
| `tasks` | The tasks, in order. |
| `workflow` | Instead of `tasks`: a workflow script's name (Research: `deep-research`). Never both. |
| `limits` | `at_once` 0–64, `per_turn` 1–1000, `depth` 1–4 (1: task agents start no sub-agents), `race_n` 1–8 (copies of a `parallel` that names neither `n` nor `models`). Your `subagent.max_*` settings win. |
| `picture` | Lines drawn in the picker; keep to 12 lines of 44 cells, as the built-ins do. Left out, the picker draws one line per task. |
| `cost` | Shown in the picker, against working alone. |
| `picker` | `false` hides it from the picker. |
| `lead_writes`, `lead_prompt` | A mode's only: `false` takes the lead's edit tools; text added to the lead's prompt. |

An agent is any agent oceancode knows; an unknown one's error lists them. `general` and `builder` write; `explore`,
`review` and `judge` are read-only; your own markdown agents count too. The shipped workflows use only these five.

### The four task types

```yaml
- type: task                   # one agent, one prompt
  id: build                    # its result's name; default: the agent's id
  agent: builder
  prompt: |
    Carry out the to-dos:
    {plan}
  schema: verdict              # verdict, ranking or deliverables: the reply is that JSON
  model: openai/gpt-5          # this task only
  condition: '!tests.pass'     # runs only when it holds; quote a leading !
  skills: [security-audit]     # SKILL.md bodies put before the prompt
  todo: { from: plan }         # the todo block of an earlier reply, or a list of rows
  save: spec                   # writes the reply to .oceancode/plans/<date>-spec-<run>.md
- type: parallel               # different tasks at once
  id: scouts                   # required
  schema: verdict              # for subtasks that name none
  subtasks:
    - { type: task, id: code, agent: explore, prompt: "Read the code. {input}" }
    - { type: task, id: docs, agent: explore, prompt: "Read the docs. {input}" }
- type: parallel               # copies: one agent, one prompt, n times
  id: checks
  agent: review
  prompt: "Refute the change. {input}"
  n: 3                         # 1–8; else one copy per model; else limits.race_n; else 3
  models: [openai/gpt-5, openai/gpt-5-mini]
- type: loop                   # repeats its tasks
  max: 3                       # passes, at least 1
  until: tests.pass            # ends it when this holds
  tasks:
    - { type: gate, gate: tests }
    - { type: task, id: fix, agent: builder, condition: '!tests.pass', prompt: "Fix the cause: {tests.output}" }
- type: gate                   # approve, pick, tests or check
  gate: check
  id: lint
  command: cargo clippy --all-targets -- -D warnings
  expect: Finished             # passes on exit 0 with this text in the output's last 4 KiB
```

- **task**: `agent` and `prompt` are required. `todo` needs an agent that writes; the agent is resumed while rows
  are open, three times at most, and a row still open fails the task. `save` runs once, so never on a subtask or
  inside a loop, and never replaces a file. `effort` is read on a task too, but only the agent's `effort` is applied.
- **parallel**: `id` is required. With `subtasks`, each a `type: task`, every result is saved under its own id and
  the set under the parallel's; it takes no `agent`, `prompt`, `n` or `models`, and every subtask id is unique in the
  file. Without, it runs copies of one `agent` with one `prompt`.
- **loop**: `max` and `tasks` are required; `until` is optional.
- **gate**: see [Gates](#gates). A gate and a parallel take `condition` too.

A failed task or subtask ends the run as failed; copies end it only when none succeeds. A failing gate does not stop
the run: follow it with a fix under `condition: '!<id>.pass'` inside a loop `until: <id>.pass`.

### Templating, conditions and schemas

- `{input}` is the prompt the run started with. `{id}` is a saved result as text: a plain reply as itself, a schema
  reply as JSON, a parallel as a JSON list. `{id.field}` is one field (`{review.findings}`, `{tests.output}`; on a
  parallel, each member's), and `{id.file}` the plan file a `save` wrote. A name nothing has saved stays as typed,
  braces and all.
- A condition reads `name.field` or `!name.field`, both words lowercase letters and `_` only — so a result a condition
  reads needs such an id (`fix_two`, not `fix2`). It holds when the field is `true`; on a parallel, when it is true for
  every member that answered in a schema; for a name nothing has saved, never, so `!review.pass` runs before any
  review. There is no `&&`, `==` or number. Quote it: a bare `!` starts a YAML tag, and a tag is refused.
- `schema: verdict` asks for `{pass, findings}`, `ranking` for `{order, reasons}` (attempt numbers, best first: what
  a `pick` gate shows), `deliverables` for `{deliverables}`. The reply is held to its schema, asked again a bounded
  number of times.

### Gates

Gates are local: the cloud engine never waits for a person.

| `gate` | Keys | Result | Needs |
|---|---|---|---|
| `approve` | `show`: a saved result shown with the question (else the input) | Stop ends the run `blocked · not approved` | an interactive session |
| `pick` | `from`: an earlier parallel's id; `show`: a `ranking` result | applies the chosen copy and ends the run | an interactive session; copies (`isolate: copy`) |
| `tests` | `command` (else the config's `test_command`); `each`: run in every copy of a parallel | `{pass, exit, output}` under its `id`, else `tests` | `test_command` when it names no `command` |
| `check` | `command` (required), `expect` | `{pass, exit, output}` under its `id`, else `check` | nothing |

With `each` the result stays on each copy, so that gate takes no `expect` and no `id`.

### Aliases

The work-mode files before 2026-11-02 used other words. They are still read, so every older file parses; write the
first column. A word and its alias together are refused.

| Write | Also read |
|---|---|
| `name` | `id` (top level) |
| `tasks` | `steps` |
| a task's `id` | `as` |
| `prompt` | `do` |
| `condition: x` (runs the task when x holds) | `unless: '!x'` (skips it when x holds) |
| `{input}` | `{task}` |
| `type: task`, `type: gate` | a task keyed by `agent`, a gate keyed by `gate` |
| `type: parallel` | `parallel: { … }` with `as` beside it |
| `type: loop` | `loop: { max, until, steps }` |

An error names where it is and what was meant, counting the top-level list as `tasks` even when the file wrote
`steps` (`crates/ocean-protocol/src/diagram_read.rs:21`):

```
mode draft: tasks[2].unles: unknown field, expected one of `type`, `id`, …; did you mean `unless`?
```

### From the cloud engine's words

A local file has the shape of a bare CNL document (`orchestration/cnl-engine/`). What the local engine lacks is the
registry, SharedMemory and CEL; what it adds is `loop` and `gate`.

| Cloud (CNL) | This file |
|---|---|
| the `workflow:` envelope with `name`, `description`, `tasks` | top-level `kind: workflow`, `name`, `label`, `description`, `tasks` |
| `type: agent`, `type: harness` (`goal`, `mission`) | `type: task` with `agent` and `prompt` |
| a task's `id` | `id` |
| `parallel` with `subtasks` | `type: parallel` with `subtasks` |
| `validate` | a verdict task or parallel in a `loop` with `until: <id>.pass` |
| `condition` (CEL) | `condition: "name.field"` or `"!name.field"` |
| `retry` | `type: loop` with `max` |
| `{input}`, `{task_id}` | `{input}`, `{id}`, `{id.field}` |
| a harness's `skills` | `skills` |
| `allowed_tools`, `posture: read_only` | the agent: `explore`, `review` and `judge` are read-only |
| `sequential` | the top-level `tasks`, which run in order |
| `batch`, `dynamic`, `debate`, `output`, `version`, `inputs`, `followup`, `timeout`, `budget` | none (budgets: the config's `workflows.*`) |

### Models

A cheap model for the scouts and a strong one for the builder or the judge:

- `agents.<id>.model` and `effort` pin an agent in every task;
- a task's `model` pins that task;
- `models: [a, b, c]` on a copies `parallel` runs one copy per model;
- the `workflow` tool's `args.models: {<agent id>: <model>}`, when it launches `diagram`, wins over an agent's pin.

A model is `provider/model`, as `/model` lists it. The session's `/subagent` model wins over every pin; with no pin,
a task runs the config's `agents.<id>.model`, else `subagent.model`, else the session's model. The picker tags each
agent with its pin.

## What is and is not enforced

The file is data the engine runs (`crates/ocean-session/src/run/workflow/builtins/diagram.rhai`), so these hold
whatever an agent says:

- **The order.** The tasks run as written; no model picks the next one, and a replayed run never decides again. A
  failed task ends the run.
- **The gates.** An approve gate waits for you, and Stop ends the run. A tests or check gate passes only on exit 0
  (and `expect` in the output). A pick applies only the copy you chose.
- **The answers.** A reply in a schema is checked against it, and a condition or `until` reads its fields; a loop
  ends at `max`.
- **The to-dos.** Rows are in the agent's list before it starts, it is resumed while they are open, and a row still
  open fails the task.
- **The saves.** One new file under `.oceancode/plans/`, never elsewhere, never over another.
- **The limits.** At once, per turn and depth bound the run's agents ([23](/oceancode/work-modes#limits)); `explore`,
  `review` and `judge` have no edit tools.
- **The rules of the file.** An unknown key or agent, a malformed condition, `todo` on a read-only agent, `save` in a
  loop or a subtask, a writer in a parallel without `isolate: copy`: each is refused before anything runs, and a
  workflow whose needs are unmet never starts.

These are judgement, which no file can hold:

- the quality of a spec, a review or a report;
- a builder's "done" beyond the tests and its to-do rows, which it closes itself;
- the honesty of `verdict.pass`: a model can pass what it should not, so a second lens or a `check` gate is the guard;
- what a skill's text does: `skills` adds text to the prompt, not rules;
- a `{name}` that names nothing: it stays in the prompt as typed, and validation does not catch it;
- which sub-agents a task's agent calls: a mode's allow-list shapes only the lead's own calls
  (`crates/ocean-session/src/run/orchestration.rs:679`), which is why Spec, Review and Secure set `limits.depth: 1`
  (Build: 2).

## See also

- [23 · Work modes](/oceancode/work-modes) — the ways of working, Goal and Race, limits, Auto.
- [02 · Configuration](/oceancode/configuration) — `mode`, `test_command`, `agents.<id>.mode`, `workflows.*`.
- [09 · Capabilities and plugins](/oceancode/capabilities) — where skills are found.
- [19 · Ocean pager](/oceancode/pager) and [22 · Ocean pager reference](/oceancode/pager-reference) — the picker, the badge,
  the dock and question cards.
- [21 · CLI reference](/oceancode/cli-reference) — `oceancode workflow`.
