
# Stations and lines

Stations and lines live in the Orchestrator. You keep a copy of each as a JSON file in your worker repo, edit it there, and sync it with **fob-orc**:

```text
.orchestrator/
  lines/IN.json                       one file per line
  stations/IN0__seed_invoices.json    one file per station
  stations/IN1__check_invoices.json
  scenarios/…                         test configs for fob-worker (not synced)
```

```bash
fob-orc lines pull --all          # Orchestrator → files
fob-orc stations pull --all
fob-orc lines push --all          # files → Orchestrator (push lines first)
fob-orc stations push --all
```

fob-worker reads these files to show your lines and to give `steps run` a station's config. Pull again whenever someone else may have changed them.

## Line files

```json
{ "code": "IN", "name": "Invoice intake", "location": "acme" }
```

`code` and `location` are required. `location` must match the `WORKER_LOCATION` of the worker that should run the line's stations.

## Station files

```json
{
  "short_code": "IN1",
  "line": "IN",
  "name": "check_invoices",
  "is_enabled": true,
  "dependencies": ["IN0"],
  "schedule_cron": "*/5 * * * *",
  "schedule_enabled": true,
  "steps": [
    { "slug": "lib-worker:move_files", "config": { "source_bin": "IN0/output", "target_bin": "IN1/input" } },
    { "slug": "IN1_01_check", "config": { "approval_limit": 5000 } }
  ]
}
```

| Field | |
| --- | --- |
| `short_code` | The station's code, such as `IN1`. fob-worker and fob-orc accept it wherever they take a station |
| `line` | The line's `code` |
| `name` | A name, also used in the file name |
| `steps` | The steps to run, in order, each with its `config` |
| `dependencies` | Stations this one comes after. fob-worker uses them to order a line's stations |
| `schedule_cron`, `schedule_enabled` | Run on a cron schedule |
| `is_enabled` | Whether the station can run at all |

After a pull, files also carry the station's Orchestrator `id`; keep it, so a push updates the station instead of creating a new one.

## The move_files conveyor

The first step of every station after the line head moves workpieces in from the station before it:

```json
{ "slug": "lib-worker:move_files", "config": { "source_bin": "IN0/output", "target_bin": "IN1/input" } }
```

| Config | |
| --- | --- |
| `source_bin`, `target_bin` | `STATION/bin`, or `STATION/bin/sub-folder` |
| `batch_size` | Most workpieces to move per run (default 100) |
| `moves` | Instead of the two above: a list of `{ source_bin, target_bin }` |
| `report` | `true` to attach the summary as the run's report |

It moves only workpiece folders (folders with a `pointer.json`), in name order. If a workpiece with the same name is already in the target bin, the two are merged. Register it in your worker's `src/index.js`, as the template does.

`fob-worker lines show IN` lists each station's conveyor, so you can check the wiring:

```text
--- Conveyors ---

AT STATION  FROM BIN    TO BIN     MODE
---------------------------------------
IN1         IN0/output  IN1/input  —
```

## Running a station

- **On a schedule:** set `schedule_cron` and `schedule_enabled`.
- **On demand:** `fob-orc stations run IN1`, or from the Orchestrator.

Either way, your worker must be running at the line's location for the steps to run. See [Run your worker in the background](/docs/workers/processes).

## Updating step names

`fob-worker stations update-step-metadata` copies each step's `name` and `description` from your code into the local station files that have an Orchestrator `id` (files you've pulled, or pushed and pulled back). Push afterwards to update the Orchestrator.
