Affordance extraction for embodied scenes. Given an object or situation description and a perspective, returns a structured list of affordances — actions, required capabilities, preconditions, expected outcomes, risks/side-effects, confidence. Suitable for agent planning, LLM tool-use filtering, or game-design analysis.
Speaks the OpenAI chat-completions API: works with OpenAI, OpenRouter (default), Ollama, Groq, Together, or any compatible backend.
docker run --rm -p 8000:8000 \
-e INSPECTOR_OPENAI_API_KEY=sk-or-... \
-e INSPECTOR_OPENAI_MODEL=anthropic/claude-sonnet-4.6 \
ghcr.io/openfantasymap/inspector:latestcurl -sS http://localhost:8000/inspect \
-H "content-type: application/json" \
-d '{
"obj": "a rusty iron sword, the hilt wrapped in worn leather",
"world_facts": "The Sword Coast of Faerûn, near Phandalin.",
"perspective": "a sixteen-year-old apprentice blacksmith",
"context": "the boy is alone in the back of the smithy after dusk"
}' | jq .Returns:
{
"affordances": [
{
"action": "strike with the flat",
"target": "an attacker at arm's reach",
"required_capabilities": ["strength", "intent"],
"preconditions": ["weapon held two-handed", "attacker within 1m"],
"expected_outcome": "stun or distract; will not cut through padded armour",
"possible_failure_modes": ["sword slips from grip", "miss"],
"confidence_level": "medium"
},
...
],
"model": "anthropic/claude-sonnet-4.6"
}Body:
{
"obj": "a rusty iron sword...",
"world_facts": "free-text narrative grounding (optional)",
"perspective": "who is doing the analysis (default: \"Human adult\")",
"context": "current situation (default: \"generic\")",
"model": "optional model override",
"temperature": 0.7
}Returns {"affordances": [...], "model": "..."}. If the model returns
invalid JSON the response is HTTP 502 with the diagnostic in detail.
Each entry in affordances is a dict with these fields (the model is
asked to populate them; missing fields are acceptable):
| field | meaning |
|---|---|
action |
the verb / what is done |
target |
what the action is performed on |
applies_to |
the subset of the object the affordance applies to |
combination_of |
other affordances this composes |
required_capabilities |
skills / tools the agent must have |
preconditions |
what must be true beforehand |
constraints |
physical / social / legal / cultural limits |
expected_outcome |
the intended result |
possible_failure_modes |
how it can go wrong |
confidence_level |
one of high / medium / low |
Returns {"status": "ok"} once env is validated.
| Env | Required | Default | Purpose |
|---|---|---|---|
INSPECTOR_OPENAI_API_KEY |
yes | — | OpenAI-compatible API key. |
INSPECTOR_OPENAI_MODEL |
yes | — | Default model id. |
INSPECTOR_OPENAI_BASE_URL |
no | https://openrouter.ai/api/v1 |
Override for any OpenAI-compatible endpoint. |
INSPECTOR_TEMPERATURE |
no | 0.7 |
Default sampling temperature. |
INSPECTOR_HOST |
no | 0.0.0.0 |
Bind address. |
INSPECTOR_PORT |
no | 8000 |
Bind port. |
python -m venv .venv && . .venv/bin/activate
pip install -e .[test]
pytest
uvicorn inspector.app:app --reloadDual-licensed under either of MIT or Apache-2.0, at your option.