
# Run steps locally

`fob-worker steps run` runs one of your steps on your machine, the way the worker would run it for the Orchestrator, without the Orchestrator. Run it from the root of your worker repo.

```bash
fob-worker steps list                      # what's under src/steps/
fob-worker steps run IN1_01_check          # asks which config to use
```

## Choosing a config

| Flag | Config used |
| --- | --- |
| `--station IN1` | The step's config in that station's file in `.orchestrator/stations/` |
| `--scenario <name>` | A saved test config (below) |
| `--empty` | `{}`, so `inputSchema` defaults apply |
| none | A menu of every station that uses the step, every scenario for it, and "No config" |

With `--station`, the station file must be in your repo; run `fob-orc stations pull IN1` first if it isn't.

## Scenarios

A scenario is a JSON file with a config for one step, kept for repeat runs: a typical case, an edge case, yesterday's bug.

```text
.orchestrator/scenarios/<step slug>/<name>.json
```

```bash
mkdir -p .orchestrator/scenarios/IN1_01_check
echo '{ "approval_limit": 1000 }' > .orchestrator/scenarios/IN1_01_check/low-limit.json
fob-worker steps run IN1_01_check --scenario low-limit
```

Scenarios are only for fob-worker; fob-orc doesn't push them. Commit them with your code so everyone can use them.

## What a run does

1. Discovers the steps under `src/steps/`.
2. Loads the outputs of earlier runs from `temp/*.json` as `step_outputs`.
3. Resolves `{{<slug>.<field>}}` templates in the config against them.
4. Calls the step with a local work record (`local-wr-<timestamp>`) and prints the output.
5. Saves the output to `temp/<slug>.json`, overwriting the last one.

```text
Step: IN1_01_check
Config: scenario: two-invoices
Steps: src/steps/
Temp: temp

   No previous step outputs found in temp/

------------------------------------------------------------
Running step...
------------------------------------------------------------
[IN1_01_check] Raw config: {"invoices":[{"number":"INV-1001","amount":1250},{"number":"INV-1002","amount":7400}]}
[IN1_01_check] Resolved config: {"invoices":[{"number":"INV-1001","amount":1250},{"number":"INV-1002","amount":7400}]}

------------------------------------------------------------
Output:
------------------------------------------------------------
{
  "checked": 2,
  "above_limit": [
    "INV-1002"
  ]
}

   Output saved: temp/IN1_01_check.json
Step completed successfully
```

`attachReport()` and the other attach helpers write to `temp/work_records/local-wr-…/` and send nothing. Anything else your step does is real: if it calls an API or writes to a system, a local run does that too. Point `.env` at test accounts while you develop.

## Chaining steps

Because each run saves its output and the next run loads every saved output, you can run a station's steps one after another:

```bash
fob-worker steps run IN1_01_check --scenario two-invoices
fob-worker steps run IN1_02_report --scenario from-check
```

`IN1_02_report` sees `step_outputs.IN1_01_check`, and a config such as `{ "flagged": "{{IN1_01_check.above_limit}}" }` resolves to `["INV-1002"]`. To start clean, delete the `temp/*.json` files.

## When a step fails

fob-worker prints the error and exits with status 1:

```text
Error: [IN1_02_fail] Invalid input config:
  - threshold: Invalid input: expected number, received undefined
```

```text
Error: Bank API returned 503
```

- **Invalid input config**: the config doesn't match `inputSchema`. Check the `Raw config` and `Resolved config` lines; an unresolved template usually means the earlier step's output isn't in `temp/`.
- **Invalid output**: what `execute` returned doesn't match `outputSchema`.
- **Anything else**: thrown by your code. Run with `DEBUG=1` for the stack trace:

```bash
DEBUG=1 fob-worker steps run IN1_01_check --scenario two-invoices
```

More in [Troubleshooting](/docs/workers/troubleshooting).

## Steps that process workpieces

A step that works on bins reads and writes `temp/stations/` on your machine, just as on the worker. Inspect the result with `fob-worker lines status` and `fob-worker workpieces show`. See [Workpieces and bins](/docs/workers/workpieces#testing-a-line-locally).

## Limits

- The built-in `lib-worker:move_files` step can't be run with `steps run`. Move folders between bins yourself.
- Local runs have no item.
- The output is printed for reading; the saved `temp/<slug>.json` is the machine-readable copy.
