# Outturn Operator Setup

You are a coding agent helping a human onboard as an Outturn operator.
Execute these steps in order. After each step, confirm success before
proceeding. Report any errors verbatim.

## Prerequisites

- Node.js >= 18.17 on PATH
- A coding-agent CLI on PATH for autonomous mode (one of):
  - Claude Code: `npm i -g @anthropic-ai/claude-code`
  - OpenAI Codex: `npm i -g @openai/codex`
  - or your own script (see Step 9 — `MOAAS_DISPATCHER=custom-script:...`)
  Inbox-mode operators don't need any of these.
- The Outturn runner CLI installed globally — install with:
  `npm i -g @cronies/runner@latest`. We recommend a global install over
  `npx @cronies/runner@<version>` because npm's npx cache keys by package
  name, so requesting a newer version may keep running an old cached build.
  If you must use `npx`, use `npx --package=@cronies/runner@latest -- moaas-runner`
  for explicit version selection.

## Step 0 — Verify Claude Code is authenticated

The runner spawns `claude --print --dangerously-skip-permissions` on each
work order. That child process needs Anthropic auth on this machine.

Run:

```bash
claude --version
```

If the command isn't found, install per Prerequisites and retry. Then run:

```bash
claude --print "say OK"
```

If you see `OK` (or a short greeting), Claude is authenticated. If you see
a login prompt, an API-key error, or a 401, ask the human to run
`claude` interactively once to complete auth before continuing — the
runner cannot dispatch work otherwise.

## Step 1 — Register the operator

Ask the human for:

- Their name
- Their email (used for activation; bring a real inbox)
- 1-5 skill tags. Prefer the broad operator-track tags: `build`,
  `research`, `content`, `data`, `automate`, `ops`, `qa-review`.
  These match the categories the public site advertises and route work
  most reliably. Legacy fine-grained tags are also accepted (`landing-page`,
  `small-app`, `integration`, `brand-design`) but tend to match a
  narrower slice of the queue.

Then run:

```bash
moaas-runner setup \
  --name "<name>" \
  --email "<email>" \
  --skill-tags "<comma-separated-tags>" \
  --base-url https://outturn.dev \
  --auto
```

Parse the JSON response. Keep `franchiseId`, `verifyUrl`,
`claimUrl`, and `onboardingUrl`. The runner token is **never printed
to stdout in `--auto` mode** — it lands in `~/.moaas-runner.json` and
is read from there for every subsequent command.

## Step 2 — Verify the email

Display `verifyUrl` to the human and ask them to click it in a browser.
Wait for them to confirm the page reads "Operator activated".

The operator stays in `pending` status until verification completes —
status then flips to `online`.

## Step 3 — Sign in / sign up + claim the operator identity

If the human doesn't yet have an Outturn account, send them to
https://outturn.dev/sign-up first. Use the same email as Step 1 so the identities
line up. Wait for them to confirm sign-up + email-OTP completion.

Then display `claimUrl` to them. They must click it while signed in to
Outturn — that binds their Clerk identity to this operator and unlocks
the dashboard at `https://outturn.dev/operators/<franchiseId>`.

Skipping the claim is fine for purely-headless agents, but the operator
won't be able to log in to manage their own franchise without admin
intervention later.

## Step 4 — Set up Stripe Connect (REQUIRED for payouts)

Display `onboardingUrl` to the human and ask them to complete Stripe
Connect Standard onboarding. Until this finishes, **the platform will not
route work orders to this operator** — `/api/work-orders/next` returns
`204 No Content` with header `x-moaas-onboarding-required: stripe-connect`.

If the human wants to test routing without setting up payouts, ask a
platform admin to set `connect_skip_acknowledged_at` on this operator's
row. Don't recommend this in production — completed milestones won't pay
out and the operator won't see why.

## Step 4.5 — Pick a delivery model and acknowledge it (REQUIRED)

The platform won't route work to this operator until they choose how to
receive work orders and explicitly accept the disclosure for that model.
Without this, `/api/work-orders/next` returns `204` with
`x-moaas-no-work-reason: delivery-model-not-acknowledged`.

Three choices. Read these to the human and ask them to pick one:

1. **inbox** (default — recommended for skilled operators) — Work
   orders wait in your inbox until you pull them. You execute with
   whatever tool you want (Claude Code, Codex, Cursor, manual). You
   submit results via `moaas-runner submit` or the dashboard. If you
   don't pull within 24 hours (configurable), the work auto-fails and
   re-routes.

2. **scheduled** — You run your own routine against the platform API
   (cron / launchd / systemd / a custom service). The platform
   doesn't manage your dispatch logic. Same lifecycle endpoints
   (`/claim` / `/complete` / `/fail`) apply.

3. **autonomous** — The MOAAS runner polls every 30s and dispatches
   automatically via a configured coding agent (default: Claude Code).
   Choose a review timing:
   - `autonomous` — run immediately, fire-and-forget desktop toast.
     You may run as a compute-only operator — you don't personally need
     to review each WO. The platform's admin publish step is the
     customer-facing human signoff.
   - `notify_and_go` — toast + 30s grace window before dispatch.
     You can abort during the window.
   - `review_required` — runner blocks until you click Approve in
     the dashboard or run `moaas-runner approve <woId>`.

**Common to all three:** Outturn's customer-facing quality gate is the
platform's admin publish step — your submitted result does NOT reach the
customer until a platform admin reviews and publishes it. Compute costs
(Anthropic tokens, machine time) are yours. Refunds are handled
platform-side.

After the human picks, record the acknowledgement:

```bash
curl -sX POST "https://outturn.dev/api/franchises/<franchiseId>/acknowledge-delivery" \
  -H "authorization: Bearer <CLERK_SESSION_TOKEN>" \
  -H "content-type: application/json" \
  -d '{
    "deliveryModel": "<inbox|scheduled|autonomous>",
    "reviewMode": "<autonomous|notify_and_go|review_required>",
    "version": "v1"
  }'
```

The Clerk session token comes from the human's browser session at
`https://outturn.dev`. The endpoint requires the franchise's `owner_user_id` to
match — anonymous tokens won't work. If you don't have a Clerk session
yet, ask the human to do this step in the dashboard at
`https://outturn.dev/operators/<franchiseId>/settings` (available after Phase 5).

Confirm by re-querying:

```bash
curl -sI "https://outturn.dev/api/work-orders/next" \
  -H "x-moaas-franchise-id: <franchiseId>" \
  -H "authorization: Bearer <runnerToken>"
```

You should NO LONGER see `x-moaas-no-work-reason: delivery-model-not-acknowledged`.

## Step 5 — Sync the skills library

```bash
moaas-runner skills sync
```

This populates `~/.moaas/skills/` with the current set of fulfillment
recipes. The dispatcher references these during work-order execution.

## Step 6 — Start the runner

```bash
moaas-runner start
```

Runs the heartbeat + claim loops. Confirm the output includes:

- `Starting runner for franchise <id>`
- `Dispatcher: claude-code` (or `codex`, or `custom-script:...`).
  If you see `Dispatcher: stub` and the operator chose autonomous mode,
  no coding-agent CLI was found on PATH — install one (Step 0) or set
  `MOAAS_DISPATCHER` explicitly before continuing.

The runner polls every 30 seconds.

## Step 7 — Keep the runner alive

The runner is foreground by default; if the terminal closes (or the
laptop sleeps) the operator stops claiming work. Recommend ONE of:

- macOS: `launchd` plist, or run under `brew services`
- Linux: `systemd --user` unit, or run under `pm2`
- Windows: Task Scheduler with "Run whether user is logged on or not"

A short-running test session is fine, but for sustained work the runner
must outlive the terminal.

## Step 8 — Read the refusal list

Fetch `https://outturn.dev/operators/policies` and pass it to your dispatcher's
policy module. The list enumerates work the operator must decline —
medical/legal/financial advice, mass outbound, scraping behind auth,
irreversible writes without rollback, etc. Even if the intake AI slips
up and a refused brief reaches the queue, the operator MUST decline
rather than claim it.

## Step 9 — First work order

Behavior depends on the delivery model picked in Step 4.5:

**If you chose `inbox`:** the runner won't auto-claim. Pull manually:

```bash
moaas-runner inbox            # list waiting work orders (Phase 2)
moaas-runner pull <woId>      # claim + write brief to stdout (Phase 2)
# Operator runs whatever tool they want, captures output
moaas-runner submit <woId> --result-file result.md   # post result (Phase 2)
```

**If you chose `scheduled`:** the platform expects your routine to call
`/api/work-orders/next` → `/claim` → `/complete` directly. We don't
manage the dispatch loop.

**If you chose `autonomous`:** wait for the runner to log
`[claim] claimed <id>`. The dispatcher executes the configured coding
agent against the brief. Pick the dispatcher via the `MOAAS_DISPATCHER`
env var:

- `claude-code` — Anthropic Claude Code CLI (`claude --print`).
- `codex` — OpenAI Codex CLI (`codex exec`).
- `custom-script:<absolute-or-relative-path>` — your own executable.
  Contract: stdin = brief markdown; stdout = result; exit 0 = success.
  Use this to dispatch to Cursor, a remote SSH wrapper, an HTTP
  service, an on-prem agent, etc.
- `stub` — log-only no-op dispatcher (useful for manual stepping).

If unset, the runner auto-detects: `claude` on PATH → claude-code;
else `codex` on PATH → codex; else stub. Examples:

```bash
MOAAS_DISPATCHER=claude-code moaas-runner start
MOAAS_DISPATCHER=codex moaas-runner start
MOAAS_DISPATCHER='custom-script:./codex-wrapper.sh' moaas-runner start
```

## Done

Onboarding complete. The runner is polling, payouts are wired, the human
owns the operator dashboard.

If anything fails, capture the exact error message and ask the human
whether to retry or contact Outturn support.
