
# Get started

This walks you from an empty folder to a step that runs on your machine with fob-worker, then on the Orchestrator through your own worker. The example step checks invoices against an approval limit.

You'll need:

- **Node.js 18 or later** and **git**.
- **An Orchestrator account** for parts 5 and 6: [sign up](https://console.finopsbricks.com/signup), then open the [Orchestrator](https://orchestrator.finopsbricks.com/orgs) and create an organisation. Parts 1 to 4 work without one.

## 1. Install the CLIs

```bash
npm install -g @finopsbricks/fob-worker @finopsbricks/fob-orc
```

See [Install fob-worker](/docs/workers/install) for details and shell completion.

## 2. Create a worker repo from the template

```bash
git clone https://github.com/finopsbricks/worker-template.git worker-acme
cd worker-acme
rm -rf .git && git init
```

The template has placeholders. Replace them with your organisation's short name (here `acme`); on macOS:

```bash
grep -rl '{{' . --include='*.js' --include='*.json' --include='*.md' | xargs sed -i '' \
  -e 's/{{ORG_NAME}}/acme/g' -e 's/{{LOCATION}}/acme/g' \
  -e 's/{{WORKER_NAME}}/worker-acme/g' -e 's/{{WORKER_DESCRIPTION}}/Worker for acme/g'
```

On Linux, use `sed -i` instead of `sed -i ''`. Then install:

```bash
cp .env.example .env
npm install
```

`npm install` fetches [lib-worker](https://github.com/finopsbricks/lib-worker) from GitHub. You fill in `.env` in part 5.

## 3. Write a step

A step is a file under `src/steps/` that exports `defineStep()`. Create this file:

```text
src/steps/IN1__check_invoices/IN1_01_check.js
```

```js
import { defineStep } from '@fob/lib-worker';
import { z } from 'zod';

export default defineStep({
  slug: 'IN1_01_check',
  name: 'Check invoices',
  description: 'Flags invoices above the approval limit',
  inputSchema: z.object({
    approval_limit: z.number().default(5000),
    invoices: z.array(z.object({ number: z.string(), amount: z.number() })).default([]),
  }),
  outputSchema: z.object({ checked: z.number(), above_limit: z.array(z.string()) }),
  execute: async (config) => {
    const above_limit = config.invoices
      .filter((invoice) => invoice.amount > config.approval_limit)
      .map((invoice) => invoice.number);
    return { checked: config.invoices.length, above_limit };
  },
});
```

`name` and `description` are required. The folder name `IN1__check_invoices` is a convention (station short code, then a name); the slug is what identifies the step. See [Write steps](/docs/workers/write-steps).

## 4. Run it on your machine

```bash
fob-worker steps list
```

```text
SLUG          FOLDER               FILE
-------------------------------------------------------------
IN1_01_check  IN1__check_invoices  IN1_01_check.js

Total: 1 steps
```

Save a test config as a **scenario**, in this file:

```text
.orchestrator/scenarios/IN1_01_check/two-invoices.json
```

```json
{
  "invoices": [
    { "number": "INV-1001", "amount": 1250 },
    { "number": "INV-1002", "amount": 7400 }
  ]
}
```

And run the step with it:

```bash
fob-worker steps run IN1_01_check --scenario two-invoices
```

```text
Step: IN1_01_check
Config: scenario: two-invoices
…
Output:
------------------------------------------------------------
{
  "checked": 2,
  "above_limit": [
    "INV-1002"
  ]
}

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

Edit the step, run it again. That's the loop fob-worker is for. [Run steps locally](/docs/workers/run-steps) covers configs, chaining steps and debugging.

## 5. Connect to the Orchestrator

In your organisation in the Orchestrator, open **Settings → API Keys** and create a key for this worker. Copy the secret; it's shown once.

Fill in `.env`:

```bash
ORCHESTRATOR_URL=https://orchestrator.finopsbricks.com
ORCHESTRATOR_API_KEY=fob_orc_…
ORCHESTRATOR_API_SECRET=…
WORKER_LOCATION=acme
```

`WORKER_LOCATION` names where this worker runs. The Orchestrator sends a line's steps to the worker whose location matches the line's.

Give fob-orc the same key, as a profile:

```bash
fob-orc config profiles add acme --api-url https://orchestrator.finopsbricks.com \
  --api-key fob_orc_… --api-secret …
fob-orc status
```

`.env` is in the template's `.gitignore`. Don't commit it.

## 6. Run the station on the Orchestrator

Describe the line and station as files. `.orchestrator/lines/IN.json`:

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

And the station, in this file:

```text
.orchestrator/stations/IN1__check_invoices.json
```

```json
{
  "short_code": "IN1",
  "line": "IN",
  "name": "check_invoices",
  "is_enabled": true,
  "steps": [
    {
      "slug": "IN1_01_check",
      "config": { "approval_limit": 5000, "invoices": [{ "number": "INV-1001", "amount": 1250 }] }
    }
  ]
}
```

Push both, start the worker, and trigger a run:

```bash
fob-orc lines push --all
fob-orc stations push --all
fob-worker procs start          # or: npm start, in another terminal
fob-orc stations run IN1
```

The worker picks up the step within a couple of seconds. Check the result with `fob-orc work-records list` or in the Orchestrator. `fob-worker procs logs` shows the worker's output; `fob-worker procs stop` stops it.

`procs` needs pm2 (`npm install -g pm2`). See [Run your worker in the background](/docs/workers/processes).

## Next

- [Concepts](/docs/workers/concepts): lines, stations, steps, workpieces and bins.
- [Workpieces and bins](/docs/workers/workpieces): pass files from one station to the next.
- [Use with AI agents](/docs/workers/ai-agents): let a coding agent write and debug steps with fob-worker.
