All endpoints return JSON. State-changing requests (POST, DELETE) require Content-Type: application/json.
If MANTIS_AUTH_TOKEN is set, every request (except /health) must include the token via one of:
- Bearer header:
Authorization: Bearer <token> - Cookie:
mantis_token=<token>(set automatically on first browser visit with?token=) - Query parameter:
?token=<token>
Without MANTIS_AUTH_TOKEN, access is restricted to localhost (127.0.0.1 / ::1).
Always public (no auth required). Returns server health and agent count.
curl http://localhost:8420/health{
"status": "healthy",
"agents_running": 2,
"max_agents": 5,
"uptime_s": 3621.4
}List all available challenge types with their metrics and descriptions.
curl http://localhost:8420/api/challenges{
"ETH-1H-BINARY": {
"type": "binary",
"short": "ETH 1h direction",
"desc": "Predict whether ETH goes up or down in the next hour",
"asset": "ETH",
"metric": "AUC",
"metric_info": {
"primary": "mean_auc",
"all": ["mean_auc"],
"direction": "higher",
"label": "AUC"
}
}
}List all agents. Returns lightweight summaries by default. Supports ETag caching.
| Param | Type | Default | Description |
|---|---|---|---|
full |
query | 0 |
Set to 1 for full agent state including iterations |
# Summary list
curl http://localhost:8420/api/agents
# Full detail (includes all iterations, notes, chat)
curl http://localhost:8420/api/agents?full=1Response (summary mode):
[
{
"id": "a1b2c3d4e5f6",
"status": "running",
"config": {
"challenge": "ETH-1H-BINARY",
"goal": "Explore momentum signals",
"min_iterations": 5,
"max_iterations": 20,
"model": "sonnet",
"days_back": 60
},
"created_at": "2026-03-26T12:00:00Z",
"iteration_count": 3,
"paused": false,
"last_metrics": {"mean_auc": 0.542}
}
]Supports ETag: pass If-None-Match header to get 304 Not Modified when nothing changed.
Get full detail for a single agent, including all iterations, live activity, notes, and chat.
curl http://localhost:8420/api/agents/a1b2c3d4e5f6Returns 404 if agent does not exist.
Create and launch a new agent.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
challenge |
string | yes | — | Challenge name (e.g. ETH-1H-BINARY) |
goal |
string | yes | — | Research goal (max 10,000 chars) |
model |
string | no | sonnet |
Claude model: sonnet, opus, or haiku |
min_iterations |
int | no | 5 |
Minimum iterations before agent can signal done (1-100) |
max_iterations |
int | no | 20 |
Hard stop after this many iterations (1-500) |
days_back |
int | no | 60 |
Days of historical data to use (60-365) |
curl -X POST http://localhost:8420/api/agents \
-H "Content-Type: application/json" \
-d '{
"challenge": "ETH-1H-BINARY",
"goal": "Explore momentum and mean-reversion signals using RSI and Bollinger bands",
"max_iterations": 10
}'{"id": "a1b2c3d4e5f6", "status": "starting"}Returns 400 if challenge is unknown or goal is missing.
Returns 429 if max concurrent agents reached.
Stop a running agent and kill its Docker container.
curl -X POST http://localhost:8420/api/agents/a1b2c3d4e5f6/stop{"status": "stopped"}Delete an agent, kill its container, and remove all data.
curl -X POST http://localhost:8420/api/agents/a1b2c3d4e5f6/delete{"status": "deleted"}Pause an agent between iterations. The agent finishes its current iteration then waits.
curl -X POST http://localhost:8420/api/agents/a1b2c3d4e5f6/pause{"paused": true}Resume a paused agent.
curl -X POST http://localhost:8420/api/agents/a1b2c3d4e5f6/resume{"paused": false}Update a running agent's research goal. The agent sees the new goal on its next iteration.
curl -X POST http://localhost:8420/api/agents/a1b2c3d4e5f6/goal \
-H "Content-Type: application/json" \
-d '{"goal": "Focus on volume-weighted momentum features"}'{"status": "updated"}Get the agent's current goal.
curl http://localhost:8420/api/agents/a1b2c3d4e5f6/goal{"content": "# Research Goal\n\nFocus on volume-weighted momentum features\n"}Send a message to the agent's INBOX.md. The agent reads this on its next iteration.
curl -X POST http://localhost:8420/api/agents/a1b2c3d4e5f6/message \
-H "Content-Type: application/json" \
-d '{"text": "Try adding RSI divergence as a feature"}'{"status": "sent"}Read the agent's current INBOX.md contents.
curl http://localhost:8420/api/agents/a1b2c3d4e5f6/inbox{"content": "[14:30] Operator: Try adding RSI divergence as a feature"}Replace the agent's INBOX.md content entirely.
curl -X POST http://localhost:8420/api/agents/a1b2c3d4e5f6/inbox \
-H "Content-Type: application/json" \
-d '{"content": "New instructions here"}'{"status": "ok"}Get the chat history (operator messages + Ask Claude responses).
curl http://localhost:8420/api/agents/a1b2c3d4e5f6/chat{
"messages": [
{"role": "user", "text": "How is AUC trending?", "ts": "2026-03-26T14:30:00", "type": "ask"},
{"role": "assistant", "text": "AUC improved from 0.51 to 0.54 over...", "ts": "2026-03-26T14:30:05", "type": "ask"}
],
"paused": false
}Ask Claude a question about the agent's current state. Response appears in the chat asynchronously.
curl -X POST http://localhost:8420/api/agents/a1b2c3d4e5f6/ask \
-H "Content-Type: application/json" \
-d '{"text": "What features are contributing most to AUC?"}'{"status": "processing"}Poll GET /api/agents/<id>/chat to see the response when ready.
Get the agent's notes.txt (maintained by the agent itself).
curl http://localhost:8420/api/agents/a1b2c3d4e5f6/notes{"content": "Iteration 3: RSI feature improved AUC by 0.02..."}Get the agent's STATE.md (structured state the agent maintains).
curl http://localhost:8420/api/agents/a1b2c3d4e5f6/state{"content": "# Current State\n\nBest AUC: 0.542 (iteration 3)\n..."}Get the agent's raw stdout log.
| Param | Type | Default | Description |
|---|---|---|---|
tail |
query | 200 |
Number of lines from the end (1-5000) |
curl "http://localhost:8420/api/agents/a1b2c3d4e5f6/stdout?tail=50"{
"content": "[iter 3] calling claude (sonnet)...\n reading: notes.txt\n...",
"lines": 450,
"showing": 50
}Get all iteration results for an agent.
curl http://localhost:8420/api/agents/a1b2c3d4e5f6/iterations{
"count": 3,
"iterations": [
{
"iteration": 1,
"timestamp": "2026-03-26T12:05:00",
"metrics": {"mean_auc": 0.512},
"analysis": {
"feature_report": [...],
"inference_spec": {
"summary": "Uses 10m and 60m momentum with Bollinger band width...",
"data_requirements": [{"field": "close", "source": "Binance OHLCV", ...}],
"update_frequency": "Every 1 minute",
"output_format": "2-element array [p_up, p_down]",
"dependencies": ["numpy"]
},
"hypothesis": "...",
"done": false
},
"has_error": false,
"elapsed_s": 45.2,
"tokens": {"input": 12000, "output": 3500, "cost": 0.0234},
"done_signal": false,
"timed_out": false
}
]
}Get the Python source code from a specific iteration.
curl http://localhost:8420/api/agents/a1b2c3d4e5f6/code/3Returns text/plain with the source code. Returns 404 if the iteration has no code file.
Get the agent's feature report for a specific iteration. The agent writes this as part of its analysis.
curl http://localhost:8420/api/agents/a1b2c3d4e5f6/iterations/3/features{
"iteration": 3,
"feature_report": [
{
"name": "momentum_10m",
"description": "10-minute log return",
"signal": "Mean-reversion indicator",
"importance_rank": 1,
"stats": {"mean": 0.001, "std": 0.023, "min": -0.12, "max": 0.15},
"predictive_power": {
"method": "spearman vs fwd returns",
"value": 0.05,
"p_value": 0.02,
"n_samples": 500,
"interpretation": "Weak but statistically significant"
}
}
]
}The feature_report is written by the agent, not computed automatically. If the agent hasn't written a feature report for an iteration, the array will be empty.
Get metrics and analysis for a specific iteration.
curl http://localhost:8420/api/agents/a1b2c3d4e5f6/iterations/3/metrics{
"iteration": 3,
"metrics": {"mean_auc": 0.542, "windows": [...]},
"analysis": {"summary": "...", "done": false}
}Check if Anthropic API key is configured. Never returns the full key.
curl http://localhost:8420/api/anthropic-key{"set": true, "masked": "sk-ant-a...xY9z"}Set the Anthropic API key. Must start with sk-ant-.
curl -X POST http://localhost:8420/api/anthropic-key \
-H "Content-Type: application/json" \
-d '{"key": "sk-ant-api03-..."}'{"set": true, "masked": "sk-ant-a...xY9z"}Remove the stored Anthropic API key.
curl -X DELETE http://localhost:8420/api/anthropic-key{"set": false}Check if CoinGlass API key is configured.
curl http://localhost:8420/api/coinglass-key{"set": true, "masked": "abc123...xY9z"}Set the CoinGlass API key. Alphanumeric, hyphens, underscores, and dots only.
curl -X POST http://localhost:8420/api/coinglass-key \
-H "Content-Type: application/json" \
-d '{"key": "your-coinglass-key"}'{"set": true, "masked": "your-c...s-key"}Remove the stored CoinGlass API key.
curl -X DELETE http://localhost:8420/api/coinglass-key{"set": false}Check cache status for all standard lookback windows.
curl http://localhost:8420/api/data-cache{
"60": {"cached": true, "assets": 29, "has_coinglass": true, "age_hours": 2.3},
"90": {"cached": false},
"120": {"cached": false},
"180": {"cached": false}
}Start background data fetch. Fetches OHLCV from Binance and optionally CoinGlass derivatives data.
| Field | Type | Default | Description |
|---|---|---|---|
days_back |
int | 60 |
Days of history to fetch (min 60, max 365) |
coinglass_key |
string | (stored key) | CoinGlass API key (auto-saved if provided) |
curl -X POST http://localhost:8420/api/data-cache/prefetch \
-H "Content-Type: application/json" \
-d '{"days_back": 60}'{"status": "started", "days_back": 60}Returns 409 if a fetch is already running.
Check progress of a running prefetch.
curl http://localhost:8420/api/data-cache/status{
"running": true,
"progress": "Fetching OHLCV: 15/29 assets",
"step": 15,
"total_steps": 29,
"error": null,
"finished_at": null
}Delete cached data for a specific lookback window.
| Field | Type | Default | Description |
|---|---|---|---|
days_back |
int | 60 |
Which cache to delete |
curl -X POST http://localhost:8420/api/data-cache/delete \
-H "Content-Type: application/json" \
-d '{"days_back": 60}'{"status": "deleted", "days_back": 60}Returns 409 if a prefetch is currently running.
All errors return JSON with an error field:
{"error": "description of what went wrong"}| Status | Meaning |
|---|---|
400 |
Bad request (missing/invalid parameters) |
401 |
Unauthorized (auth token required) |
403 |
Forbidden (wrong token or CSRF violation) |
404 |
Not found (agent or resource doesn't exist) |
429 |
Rate limited or max agents reached |
409 |
Conflict (e.g. deleting cache while fetch is running) |
By default, each IP is limited to 120 requests per minute (sliding window). Configure with MANTIS_RATE_LIMIT_RPM environment variable. Set to 0 to disable.