API docs
One endpoint for Kev and Strands Decider. Requests and answers follow the TypeSafe SystemOne shapes.
Quickstart
curl https://api.decider.cloud/v1/systemone \
-H 'Content-Type: application/json' \
-d '{
"model": "kev-4b",
"state": "Our payment service has been down for three hours.",
"questions": {
"urgent": {
"type": "noul",
"instructions": "Is this urgent?"
}
}
}'{
"model": "kev-4b",
"answers": {
"urgent": {
"type": "noul",
"noul": 0.68235
}
},
"usage": {
"input_tokens": 23,
"output_tokens": 19
},
"latency_ms": 143.59
}The first request after the API has been idle can take about 30 seconds while the models load. Later requests return in well under a second.
Public preview
The hosted API is free while it is in public preview. It runs on a single shared GPU with a fixed monthly compute budget, so treat it as a place to prototype, evaluate, and research, not as production infrastructure.
- No uptime guarantee. Availability is best-effort. The API can be slow, busy, or down, and there is no SLA.
- Shared capacity. One inference runs at a time across all users. Expect
429responses when it is busy. - Fixed budget. If the monthly compute budget runs out, the API stops responding until it resets.
- Things can change. Models, limits, and the preview itself can change or end.
- Your data. Request content is never stored. Decider logs only the model name and timing of each request. Requests do pass through Cloudflare and Modal, so don’t send personal or confidential data.
Both models are open source: Kev and Strands Decider.
Need guaranteed capacity or a private deployment? Message me on X about running Decider on your own compute.
Request
POST/v1/systemone
| Field | Type | Description |
|---|---|---|
model | string | kev-4b or strands-decider-2b. |
state | string, object, or array | The context every question is asked about. Can’t be empty. |
questions | object | One to eight questions, keyed by names you choose. Answers come back under the same keys. |
Every question has a type, instructions(string, object, or array), and, depending on the type,criteria. Unknown fields are rejected.
Question types
noul
Returns noul, the probability that the answer is true. Optional criteria describe what true andfalse mean.
{
"urgent": {
"type": "noul",
"instructions": "Is this urgent?",
"criteria": {
"true": "Customers are blocked right now",
"false": "Nothing is blocked"
}
}
}choice
criteria maps 1 to 255 option names to descriptions, or tonull. Returns the choice, a probability for every option, and a confidence. Ties go to the first option listed.
{
"route": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"engineering": "Production outages and technical failures",
"billing": "Invoices and payment questions",
"sales": null
}
}
}{
"probabilities": {
"engineering": 0.91147,
"billing": 0.082139,
"sales": 0.006391
},
"confidence": 0.867204,
"type": "choice",
"choice": "engineering"
}score
criteria is an ordered list of 2 to 10 level descriptions. Returns score, the expected zero-based level, which can fall between levels. Also returns per-level probabilities, aconfidence, and a legend.
{
"severity": {
"type": "score",
"instructions": "How severe is this incident?",
"criteria": [
"Minor inconvenience",
"Service is degraded",
"Customers cannot make payments"
]
}
}{
"probabilities": {
"0": 0.125318,
"1": 0.128191,
"2": 0.746491
},
"confidence": 0.43176,
"type": "score",
"score": 1.621173,
"legend": {
"0": "Minor inconvenience",
"1": "Service is degraded",
"2": "Customers cannot make payments"
}
}Response
| Field | Description |
|---|---|
model | The model that answered. |
answers | One answer per question, under the question’s key. |
usage | input_tokens counts rendered model tokens;output_tokens counts the serialized answers. |
latency_ms | Time spent on the GPU, including tokenization. Excludes network time and cold starts. |
Probabilities, noul, confidence, andscore have up to six decimal places. Each distribution sums to exactly 1, and the selected choice is computed before rounding.
Models and limits
| Limit | kev-4b | strands-decider-2b |
|---|---|---|
| Context per question | 12,288 tokens | 4,096 tokens |
| State | 8,192 tokens | Must fit beside the longest question |
| Single question | Within the context limit | 3,072 tokens |
| Warm runtime, p50 | 86 ms | 45 ms |
Both models accept up to 8 questions per request, 255 options per choice, 10 score levels, and a 256 KiB request body. Token counts include each model’s prompt formatting, so an input can fit Kev and still be too long for Strands. Inputs are never truncated; oversized context returns 422.
Errors
{
"error": {
"code": "busy",
"message": "GPU is busy; retry shortly"
}
}| Status | Code | What to do |
|---|---|---|
| 404 | model_not_found | Check the model field. |
| 413 | body_too_large | Keep the request body under 256 KiB. |
| 422 | invalid_request | Fix the fields listed in error.fields, or shorten input that exceeds the model’s context. |
| 429 | busy | Another request is running. Retry with backoff. |
| 500 | inference_failed | Retry once. If it repeats, the input may be the cause. |
| 503 | not_ready | The models are still loading. Retry shortly. |
429 and 503 responses includeRetry-After: 1. Validation errors list the failing field paths but never echo your input back.
Other endpoints
GET/v1/models
Lists the available models and their limits.
{
"models": [
{
"id": "kev-4b",
"provider": "kev",
"context_tokens": 12288,
"question_types": [
"noul",
"choice",
"score"
],
"max_questions": 8,
"max_choice_options": 255,
"max_score_levels": 10
},
{
"id": "strands-decider-2b",
"provider": "strands",
"context_tokens": 4096,
"question_types": [
"noul",
"choice",
"score"
],
"max_questions": 8,
"max_choice_options": 255,
"max_score_levels": 10
}
]
}GET/health
Returns {"status": "ok"} when both models are loaded, or 503 while they load. Calling it wakes the GPU, so don’t poll it continuously.
Compatibility
Request and answer shapes follow TypeSafe SystemOne. Decider is an independent implementation: predictions and confidence thresholds are not guaranteed to match TypeSafe, or each other across models.
Choice and score confidence use the TypeSafe reference formulas for both models. Choice confidence is(n × max(p) − 1) / (n − 1), or 1 for a single option. Strands rounds probabilities to four decimal places before Decider normalizes them.