Async tasks

Poll and manage long-running provider tasks.

Some verbs take seconds or minutes to finish. research, Firecrawl crawl, and findall submit a task to the provider and either poll on your behalf (the default) or hand you the task id to follow up later. A local index at ~/.marmot/tasks.json keeps track of every submission so nothing gets lost.

marmot research <query> [--async | --wait] [flags…]
marmot crawl <url> [--async | --wait] [flags…]
marmot findall <objective> [--async | --wait] [flags…]
marmot get <id> [flags…]
marmot tasks list [flags…]
marmot tasks get <id>
marmot tasks remove <id>
marmot tasks prune [flags…]

Submit and wait

With no flags, marmot blocks, polls until the task reaches a terminal status (done, failed, or cancelled), and prints the final envelope. A spinner ticks elapsed time on stderr.

marmot research "compare postgres 17 vs 16" --provider parallel

--retries <n> retries the initial submission up to N times with exponential backoff if the provider returns a transient error (network blip, 5xx, 429). The polling loop has its own retry behavior and is unaffected. --timeout <seconds> sets the per-attempt submit timeout.

marmot research "..." --provider parallel --retries 3

Submit and exit

Pass --async to return the task id immediately and exit. Useful for scripts that kick off work and check back later.

marmot research "..." --async --provider parallel

The response includes a next field with the exact follow-up command:

{
  "ok": true,
  "provider": "parallel",
  "verb": "research",
  "taskId": "trun_abc...",
  "status": "queued",
  "next": "marmot get trun_abc..."
}

Whether you used --wait or --async, the task is recorded locally. If you Ctrl-C a --wait mid-poll, the id is still in the index, and marmot tasks list will surface it.

Polling tasks

marmot get <id> [flags…]

marmot get is the universal poll and retrieve verb for research, crawl, and findall tasks. A single status check by default; add --wait to poll to completion.

FlagDescription
--provider <slug>Provider that issued the task id. Inferred from the local task index when present; required only when the task is not in the index.
--verb <name>research, crawl, or findall. Inferred from the local task index when possible. Required when the id is not in the index.
--api-key <key>Override the env var.
--waitBlock and re-poll until terminal status. Otherwise a single check.
--rawEmit the provider's native response under raw.
--jsonEmit the structured envelope. The default.

Every poll updates lastCheckedAt and status on the local record. On terminal status, completedAt is stamped and a usage record is appended (call_id equals the task id, so submit-time and completion rows join cleanly under one identifier). The local task record carries a usageLogged flag so repeated marmot get calls don't double-log.

Managing tasks

marmot tasks browses and cleans up the local index. Records live at ~/.marmot/tasks.json, file mode 0o600. Every async submission writes a record automatically. marmot get updates it.

marmot tasks list   [flags…]
marmot tasks get   <id>
marmot tasks remove <id>
marmot tasks prune  [flags…]

tasks list

Default output is TTY-aware: a human table on an interactive terminal, the JSON envelope when piped or redirected. Pass --json or --markdown to force a specific format.

FlagDescription
--provider <slug>Filter by provider.
--verb <name>Filter by verb.
--status <name>queued, running, done, failed, or cancelled.
--since <duration>Only show tasks created within this window: 1h, 24h, 7d, etc.
--limit <n>Cap rows returned (default 20, max 1000). Newest first.
--jsonAlways emit the JSON envelope.
--markdownEmit a markdown pipe-table (for embedding in docs / chats).

When the underlying task count exceeds --limit, the human-mode footer reads Showing 20 of 87 tasks. Pass --limit 1000 or filters (--since, --status, --verb, --provider) to narrow. The JSON envelope gains a total and limit field so consumers can paginate programmatically.

tasks get <id>

Print one record. Supports --json and --markdown like the other show commands.

tasks remove <id>

Drop a record from the local index. This does not cancel on the provider. Cancellation is not yet exposed as a marmot flag — use the provider's dashboard or API to cancel an in-flight task; the local index will pick up the terminal status on the next marmot get poll.

tasks prune

FlagDescription
--older-than <days>Cutoff in days (default 30). Only terminal-state records are removed.

prune only removes terminal-state records (done, failed, cancelled). In-flight tasks are never auto-removed.

Record shape

{
  "taskId": "trun_abc…",
  "provider": "parallel",
  "verb": "research",
  "status": "done",
  "createdAt": "2026-05-02T15:00:00.000Z",
  "lastCheckedAt": "2026-05-02T15:02:30.000Z",
  "completedAt": "2026-05-02T15:02:30.000Z",
  "label": "first 80 chars of the original query"
}

Limitations

  • Streaming. --stream is reserved for marmot run. Web and data verbs poll; they do not stream.
  • Webhooks. Marmot polls and does not accept callbacks.
  • Recurring monitors. Only one-shot tasks are supported. Cron-like schedules are out of scope.