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

# Automations

> factory lines orchestrate multi-stage work. Jobs run in sandboxes. Triggers, schedules, and run control live on the line.

A factory line is Islo's automation product: multi-stage work with typed routing, loops, schedules, and event triggers. A line (`line.toml`) orchestrates stages; each stage runs a job (`job.toml`); jobs execute in sandboxes. Agents do the judgment work.

Do not author manifests from memory. Scaffold jobs with `islo job init`, then confirm every field against the installed CLI:

```bash
islo schema factory --short
islo schema job --short
```

Unknown keys 422. Treat every TOML snippet here as a pattern, not a drop-in. Copy a nearby example from [islo-labs/islo-agents](https://github.com/islo-labs/islo-agents) (`examples/`) and edit it against the live schema.

For AI agents, install [islo-labs/skills](https://github.com/islo-labs/skills). Use the **factory-lines** skill to build and debug lines; use the **platform** skill for sandboxes, snapshots, gateway profiles, incoming webhooks, environments, knowledge, and the SDK.

## Building blocks

| Building block   | Role                                                                                                                                                                                                            |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| factory line     | The workflow: trigger, stages, transitions, limits.                                                                                                                                                             |
| Job              | One stage's unit of work: params, outputs, sandbox, `run_agent` / `exec` steps.                                                                                                                                 |
| Trigger          | What starts a line run: manual, schedule, line webhook, or a GitHub / Slack / Linear integration.                                                                                                               |
| Snapshot         | Prebuilt sandbox image. Put harness code (and bulky supporting briefs) here. Stage briefs belong in the job `run_agent` prompt so a prompt change is a new job version. Do not `git clone` briefs on every run. |
| Incoming webhook | Separate product: HTTP event → sandbox lifecycle or a **single** job. Not a substitute for a multi-stage line.                                                                                                  |

A standalone scheduled or manual job (no line) is the exception. Use it only when there is explicitly one stage and no routing.

## factory lines

Standard layout:

```text
line.toml
jobs/<stage>/job.toml
```

A line declares identity, what starts a run, the stages, and the routing between them. Harness, model, params, and outputs live on each stage's job — not on the line.

Required sections (confirm names and fields with `islo schema factory --short`):

| Section           | Purpose                                                                                    |
| ----------------- | ------------------------------------------------------------------------------------------ |
| `[line]`          | Name and optional description / category                                                   |
| `[trigger]`       | How runs start                                                                             |
| `[[stages]]`      | Each stage `id` plus the `job` it runs                                                     |
| `[[transitions]]` | Conditional or agentic routing, including an entry from `trigger` and completion to `done` |

Reserved stage ids: `trigger`, `done`, `wait`.

### Triggers

| Trigger               | Use when                                                                                    |
| --------------------- | ------------------------------------------------------------------------------------------- |
| `manual`              | An operator or the API starts runs; also the right first trigger while a line is under test |
| `schedule`            | Recurring cron-based runs                                                                   |
| `webhook`             | An HTTP POST to a **line-owned** path starts runs                                           |
| `integration_trigger` | Provider-native GitHub, Slack, or Linear events start runs                                  |

Schedules live in the line `[trigger]` and nowhere else. A schedule created in the UI or on a job and then overwritten by the next line deploy is that mistake:

```toml
[trigger]
type = "schedule"
cron = "0 7 * * *"
timezone = "UTC"
```

Discover integration events and whether the tenant is connected:

```bash
islo factory triggers list --with-status
islo factory triggers get slack message.received
islo factory triggers get github pull_request.opened
```

`triggers get` returns payload shape, selector shape, and example filters. Connect the provider first (`islo login --tool slack`, GitHub, or Linear) if status shows disconnected.

Line webhook vs [incoming webhook](/concepts/incoming-webhooks/):

|          | Line `[trigger]` `webhook` | Incoming webhook                                    |
| -------- | -------------------------- | --------------------------------------------------- |
| Setup    | `line.toml`                | `islo webhook incoming create`                      |
| Target   | Starts a **line** run      | Sandbox lifecycle or a **single** job               |
| Use when | Multi-stage orchestration  | Ensure / resume / delete a sandbox, or fire one job |

### Deploy order

The line pins each stage's `job_version_id` at deploy time. Redeploying a job alone does not update an already-deployed line.

1. Knowledge items the line or jobs reference
2. Every stage job
3. The line **last**

```bash
islo job deploy --path jobs/<stage>/job.toml --dry-run
islo job deploy --path jobs/<stage>/job.toml
islo factory line validate line.toml
islo factory line deploy line.toml --dry-run
islo factory line deploy line.toml
```

Smoke-test the first agent stage as a job before the full line is live:

```bash
islo job run <first-stage> --param KEY=VALUE --watch
```

Then run the line:

```bash
islo factory line run <name> --param KEY=VALUE
islo factory line-run status <run-id>
islo factory line-run events <run-id>
```

For integration triggers, fire **one** real event after deploy (open a test PR, post in the selected channel) and confirm a run appears.

### Inspect and steer a run

```bash
islo factory line-run status <run-id>
islo factory line-run events <run-id>
islo factory line-run stop <run-id> --reason "<why>"
islo factory line-run retry <run-id>
islo factory line-run steer <run-id> <stage> --param KEY=VALUE
islo factory line-run follow-up <run-id> --stage-name <stage> --reason "<what>"
islo factory line-run ask <run-id> --message "<question>"
islo factory line-run agent-turn <run-id> --stage-name <stage> --message "<message>"
```

| Symptom                                            | Do this                                                                              |
| -------------------------------------------------- | ------------------------------------------------------------------------------------ |
| Trigger fired but no run appeared                  | Use `islo factory line runs <name>` and `islo factory triggers list --with-status`   |
| Stage failed                                       | `islo factory line-run events <run-id>`, then `islo job event <command-id>`          |
| Agent did the wrong thing mid-stage                | `agent-turn` for that stage; `ask` for the line manager                              |
| 422 / extra inputs                                 | Unknown key — diff against `islo schema factory --short` / `islo schema job --short` |
| Line runs a stale job after you redeployed the job | Redeploy the line                                                                    |
| Schedule vanished after deploy                     | Put cron on the line `[trigger]`                                                     |

`stop` parks a run so you can `steer`. `retry` reruns the latest failed stage. Steering an active run returns 409 — stop first.

## Jobs (stages)

A job is what one stage executes. Path:

```text
jobs/<name>/job.toml
```

```bash
islo job init <name>
islo schema job --short
islo job deploy <name> --dry-run
islo job deploy --path path/to/job.toml
```

`islo schema job` returns the machine-readable manifest under `job_toml`. Control-plane OpenAPI `JobManifest` is the API source of truth for deploy/validate bodies.

Write **params and outputs first** — they are the line's contract. Transitions bind job params from trigger outputs, literals, and prior stages' outputs.

Policy the schema will not say:

* Harness and model live on the `run_agent` step, never in `line.toml`.
* Do not replace `run_agent` with shell-wrapped `claude` / `cursor` / `codex` CLIs.
* Keep provider tokens out of manifests and sandbox env. Connect integrations (`islo login --tool <provider>`) and inject credentials with a gateway profile.
* Put the stage brief in the job's `run_agent` prompt so a prompt change is a new job version. If the repo already has skills, check it out with an idempotent `exec` step and point at that skill. Bake only supporting or fan-out briefs into the snapshot; do not clone prompts every run.
* Do not copy procedural runbooks into Knowledge.

Gateway profiles keep GitHub, Slack, and model credentials out of the sandbox environment by default.

## Standalone jobs

Only when you explicitly want a **single** durable unit of work with no line routing:

```bash
islo job init <name>
islo job deploy --path jobs/<name>/job.toml --dry-run
islo job deploy --path jobs/<name>/job.toml
islo job run <name> --param KEY=VALUE --watch
```

A `[schedule]` block in `job.toml` is valid for that standalone job. Every param a scheduled run needs must have a default. One active schedule per job; removing it takes effect on the next deploy. If the work grows a second stage, a decision point, or a loop, it is a line — move the schedule to the line `[trigger]`.

## Incoming webhooks

Incoming webhooks authenticate an external POST and run sandbox actions (`ensure_sandbox`, `resume_sandbox`, `trigger_job`, deliver to a port, pause, delete). They still need a sandbox **target** for ingress even when the only action is `trigger_job`.

Use them for PR preview sandboxes and one-shot job kicks. Use a factory line trigger for anything multi-stage. Auth, targets, rules, and actions: [Incoming Webhooks](/concepts/incoming-webhooks/).

## Agent guidance

1. Install [islo-labs/skills](https://github.com/islo-labs/skills) (`npx skills add islo-labs/skills`).
2. Follow the **factory-lines** skill end to end, including the design-approval gate before deploy.
3. Clone or browse [islo-labs/islo-agents](https://github.com/islo-labs/islo-agents) for examples — there is no in-skill copy of those templates.
4. Always run `islo schema factory --short` and `islo schema job --short` before editing manifests. For incoming webhook templates, run `islo schema webhook`.