# Recipe: parallel cycle delivery

**The scenario:** a cycle decomposes into eight tasks. You want them running at once, not queued — and you want to know, before you start, what happens when two of them edit the same file.

The short answer: they cannot corrupt each other, and a genuine collision fails exactly one task. This recipe explains why, and what to do about the failure.

## Prerequisites

- An imported project with at least one cycle
- Model access configured for the workspace — see [Connect your agents](/guides/connect-agents/)

## Why parallel is safe here

Three properties, and they are structural rather than best-effort:

| Property | What it means |
| --- | --- |
| **A worktree per task** | Every task gets its own git working tree off the project's shared clone. Two tasks never share a checkout. |
| **One sandbox per project** | All of those worktrees live inside the project's single [Coding Workspace](/concepts/coding-workspace/) — no per-task cold boot, no per-task clone. |
| **Per-task outcomes** | The wave collects results independently. One task failing does not cancel its siblings. |

Merging is where parallelism actually meets: task branches merge into the default branch under a **per-repository lock**, so merges serialise even though the work did not.
**A conflict is a signal, not a fault:** When two tasks' edits genuinely collide, the merge conflict fails **that task only** and is never swallowed. That is deliberate: it means two pieces of planned work overlapped, which is information about the plan. Re-dispatching the failed task against the now-merged base usually resolves it.

## The recipe

1. **Let the planner decompose.** Start the project run with an outcome, not a task list — the roadmap becomes cycles, and each cycle's planner produces the wave.

   ```bash
   curl -sS -X POST "$HLIX_BASE_URL/v1/api/projects/$PROJECT_ID/start" \
     -H "x-api-key: $HLIX_API_KEY" \
     -H "X-Organization-Id: $HLIX_WORKSPACE_ID" \
     -H 'content-type: application/json' \
     -d '{"brief":"Add tenant-scoped rate limiting across the public API, with tests and updated docs."}'
   ```

   Expected result: `{"started":true}` — the run was handed to the engine, not finished.

2. **Watch the wave, not one task.** Filter the task list by status to see the shape of the wave:

   ```bash
   hlix tasks list --status building
   ```

   ```text
   ID                                    STATUS    TITLE
   ------------------------------------  --------  ------------------------
   b4a1f0d2-3c77-4e1a-9a2b-1d5e6f7c8a90  building  Add rate-limit middleware
   c7d2e1a3-4b88-4f2b-8c3d-2e6f7a8b9c01  building  Cover limits with tests
   ```

3. **Follow one task when you care about it.**

   ```bash
   hlix tasks watch "$TASK_ID"
   ```

   The stream is bounded — roughly 20 minutes — and closing is the only terminal signal. A clean exit at a non-terminal status means reconnect, not finished.

4. **Review per task, not per cycle.** Each task carries its own evidence, and a cycle is approved by its tasks passing:

   ```bash
   hlix tasks review "$TASK_ID"
   ```

5. **Handle the one that failed to merge.** If a task ends `failed` with a merge conflict, its siblings are unaffected and already merged. Re-dispatch that task; its base is now the merged result, so the conflict that existed against the old base usually does not exist against the new one.

## Keeping waves clean

- **Brief for outcomes, not files.** "Add rate limiting to the public API" decomposes into non-overlapping work; "edit `server.ts` and `limits.ts`" invites two tasks into the same file.
- **Expect the reviewer role to touch broadly.** A QA or Security Engineer task often reads widely. That is fine — reads never collide.
- **Do not scale a wave to hide a slow harness.** Parallelism is bounded by your provider's rate limits; twelve tasks against a throttled key finish no sooner than four.
- **Watch the merge lock, not the CPU.** Merges serialise per repository. In a multi-repository project each repository's lock is independent, so two repositories merge concurrently.

## If the wave misbehaves

- **Tasks stay `queued` and never start.** The dispatch refused a harness. See [If a task will not start](/guides/connect-agents/#if-a-task-will-not-start) — a preference naming an unavailable coder fails loudly rather than substituting one.
- **One task `failed`, the rest are `done`.** Expected on a genuine conflict. Read that task's error, re-dispatch it.
- **Every task failed identically.** Not a collision — a shared cause, usually a missing provider key or a project secret that never made it into the environment. See [If a secret does not reach the workspace](/security/secrets/#if-a-secret-does-not-reach-the-workspace).
- **`hlix tasks watch` exits while work continues.** The stream is bounded. Reconnect; read the status field rather than the exit code.
- **The cycle will not execute at all.** See [If a cycle will not execute](/running/cycles/#if-a-cycle-will-not-execute).

## Next steps

[The Coding Workspace](/concepts/coding-workspace/)
  [Cycles](/running/cycles/)
  [Agents & orchestration](/concepts/agents/)
  [Onboard a client repository](/guides/recipes/onboard-a-client-repo/)