# Prometheus reference (bundled with the skill)

Full command + endpoint reference. Read this when you need exact flags, request
shapes, error codes, or the Script/Schedule/Run/ScriptEvent objects. Base URL is
`$PROMETHEUS_URL` (default the hosted `https://firecrawl.dev`).
Authenticate with a **Prometheus API token** sent as
`Authorization: Bearer $PROMETHEUS_TOKEN` on every request — obtained via
`prometheus login` (browser OAuth; saved to `~/.prometheus/config.json`) or
minted in the web app's Settings.

The model: a **SCRIPT** is the collector — yours (versioned, self-healing) or
a marketplace listing you subscribe to. Scripts can declare **PARAMETERS** (CLI flags
the script parses); pass them per run with `--param` / `{params}`, or bind
them to a **SCHEDULE** — a cron plus fixed parameter values. Without a
schedule a script is an on-demand API endpoint via `prometheus run` /
`POST /prometheus/api/v1/scripts/{id}/run`.

## CLI

```
prometheus login [--url BASE] | logout | whoami
prometheus build "<prompt>" [--schema FILE] [--url URL]... [-o DIR] [--model P:ID] [--json]
prometheus scripts create "<prompt>" [--every SCHED] [--param k=v]... [--name N] [--heal STRAT] [--session ID] [--schema FILE] [--json]
prometheus scripts ls [--json]
prometheus scripts show <id> [-o script.ts] [--json]
prometheus scripts data <id> [-o FILE]         latest successful run's dataset, no fresh run
prometheus scripts runs <id> [--status S] [--trigger T] [--schedule SID] [--since ISO] [--until ISO] [--param k=v]... [--limit N] [--cursor C]   data-producing run history (alias: history)
prometheus scripts events <id> [--type repair,rebuild,...] [--limit N] [--cursor C]   system-events log: heal attempts + lifecycle
prometheus scripts heal <id> | fork <id> | pin <id> <V|latest> | rm <id>
prometheus run <scriptId> [--param k=v]... [-o FILE]   # fresh data, synchronously (the API-endpoint trigger)
prometheus schedules ls [<scriptId>] [--json]
prometheus schedules add <scriptId> --every SCHED [--param k=v]... [--webhook URL] [--name N] [--json]
prometheus schedules data <sid> [-o FILE]
prometheus schedules pause <sid> | resume <sid> | rm <sid>
prometheus schedules webhook <sid> <url|off>   # set/clear the run webhook (secret printed once)
prometheus marketplace search "<query>" [--json]
prometheus marketplace show <id> [-o script.ts] [--json]
prometheus marketplace deploy <id> --subscribe|--fork [--name N] [--every SCHED [--param k=v]...] [--json]
prometheus marketplace publish <scriptId> [--handle H] [--name N] [--summary S] [--json]
prometheus marketplace unpublish <id> [--json]
prometheus marketplace me [--json]
```

- `marketplace` aliases: `market`, `mp`. `search`/`show` are public (no token);
  the rest require login.
- `--param key=value` (repeat for multiple params; repeat a key for `string[]`
  values). The server validates against the script's declared interface and
  rejects unknown or missing-required params with a per-key error.
- On `scripts create` / `marketplace deploy`, `--every` also schedules in the
  same call (`--param` then binds values to that schedule); omit `--every` for
  on-demand only. `scripts pin <id> <V>` pins runs to version V
  (`pin <id> latest` subscribes to the latest again).
- TTY → human output (`build` writes `script.ts` + `sample.json`). Piped or
  `--json` → raw JSON on stdout.
- Errors go to stderr; exit code is non-zero. Set `PROMETHEUS_DEBUG=1` for the
  full error payload.

## HTTP endpoints

| Method & path | Purpose |
|---|---|
| `POST /prometheus/api/v1/build` | Prompt → verified collector + sample (+ declared `parameters`). Runs the agent (~30–180s). |
| `GET /prometheus/api/v1/build/{sessionId}` | Re-fetch a prior build's `{script, sample, parameters, …}`. |
| `GET /prometheus/api/v1/profile/{ref}` | Unified script profile (`s_<scriptId>` / `l_<listingId>`) → `{ref, relationship, script, versions, runs, events, content, listing}`. Listing refs are **public** (relationship `viewer`); script refs require auth. |
| `GET /prometheus/api/v1/scripts` | List scripts (owned + tracked; schedules nested) → `{scripts}`. |
| `POST /prometheus/api/v1/scripts` | Mint a script from `sessionId` \| `script` \| `prompt`; optional `parameters` (raw script only), `seedData`, and `schedule: {name?, every, params?, enabled?}` → `201 {script, schedule?}`. |
| `GET /prometheus/api/v1/scripts/{id}` | Detail → `{script, versions, runs, events}` (versions empty for tracked; `runs`/`events` are the recent slices of the endpoints below); `?include=content` adds `content` (`&version=n` selects). |
| `PATCH /prometheus/api/v1/scripts/{id}` | `{name?, summary?, heal?, pinnedVersion? (null = track latest), mode?: "fork"}` (fork = take over a tracked script, one-way) → `{script}`. |
| `DELETE /prometheus/api/v1/scripts/{id}` | Archive (soft delete); cascades to schedules. |
| `GET/POST /prometheus/api/v1/scripts/{id}/versions` | List versions / `POST {script}` appends a manual version (parameter interface carries forward; re-gated if published). Owned only. |
| `POST /prometheus/api/v1/scripts/{id}/heal` | Repair/rebuild now (~minutes) → `{healed, events: ScriptEvent[]}` (the attempts also land in the events log). Owned only. |
| `POST /prometheus/api/v1/scripts/{id}/run` | **Run now, synchronously (~2 min max) → `{run, data}` with the JSON inline.** Body `{params?: object, trigger?: "manual"}` (default trigger `api`). `200` success; `502` `{run, data: null}` on failure (run.error explains); `400` `{error, code: "invalid_params", errors: {key: message}}` on bad params (no run recorded). |
| `GET /prometheus/api/v1/scripts/{id}/runs` | **Data-producing run history** (schedule runs + one-offs; heal attempts live in `…/events`), newest first → `{runs, nextCursor}`. Query params: `limit` (1–100, default 20), `cursor` (opaque, from `nextCursor`), `status` (running\|success\|error\|declined), `trigger` (schedule\|api\|manual\|self_heal), `scheduleId`, `since`/`until` (ISO 8601, inclusive, on startedAt), and partial params match via `params.<key>=<value>` args (e.g. `?params.city=Paris` — runs whose effective params CONTAIN those key/values; values parse as JSON scalars when possible, else match as strings; scalars only). Kept forever. |
| `GET /prometheus/api/v1/scripts/{id}/runs/{rid}/data` | A specific run's stored dataset (raw body; headers X-Run-Id, X-Run-Row-Count; 404 until data exists). |
| `GET /prometheus/api/v1/scripts/{id}/events` | **System-events log** (heal attempts incl. declined verdicts, schedule auto-pauses, cache syncs, auto-forks, gate verdicts, version appends), newest first → `{events, nextCursor}`. Query params: `limit` (1–100, default 20), `cursor`, `type` (comma-separated: repair, rebuild, schedule_auto_pause, cache_sync, auto_fork, gate_verdict, version_append). Kept forever. |
| `GET/POST /prometheus/api/v1/scripts/{id}/schedules` | List schedules / `POST {name?, every, params?, enabled?, webhookUrl?}` → `201 {schedule}` (`400 invalid_params` when required params aren't covered; with `webhookUrl` the response carries the shown-once `webhookSecret`). |
| `PATCH /prometheus/api/v1/scripts/{id}/schedules/{sid}` | `{name?, every?, params? (rebind values), enabled?, webhookUrl? (null clears webhook + secret)}` → `{schedule}`. |
| `DELETE /prometheus/api/v1/scripts/{id}/schedules/{sid}` | Archive (soft delete) → `{ok, archived}`. |
| `GET /prometheus/api/v1/scripts/{id}/schedules/{sid}/data` | The schedule's latest successful dataset (params fixed → coherent feed; raw body, same headers; 404 if none). |
| `GET /prometheus/api/v1/marketplace/listings` | Search published listings (`q`, `sort=trending\|new\|top`, `limit`, `offset`). **Public**, rate-limited. |
| `POST /prometheus/api/v1/marketplace/listings` | Publish a script's latest version: `{scriptId, name?, summary?, handle?, sample?}` (parameters ride along automatically). Runs the sterility gate; `201` even on rejection (see `status`/`gate`). |
| `GET /prometheus/api/v1/marketplace/listings/{id}` | Full listing detail (script/parameters/prompt/schema/sample). **Public**, rate-limited. |
| `PATCH /prometheus/api/v1/marketplace/listings/{id}` | Owner update: `{script?, parameters?}` pushes a new gated version · `{summary?, sample?}` meta · `{status:"unpublished"}` withdraws. |
| `DELETE /prometheus/api/v1/marketplace/listings/{id}` | Unpublish (tracking scripts auto-fork at their next run). |
| `GET /prometheus/api/v1/marketplace/listings/{id}/script` | Resolve the current approved script + parameters (tracker run-time). **Public**, rate-limited. |
| `POST /prometheus/api/v1/marketplace/listings/{id}/deploy` | Deploy into your library: `{mode:"track"\|"fork", name?, schedule?: {every, params?}}` → `201 {script, schedule?}` (track = a `kind:"tracked"` script, no local copy). |
| `POST /prometheus/api/v1/marketplace/listings/{id}/events` | Report usage: `{type, refId?, error?}` → `{ok:true}`. |
| `POST /prometheus/api/v1/marketplace/publishers` | Claim a publisher handle (first publish; permanent) → `201` Publisher. |
| `GET /prometheus/api/v1/marketplace/publishers/{handle}` | Publisher profile + their listings. **Public**, rate-limited. |
| `GET /prometheus/api/v1/marketplace/me` | Your publisher profile + your listings. |

Public marketplace GETs are rate-limited per IP — `429 {"code":"rate_limited"}`
with a `retry-after` header. Marketplace writes without a token return
`401 {"code":"auth_required"}`.

### `POST /prometheus/api/v1/build` request

```jsonc
{
  "prompt": "string (required)",
  "schema": { /* JSON Schema; enforce output shape */ },   // optional
  "urls":   ["https://…"],                                  // optional starting points
  "model":  { "provider": "openai", "model": "gpt-5.5" }    // optional
}
```

Response `200`: `{ sessionId, language, script, sample, rowCount, summary,
howItWorks, expectedOutput, schema, parameters, integration }` —
`integration.run` shows the parameter flags (e.g.
`tsx script.ts --city=<value>`).
Errors: `400` missing prompt · `401` `auth_required` (no/invalid Bearer token —
run `prometheus login`) · `403` `reconnect_required` (the team's Firecrawl
connection expired — reconnect in Settings) · `502` `build_incomplete` (retry
with a sharper prompt or `urls`).

### `POST /prometheus/api/v1/scripts` request

```jsonc
{
  "prompt": "string",        // OR "sessionId": "build-…" OR "script": "…" (one required)
  "name": "string",          // optional (derived if omitted)
  "summary": "string",       // optional
  "schema": { /* … */ },      // optional
  "heal": "repair_then_rebuild",  // optional; default
  "parameters": [ /* ScriptParameter */ ],  // optional; only with raw `script`
  "seedData": "…",           // optional; with `script` — JSON text to seed the timeline
  "schedule": {              // optional: schedule in the same call
    "name": "string",        // optional
    "every": "daily@09:00",  // required inside schedule
    "params": { "city": "Paris" },  // optional: bound parameter values
    "enabled": true           // optional
  }
}
```

Response `201`: `{ "script": Script, "schedule"?: Schedule }`. Omit `schedule`
for an on-demand script.

## Parameters

A script's declared CLI interface — a list of **ScriptParameter**:

```jsonc
{
  "name": "city",            // kebab-case; the script takes --city=<value>
  "type": "string",          // string | number | boolean | string[]
  "description": "…",
  "required": true,
  "example": "Paris",        // always present on required params (a tested value)
  "default": "…"             // optional params may declare a default
}
```

Callers pass a `{params}` object — the API validates it against the interface
and translates it to `--name=value` argv. Bad params →
`400 {error, code: "invalid_params", errors: {key: message}}` and no run.
Self-heal triages input failures out (re-runs the current version with the
declared example params first) and heals preserve the parameter interface.

## Schedules (`every`, all UTC)

`hourly` · `30m` (1–59) · `6h` (1–23) · `daily` · `daily@14:00` · `weekly` ·
`monday@09:00` (any weekday) · raw 5-field cron (`0 9 * * 1`). A schedule's
`params` are fixed, so its data endpoint is a coherent feed; required
parameters must be covered by bound values plus declared defaults.

## Self-heal (`heal`)

`off` · `repair` (patch script) · `rebuild` (regenerate from request) ·
`repair_then_rebuild` (default — try repair, escalate to rebuild). A successful
heal appends a NEW script version (same parameter interface) that every
track-latest consumer picks up. Subscribed scripts are platform-maintained — fork
first to heal them yourself.

## Script object

```jsonc
{
  "id": "…",
  "kind": "owned",              // owned | subscribed (a marketplace listing you run; no local versions)
  "name": "…",
  "summary": "…|null",
  "prompt": "…|null",           // originating request — heal's rebuild leg derives from it
  "schema": null,                // pinned output schema, when given
  "engine": "claude|codex|null", // pinned from the build; null = server default (owned only)
  "model": "…|null",
  "heal": "repair_then_rebuild",
  "latestVersion": 3,            // subscribed: the listing version last synced (0 = none yet)
  "parameters": [ /* ScriptParameter */ ],  // declared CLI interface ([] when none)
  "pinnedVersion": null,         // owned only: run this exact version; null = latest
  "health": "healthy",          // healthy | failing | healing | pending
  "createdAt": "ISO",
  "latestRun": { /* status, kind, trigger, finishedAt, rowCount, error */ },
  "source": { "listingId": "…", "version": 3 },  // subscribed only
  "publishedListingId": "…|null",
  "schedules": [ /* Schedule, below */ ]
}
```

Versions: `{ version, source, createdAt, gate? }` —
source: `build | manual | self_heal | platform_heal | marketplace_sync | import`.
Subscribed scripts support run/runs/events/schedules/data + `PATCH {name, mode:"fork"}` +
`DELETE`; versions/heal/publish are 404/400.

## Schedule object

```jsonc
{
  "id": "…",
  "scriptId": "…",
  "name": "…|null",
  "schedule": { "cron": "0 9 * * *", "description": "daily at 09:00 UTC" },
  "params": { "city": "Paris" },  // bound parameter values; null when none
  "enabled": true,
  "health": "healthy",
  "createdAt": "ISO",
  "lastRunAt": "ISO|null",
  "nextRunAt": "ISO|null",
  "webhookUrl": "https://…|null",   // POSTed after every scheduled run
  "webhookSecret": "whsec_…|null",  // HMAC signing secret — treat as sensitive
  "lastWebhookAt": "ISO|null",
  "lastWebhookStatus": "ok|<status>|timeout|error|null",
  "latestRun": { /* status, kind, trigger, finishedAt, rowCount, error */ }
}
```

Webhooks: a schedule with `webhookUrl` gets a POST after every scheduled run
(`run.succeeded`/`run.failed`, full dataset inline; one-off runs never fire it),
plus `schedule.paused` when self-heal declines the schedule's bound params as
out of the script's scope and auto-pauses it (`disabledReason` on the schedule
explains; re-enabling clears it).
Single best-effort attempt, 10s timeout. Verify `x-prometheus-signature`
(`t=<unix>,v1=<hex hmac-sha256(secret, "<t>.<raw body>")>`) with the schedule's
`webhookSecret`. PATCH `webhookUrl: null` clears url + secret; re-setting
generates a fresh secret (rotation).

## Run object

A run is a **data-producing execution**; heal attempts are script events, not
runs.

```jsonc
{
  "id": "…",
  "scheduleId": "…|null",       // null for one-off runs
  "params": { /* …|null */ },    // effective parameter values the run executed with
  "versionRan": 3,               // which script version executed, when known
  "scriptVersionId": "…|null",   // script_versions row id that executed; null for subscribed runs and legacy rows
  "status": "success",           // running | success | error | declined (legacy heal verdicts only)
  "kind": "refresh",             // create | refresh
  "trigger": "api",              // schedule | api | manual | self_heal
  "startedAt": "ISO|null",
  "finishedAt": "ISO|null",
  "dataBlobUrl": "…|null",
  "rowCount": 5,
  "error": "string|null"
}
```

`health`: `success` run → `healthy`; `error` → `failing`; a repair/rebuild
event in flight → `healing`; no run yet → `pending`.

## ScriptEvent object

One entry in the system-events log (`GET …/scripts/{id}/events` /
`prometheus scripts events`) — heal attempts and lifecycle.

```jsonc
{
  "id": "…",
  "type": "repair",             // repair | rebuild | schedule_auto_pause | cache_sync | auto_fork | gate_verdict | version_append
  "status": "success",          // running | success | error | declined | info (instantaneous events)
  "trigger": "self_heal",       // what set it off, when known
  "scheduleId": "…|null",       // the schedule the event concerns (heal context, auto-pause)
  "params": { /* …|null */ },    // heal legs: the param values under judgment
  "version": 4,                  // resulting/affected script version, when applicable
  "error": "string|null",       // failure/decline reason
  "rowCount": 5,
  "startedAt": "ISO",
  "finishedAt": "ISO|null",
  "detail": { /* …|null */ }     // type-specific extras (pause reason, listingId, gate verdict, …)
}
```

A `declined` repair/rebuild event means self-heal judged the failing params
out of the script's scope (no version appended; the bound schedule, if any,
was auto-paused).

## Marketplace listing object

`GET /prometheus/api/v1/marketplace/listings` returns the card fields; `GET …/listings/{id}`
adds the detail fields below.

```jsonc
{
  "id": "…",
  "name": "Hacker News — top stories",
  "summary": "…",
  "status": "published",       // pending | published | rejected | broken | unpublished
  "version": 3,                // current gate-approved version (0 = none approved yet)
  "publisher": { "handle": "prometheus", "displayName": "Prometheus", "official": true },
  "copies": 87,
  "subscriberRuns14d": 410,
  "createdAt": "ISO",
  "updatedAt": "ISO",
  "publishedAt": "ISO|null",
  // ── detail-only fields (GET /listings/{id}) ──
  "prompt": "the original build request — heal/rebuild derives from it",
  "schema": { /* JSON Schema | null */ },
  "sample": { /* ~3-row author-approved sample | null */ },
  "script": "import Firecrawl from '@mendable/firecrawl-js'; … | null",  // current APPROVED version; null when none yet
  "parameters": [ /* ScriptParameter */ ],            // the approved version's declared interface
  "gate": { "status": "approved", "reason": null },   // latest version's gate: pending | approved | rejected
  "versions": [
    { "version": 1, "source": "publish", "gateStatus": "approved", "createdAt": "ISO" }
    // source: publish | author_update | self_heal | platform_heal
  ]
}
```

## Using a built script

The `script` is self-contained TypeScript. To run it:

```bash
npm i @mendable/firecrawl-js tsx
export FIRECRAWL_API_KEY=fc-...
tsx script.ts                        # prints JSON (same shape as `sample`) to stdout
tsx script.ts --city=Paris           # parameterized scripts take their declared flags
```

It reads `FIRECRAWL_API_KEY` from the environment and writes only JSON to
stdout (logs go to stderr), so it's safe to pipe into `jq` or a file.
