Plan formats¶
Three shapes are accepted. The runtime picks them up in priority order from the /v1/predict payload.
When to use which¶
| Use case | Recommended shape |
|---|---|
| Recurring high-volume workflow with predictable steps | Micro-plan JSON, baked into the image at plans/<domain>/<workflow>.json |
| Arbitrary plain-English request | plan_text — server decomposes via Claude (cached) |
| Ad-hoc plan you don't want baked in | task_suite (inline JSON dict) |
Multi-task suite with task_id + verify clauses |
task_suite or task_file |
Micro-plan (recommended for production extraction)¶
A flat JSON list of step objects executed by MicroPlanRunner. Best reliability — sections, gates, loops, and explicit claude_only markers all live here.
[
{
"intent": "Navigate to https://marketplace.example.com/listings/state-fl/by-owner/price-35000/",
"type": "navigate",
"budget": 3,
"section": "setup",
"required": true
},
{
"intent": "Verify page shows private-seller listings near Florida above $35,000",
"type": "extract_data",
"claude_only": true,
"section": "setup",
"gate": true,
"verify": "Page shows listings from private sellers near Florida with prices above $35,000"
},
{
"intent": "Click only an organic private-seller listing title; skip sponsored cards",
"type": "click",
"budget": 8,
"grounding": true,
"section": "extraction"
},
{
"intent": "Read the URL from the browser address bar",
"type": "extract_url",
"claude_only": true,
"section": "extraction"
},
{
"intent": "Scroll down toward the Description section",
"type": "scroll",
"budget": 10,
"section": "extraction"
},
{
"intent": "Extract Year, Make, Model, Price, Phone if visible, and Seller Name",
"type": "extract_data",
"claude_only": true,
"section": "extraction"
},
{
"intent": "Go back to the search results page",
"type": "navigate_back",
"budget": 3,
"section": "extraction"
},
{
"intent": "Loop back to click the next listing",
"type": "loop",
"loop_target": 2,
"loop_count": 3,
"section": "extraction"
}
]
Field reference is on the Concepts page.
Submit it three ways:
// (a) reference a baked-in path
{ "micro": "plans/example/extract_listings.json" }
// (b) inline the raw step list
{ "task_suite": [ ...the array above... ] }
// (c) inline as a JSON string
{ "task_file_contents": "[\"intent\":\"...\", ...]" }
The server validates and clamps every plan against:
MANTIS_MAX_STEPS_PER_PLAN(default 200) — oversized plans rejected with 400MANTIS_MAX_LOOP_ITERATIONS(default 50) —loop_countsilently clamped
Task suite (Claude-CUA-style autonomous-per-task)¶
Used by a multi-task CRM workflow. Each task is given to the runner with its own max_steps budget and a verify clause; Claude decides what to do per task.
{
"session_name": "crm_demo",
"base_url": "https://crm.example.com",
"auth": { "user_id": "...", "password": "..." },
"tasks": [
{
"task_id": "login",
"intent": "Go to https://... and log in with user X and password Y",
"save_session": true,
"start_url": "https://crm.example.com",
"verify": { "type": "url_not_contains", "value": "login" }
},
{
"task_id": "update_lead_industry",
"intent": "Go to the Leads Page. Update industry of qualified lead to 'Space Exploration'.",
"require_session": true,
"start_url": "https://crm.example.com",
"verify": { "type": "page_contains_text", "value": "Space Exploration" }
}
]
}
Verify predicates supported today:
verify.type |
Meaning |
|---|---|
url_not_contains |
After the task, the URL doesn't contain value |
url_contains |
After the task, the URL contains value |
page_contains_text |
The current page renders value somewhere |
download_exists |
A file matching the glob was created during the task |
Submit:
plan_text (auto-decompose)¶
Plain English in, micro-plan out. The server runs PlanDecomposer (Claude, cached by the plan-text signature so subsequent runs of the same plan-text don't re-pay decomposition).
{
"plan_text": "Go to a marketplace listings site, filter to private sellers above $35,000 in Florida, extract listing details for the first 3 listings, save year/make/model/price/phone."
}
Decomposition costs ~$0.10 per unique plan-text the first time, free after. Best for one-shot tasks or when you don't yet have a stable workflow definition. Once you've validated a decomposition, copy the resulting plan to a plans/...json file and start submitting via micro for cheaper, deterministic runs.
Decision tree¶
Have a stable workflow you'll run many times?
├─ yes → write a micro-plan once and submit via `micro`
└─ no → is it a one-shot or rapidly-changing?
├─ yes → submit as `plan_text`, server decomposes via Claude
└─ no → is it a multi-task suite?
├─ yes → submit as `task_suite`
└─ no → micro-plan inline via `task_suite` field
Per-tenant URL allowlist¶
If your tenant config has a non-empty allowed_domains list, the server scans your plan for navigate URLs / task.start_url / task_suite.base_url and rejects 403 if any host is off-list. This applies to all three plan shapes. See URL allowlist for the matching rules.
Next¶
- Authentication — getting a tenant token
- Sending plans — full request shape and curl recipes
- Operations / tenant keys — operator-side provisioning