OverviewScouts

Scouts

Scheduled agents that read one client's data with your own model key and file one report per finding into the client's inbox, on /client/v1/scouts with an agency key.

Overview

A scout is a scheduled agent that watches one client for you. On each run it reads the client's data through the same read routes your agency already uses (errors, server logs, events, sessions, links, destinations), compares what it sees with what it remembers from earlier runs, and files one report per finding into the client's inbox. When nothing clears its bar, it closes out quietly: an empty run is a good run.

Scouts run on your model key (OpenRouter, Gemini or Cloudflare). Mythic pays for no model calls, and the spend is reported per scout.

RouteWhat it does
GET /scouts/skillsThe built-in skills and the playbook each follows
GET /scouts/modelsModels a scout can run on
GET /scouts/usageReported model spend on scout runs
GET /scouts, POST /scoutsList or create scouts
GET/PATCH/DELETE /scouts/{id}One scout: read, change or pause, delete
POST /scouts/{id}/runRun a scout now
GET /scouts/{id}/runsThe last 30 runs, with what each found and spent
GET /scouts/{id}/memory, DELETE /scouts/{id}/memory/{key}What a scout remembers, and forgetting one entry
GET /scouts/reportsThe inbox
GET/PATCH /scouts/reports/{id}One report, and resolving, dismissing or snoozing it

The same operations are MCP tools: list_scout_skills, list_scout_models, get_scout_usage, list_scouts, get_scout, create_scout, update_scout, delete_scout, run_scout, list_scout_runs, get_scout_memory, forget_scout_memory, list_scout_reports, get_scout_report and update_scout_report. See the tool reference.

These are separate from the read-only Scouts in Replay Vision, which summarize one scanner's observations in a single call. Client scouts call tools in a loop across a client's surfaces and file inbox reports.

Base URL

https://mythic-analytics.gulp.workers.dev/client/v1/scouts

Authentication

Agency key (ak_), or an agency-wide mcp_ key with scouts:read or scouts:write. A location secret key (sk_) gets 403 agency_required. Routes do not need a bound location: location_id is a query parameter or body field where a route takes one, and it must be one of your clients (403 location_not_linked). 120 requests a minute per agency (429 rate_limited, with Retry-After).

A scout reads surfaces your key may not, so an mcp_ key also needs the read scope of those surfaces. ak_ keys hold every scope.

ActionScopes on an mcp_ key
List skills, models, usage, scouts, runs, memory, the inboxscouts:read
Create a scout, change it, or run it nowscouts:write + the read scope of every surface its skill reads
Pause (PATCH with only {"enabled": false}), delete, forget memoryscouts:write
Open a reportscouts:read + the read scope of every surface in its families
Change a report's statusscouts:write + the read scope of every surface in its families

A missing surface scope answers 403 insufficient_scope with required naming the first scope to add, for example logs:read. In the inbox, a report you cannot read keeps its place with an empty summary_md and a restricted object (reason, required) instead of its text.

A report whose run read server logs follows the logs privacy rule: it is refused on HIPAA locations (403 hipaa_restricted) and while the location's privacy mode cannot be read (503 privacy_unknown, retry after Retry-After).

This surface serves no CORS headers. Call it from your server, never from browser JavaScript.

Plan feature

This surface is sold by tier. If your plan does not include it, every endpoint answers 402 feature_not_in_plan — the key is valid, the tier is what is missing. GET /client/v1/agency/quota lists what your plan includes.

On Scouts the plan check runs only where a scout reads data or spends: creating a scout, changing it, and running it now answer 402 feature_not_in_plan when the client's plan lacks the scouts feature, and 503 entitlements_unavailable when the plan cannot be read. Listing, the inbox, triage, deleting and pausing work without it, so an agency that downgrades can always stop spend. scouts comes with plans that include error tracking.

Model key

Scouts use the client's or agency's Replay Vision model keys (OpenRouter, Gemini or Cloudflare). The agency and each client can hold one key per provider, and each has a default key. Without a key, creating, changing or running a scout answers 409 no_model_key: "Add a model key (OpenRouter, Gemini or Cloudflare) for this client or the agency first."

Provider

A scout's optional provider (openrouter, gemini, cloudflare, or null) picks the key it runs on, with the same rules as a Replay Vision scanner:

  • Provider set: the client's key for that provider, else the agency's. With neither, 409 no_model_key names the provider.
  • Provider null: the client's default key if the client has keys of its own, else the agency's default key.

On POST /scouts and PATCH /scouts/{id}:

  • provider sent: a key for it must be reachable (409 no_model_key), and model must fit it (422 model_provider_mismatch).
  • Only model sent: Mythic picks the provider from the providers the client has a key for that fit the model, and stores it: the scout's current provider, else the provider of the client's default key, else the only one that fits, else OpenRouter, then Cloudflare, then Gemini. When none fits, 422 model_provider_mismatch lists the providers the client has keys for.
  • provider: null: the scout runs on the default key.
  • Neither sent: the provider stays as it was (null on create).

A model-only change on a scout whose provider's key was deleted gets 409 no_model_key naming that provider. Deleting a key does not change scouts set to its provider: their runs fail with no_model_key until a key for it is added again. POST /scouts/{id}/run checks the stored provider. Scout responses include provider, and a run keeps the provider the scout had when it was queued.

Scouts created before keys were per provider were set to the provider of the key they ran on, when their model fits it; the others have provider: null.

Model

The model a run uses:

  1. The scout's own model, which must be a model the key can run (422 model_provider_mismatch otherwise). google/ ids fit OpenRouter and Cloudflare keys, other vendor/model ids fit only OpenRouter keys, @cf/vendor/model ids fit only Cloudflare keys, and bare ids like gemini-3.8-flash fit only Gemini keys.
  2. With no model set, the key's default model, if it fits the key and is not a lite or nano model.
  3. Otherwise google/gemini-3.8-flash (OpenRouter), gemini-3.8-flash (Gemini) or @cf/moonshotai/kimi-k2.6 (Cloudflare).

Lite and nano models are refused. A scout calls tools in a loop, and lite and nano models follow tool contracts poorly. Any model id containing lite or nano as a segment is rejected with 400 invalid_scout, and GET /scouts/models does not list them.

GET /scouts/models?provider=openrouter lists OpenRouter models that accept tools (without lite, nano or :free models), with prices as OpenRouter reports them. provider=gemini lists the current Gemini Flash models. provider=cloudflare returns a fixed list of models that accept tools, with default: "@cf/moonshotai/kimi-k2.6". It includes Workers AI @cf/ models and google/gemini-3.8-flash and google/gemini-3.7-flash. Read the list from the API rather than hard-coding it.

On a Cloudflare key, @cf/ models are billed as Workers AI usage on your Cloudflare account (a free daily allowance, then Workers Paid). google/ models are billed through AI Gateway and need AI Gateway credits or your own Google key stored in AI Gateway; without either, runs fail with HTTP 402. See Cloudflare keys.

Skills

A skill is the scout's standing instructions: what counts as worth a person's attention on its surfaces, how to tell it from noise, and when to stay quiet. GET /scouts/skills returns each one with its full playbook (playbook_md) and the version recorded on every run. The skill cannot change after the scout is created.

SkillReadsWhat it watches
error_trackingexceptions, logs, sessions, eventsBrowser JavaScript errors and server error logs that cost visitors, leads or tracking: bursts, new issues, comebacks and same-session browser plus server failures, weighted by landing and conversion pages
attribution_driftevents, sessions, linksChannels losing credit: paid traffic arriving without UTMs or click ids, tagged share falling, and channel shifts scored against the same weekday over four weeks
customexceptions, logs, events, sessions, links, destinationsYour own instructions over every surface a scout can read

instructions (up to 8,000 characters) are your notes, added after the skill's playbook: what to watch, what to ignore, business context. The custom skill requires them.

Each read surface maps to a scope: exceptions:read, logs:read, sessions:read, events:read, links:read, destinations:read. The scout itself reads with only the scopes of its skill's surfaces, bound to its one client, under the same plan, privacy and HIPAA rules as your own calls. If a client's plan lacks logs, an error_tracking scout notes it and continues with browser errors.

Schedule

{ "kind": "weekly", "time": "09:30", "day_of_week": 1, "timezone": "Europe/Berlin" }
FieldValues
kinddaily, weekdays or weekly
timeLocal HH:mm
day_of_weekISO weekday 1 (Monday) to 7, weekly only
timezoneIANA zone, default the client's timezone (else UTC)

The default is daily at 08:00 client time. A schedule you send is merged onto the default on create, or onto the current schedule on update.

Quick start

Pick a skill

curl https://mythic-analytics.gulp.workers.dev/client/v1/scouts/skills \
  -H "Authorization: Bearer ak_your_agency_key"

Create the scout

curl -X POST https://mythic-analytics.gulp.workers.dev/client/v1/scouts \
  -H "Authorization: Bearer ak_your_agency_key" \
  -H "Content-Type: application/json" \
  -d '{
    "location_id": "loc_abc123",
    "skill": "error_tracking",
    "instructions": "The booking form on /schedule is the only conversion that matters.",
    "delivery": { "channel_ids": ["0b6f4c5e-3a0e-4a53-9d1d-6e2f7c1a9b10"] }
  }'

Run it once now

curl -X POST https://mythic-analytics.gulp.workers.dev/client/v1/scouts/SCOUT_ID/run \
  -H "Authorization: Bearer ak_your_agency_key"

Answers 202 with run_id. Runs start within a minute and usually take 1 to 5 minutes. Follow them with GET /scouts/SCOUT_ID/runs.

Read the inbox

curl "https://mythic-analytics.gulp.workers.dev/client/v1/scouts/reports?location_id=loc_abc123&priority=P0,P1" \
  -H "Authorization: Bearer ak_your_agency_key"

Changing, pausing and deleting

PATCH /scouts/{id} merges your change onto the scout. Every change except a pause is checked like a create (plan, model key, scopes, channels). A body of only {"enabled": false} pauses the scout without those checks, and pausing cancels a pending run. A concurrent change answers 409 version_conflict: fetch the scout again and retry.

POST /scouts/{id}/run needs an enabled scout (409 scout_paused) with no run pending or running (409 run_in_progress). The body must be empty or {}.

DELETE /scouts/{id} stops the scout. Its reports stay in the inbox (reports_retained: true).

The inbox

Each report is one finding, with a title, a markdown summary_md, a suggested_action, a priority, an actionability with its explanation, and evidence.

PriorityMeaning
P0Conversions or tracking broken now
P1Broad regression on landing pages or paid traffic
P2Moderate reach
P3Narrow
P4Informational
ActionabilityMeaning
immediately_actionableA concrete fix someone can start now
requires_human_inputA person must decide something first; the explanation names it
not_actionableWorth recording, no action. Filed as suppressed, hidden from the default inbox

GET /scouts/reports returns open and snoozed reports by default, newest first. Filter with location_id, scout_id, status (a comma list, or all) and priority (for example P0,P1); page with limit (1 to 200, default 50) and next_cursor. List rows carry a one-line headline instead of the summary, evidence and history; GET /scouts/reports/{id} returns the full report.

A client has at most one live (open or snoozed) report per problem (dedupe_key). When a scout sees the same problem again, it edits that report with fresh evidence (edit_count, a history entry) instead of filing a duplicate.

Report statuses

StatusHow it gets thereCan move to
openFiled, restored, or a snooze endedresolved, dismissed, snoozed
snoozedYou snoozed it until snoozed_untilopen, resolved, dismissed
resolvedYou resolved itNothing: terminal
dismissedYou dismissed it with a reasonopen
suppressedFiled as not_actionableopen, dismissed
curl -X PATCH https://mythic-analytics.gulp.workers.dev/client/v1/scouts/reports/REPORT_ID \
  -H "Authorization: Bearer ak_your_agency_key" \
  -H "Content-Type: application/json" \
  -d '{ "status": "dismissed", "reason": "Third-party chat widget; does not affect the form." }'
  • Resolve is terminal. If the problem comes back, the scout files a new report; a resolved one answers 400 invalid_status_change to any change (409 report_closed if it was resolved while your change was in flight).
  • Dismiss needs a reason (up to 1,000 characters). The scout reads your reason on its next runs, for 30 days, so it stops filing the same thing.
  • Snooze needs snoozed_until, a future time within 90 days. The report reopens when it passes.
  • Restore a dismissed or suppressed report by setting status: "open". If another open report already tracks the same problem, that answers 409 duplicate_open_report.

A report that changed since you read it answers 409 status_conflict. Every change is recorded in history with who made it (the key) and the note.

Evidence

Evidence is not model text. A scout cites tool calls from its own run, and the server copies the recorded result into the report: the tool, its args, the HTTP status, the surface (family), and an excerpt of up to 4,000 characters of exactly what the scout read. The scout adds only a note on what the result shows. A report needs at least one piece of evidence and holds at most 12 per filing. Reports keep their evidence after a run's raw tool results are pruned 30 days later.

Memory

A scout remembers between runs. GET /scouts/{id}/memory lists up to 200 entries by key prefix:

PrefixMeaning
pattern:What normal looks like (baselines)
noise:What it skips and why
dedupe:Already surfaced
addressed:Fixed, with the date
report:Which report tracks what

DELETE /scouts/{id}/memory/{key} forgets one entry: the quickest way to correct a scout, for example a noise: entry that now hides something that matters.

Runs and spend

GET /scouts/{id}/runs returns the last 30 runs: status, trigger (schedule or on_demand), model, skill version, model turns (steps), tool_calls, reports_filed, reports_edited, the surfaces read, and the close-out summary (what it looked at, filed and ruled out). Each run also carries model_calls, known_cost_usd and unknown_cost_calls.

GET /scouts/usage totals reported spend for a UTC date range (inclusive, at most 92 days, default this month), optionally for one client, with one row per scout. It counts every provider call, including failed and repaired ones. Providers do not always report cost: calls without it are counted in unknown_cost_calls, and your provider's bill is authoritative.

Delivery to alert channels

delivery.channel_ids names up to 5 active alert channels of your agency (422 invalid_delivery_channel otherwise). Each new open report is sent to each channel at most once; edits are not re-sent, and suppressed (not_actionable) reports are never sent. Nothing is sent for a report resolved or dismissed before delivery, or for a client no longer on your roster.

A Slack channel gets the title, priority, scout name, the summary's first line and a link to the report in the agency app. A webhook gets JSON with X-Mythic-Event: client_scout.report, signed like every alert webhook:

{
  "type": "client_scout.report",
  "source": "client_scout",
  "scout": { "id": "…", "name": "Error tracking", "skill": "error_tracking" },
  "run_id": "…",
  "filed_at": "2026-10-20T08:04:11Z",
  "report": {
    "id": "…",
    "location_id": "loc_abc123",
    "title": "Booking form throws on submit for Safari visitors",
    "summary_md": "…",
    "priority": "P0",
    "actionability": "immediately_actionable",
    "suggested_action": "…",
    "url": "https://…/c/loc_abc123/scouts/reports/…"
  }
}

Reports built from server logs are not delivered on HIPAA locations. Scout reports never raise alerts in the central alert feed.

Limits

LimitValue
Scouts per client10 (422 scout_limit)
Model turns per run24
Tool calls per run60
New reports per run5
Evidence items per filing12
Delivery channels per scout5
Name120 characters
Instructions8,000 characters
Dismiss reason1,000 characters
Snooze90 days
Memory entries per scout200
Runs listedLast 30
Usage range92 days
Requests120 a minute per agency