> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.islo.dev/concepts/automations/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//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//job.toml --dry-run islo job deploy --path jobs//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 --param KEY=VALUE --watch ``` Then run the line: ```bash islo factory line run --param KEY=VALUE islo factory line-run status islo factory line-run events ``` 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 islo factory line-run events islo factory line-run stop --reason "" islo factory line-run retry islo factory line-run steer --param KEY=VALUE islo factory line-run follow-up --stage-name --reason "" islo factory line-run ask --message "" islo factory line-run agent-turn --stage-name --message "" ``` | Symptom | Do this | | -------------------------------------------------- | ------------------------------------------------------------------------------------ | | Trigger fired but no run appeared | Use `islo factory line runs ` and `islo factory triggers list --with-status` | | Stage failed | `islo factory line-run events `, then `islo job event ` | | 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//job.toml ``` ```bash islo job init islo schema job --short islo job deploy --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 `) 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 islo job deploy --path jobs//job.toml --dry-run islo job deploy --path jobs//job.toml islo job run --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`. > factory lines orchestrate multi-stage work. Jobs run in sandboxes. Triggers, schedules, and run control live on the line.