Three commands and one HTTP call gets a character talking. Every
response below was captured from a live service while this page was generated,
against cyberpunk-block.
pip install -e .
Python 3.10 or newer. No third-party packages: the install pulls nothing, which is why it works behind a studio firewall and in a locked build environment.
unscripted serve --world-pack worldpacks/cyberpunk-block --auth-token dev
Binding off loopback without a token is refused rather than warned about. For a shipping build, add --no-debug-endpoints: /state/* exposes every character's private beliefs, which is what makes the debug HUD useful and what a game client must not have.
curl -s localhost:8765/v2/avatar/turn -H "Authorization: Bearer dev" -H "Content-Type: application/json" -d '{"text": "ask Dima about clinic"}'One call. The response below is the real one, captured while this page was generated.
GET /capabilities200{
"runtime_version": "1.21.0",
"contract_versions": [
"1.0.0",
"2.0.0"
],
"default_contract": "1.0.0",
"capabilities": {
"semantic_moves": true,
"deception": true,
"retrospective_revision": true,
"... 13 more": "..."
}
}A capability that is false means the feature is absent, not that it produced nothing this turn. Refuse to start if the runtime does not list a contract version you understand.
POST /v2/avatar/turn {"text": "ask Dima about clinic"}200{
"world_time": 4334,
"location_id": "place:main_street",
"parsed": {
"raw_text": "ask Dima about clinic",
"intent": "ask",
"confidence": 0.86,
"actor_id": "agent:player_1",
"target_id": "agent:dima_broke",
"location_id": null,
"proposition": {
"predicate": "clinic_open",
"slots": {
"place": "place:clinic",
"when": "last_night"
},
"polarity": "-",
"valid_start": null,
"valid_end": null,
"spatial": null,
"degree": null
},
"amount": null,
"minutes": 0,
"topic": "clinic",
"metadata": {},
"reasons": [
[
"parser.ask",
0.86,
{
"target": "agent:dima_broke",
"topic": "clinic"
}
]
]
},
"message": "Dima: \"I've got nothing for you.\"",
"observations": [],
"receipts": [
{
"event_id": 1002,
"event_type": "question",
"world_time": 4334,
"observed_by": [
"agent:barkeep_12",
"agent:corpo_okada",
"agent:dima_broke",
"agent:npc_red_jacket"
],
"reasons": {
"agent:barkeep_12": [
[
"memory.encoded",
0.45,
{
"content": "player asks about clinic",
"type": "episodic"
}
]
],
"agent:corpo_okada": [
[
"memory.encoded",
0.45,
{
"content": "player asks about clinic",
"type": "episodic"
}
]
],
"agent:dima_broke": [
[
"policy.selected",
-0.049,
{
"sampled_action": "answer_truthfully",
"top_rated_action": "greet",
"top_rated_utility": 0.589,
"stochastic": true,
"T": 0.378,
"selection_probs": [
[
"greet",
0.604
],
[
"evade",
0.259
],
[
"answer_truthfully",
0.112
],
[
"threaten",
0.025
]
],
"contributions": [
[
"relationship",
0.12,
1.2,
0.144
],
[
"safety",
-0.28,
1.12,
-0.314
],
[
"norm",
0.1,
1.21,
0.121
],
"... 2 more"
]
}
],
[
"validator.accept",
0.0,
{}
]
],
"agent:npc_red_jacket": [
[
"memory.encoded",
0.45,
{
"content": "player asks about clinic",
"type": "episodic"
}
]
]
}
}
],
"npc_response": {
"speaker_id": "agent:dima_broke",
"text": "I've got nothing for you.",
"act": "inform",
"verdict": "ACCEPT",
"utility": -0.049,
"reasons": [
[
"policy.selected",
-0.049,
{
"sampled_action": "answer_truthfully",
"top_rated_action": "greet",
"top_rated_utility": 0.589,
"stochastic": true,
"T": 0.378,
"selection_probs": [
[
"greet",
0.604
],
[
"evade",
0.259
],
[
"answer_truthfully",
0.112
],
[
"threaten",
0.025
]
],
"contributions": [
[
"relationship",
0.12,
1.2,
0.144
],
[
"safety",
-0.28,
1.12,
-0.314
],
[
"norm",
0.1,
1.21,
0.121
],
"... 2 more"
]
}
],
[
"validator.accept",
0.0,
{}
]
],
"style": {
"formality": 0.389,
"lexical_sophistication": 0.185,
"mean_sentence_length": 8.798,
"slang_level": 0.0,
"directness": 0.572,
"hedging": 0.233,
"dialect": null,
"jargon_domain": "street",
"slang_lexicon": null,
"politeness_strategy": "positive"
}
},
"developer_trace": " affect of agent:dima_broke:\n mood PAD: valence=-0.15 arousal=-0.23 dominance=+0.07 (baseline -0.15/-0.23/+0.07)\n active emotions: (calm)\n stress: 0.00\n beliefs of agent:dima_broke:\n (none)\n memory of agent:dima_broke @ t=4334:\n [episodic ] player asks about clinic\n activation=0.00 (faint) importance=0.45 valence=+0.00 source_conf=0.77\n last reason trace for agent:dima_broke:\n policy.selected -0.049 {'sampled_action': 'answer_truthfully', 'top_rated_action': 'greet', 'top_rated_utility': 0.589, 'stochastic': True, 'T': 0.378, 'selection_probs': [('greet', 0.604), ('evade', 0.259), ('answer_truthfully', 0.112), ('threaten', 0.025)], 'contributions': [('relationship', 0.12, 1.2, 0.144), ('safety', -0.28, 1.12, -0.314), ('norm', 0.1, 1.21, 0.121), ('tom', 0.0, 1.0, 0.0), ('emotion_tendency', 0.0, 1.0, 0.0)]}\n validator.accept +0.000 {}",
"done": false,
"avatar": {
"speaker_id": "agent:dima_broke",
"text": "I've got nothing for you.",
"act": "inform",
"verdict": "ACCEPT",
"utility": -0.049,
"style": {
"formality": 0.389,
"lexical_sophistication": 0.185,
"mean_sentence_length": 8.798,
"slang_level": 0.0,
"directness": 0.572,
"hedging": 0.233,
"dialect": null,
"jargon_domain": "street",
"slang_lexicon": null,
"politeness_strategy": "positive"
},
"reasons": [
[
"policy.selected",
-0.049,
{
"sampled_action": "answer_truthfully",
"top_rated_action": "greet",
"top_rated_utility": 0.589,
"stochastic": true,
"T": 0.378,
"selection_probs": [
[
"greet",
0.604
],
[
"evade",
0.259
],
[
"answer_truthfully",
0.112
],
[
"threaten",
0.025
]
],
"contributions": [
[
"relationship",
0.12,
1.2,
0.144
],
[
"safety",
-0.28,
1.12,
-0.314
],
[
"norm",
0.1,
1.21,
0.121
],
"... 2 more"
]
}
],
[
"validator.accept",
0.0,
{}
]
],
"honesty": "honest",
"asserted": [],
"emotion": {
"dominant": "downcast",
"intensity": 0.154,
"valence": -0.154,
"arousal": -0.231,
"dominance": 0.073,
"active": {}
},
"blendshapes": {
"browInnerUp": 0.0385,
"mouthFrownLeft": 0.0462,
"mouthFrownRight": 0.0462
},
"gaze": {
"target": "agent:player_1",
"aversion": 0.0,
"make_contact": true
},
"prosody": {
"speech_rate": 0.931,
"pitch_shift": -0.057,
"loudness": 0.419
},
"posture": "neutral"
},
"contract_version": "2.0.0"
}`text` is the line. `honesty` is the runtime's own record of whether it matched what the speaker believes — never infer that from the prose. `asserted` is what the line committed the character to, and who was close enough to hear it. The face and prosody blocks drive an avatar and a voice.
GET /v2/state/knowledge200{
"world_time": 4334,
"time_of_day": "00:14",
"facts": [
{
"key": "clinic_open(place=place:clinic,when=last_night)[None,None,None]",
"text": "clinic_open(place=place:clinic, when=last_night)",
"predicate": "clinic_open",
"detail": 2,
"holders": [
{
"agent": "agent:barkeep_12",
"name": "Honce",
"prob": 0.1995,
"confidence": 0.8005,
"hops": 0,
"origin": "seed_bar_clinic",
"times_heard": 1,
"independent_origins": 1
},
{
"agent": "agent:officer_kane",
"name": "Officer Kane",
"prob": 0.1935,
"confidence": 0.8065,
"hops": 0,
"origin": "seed_kane_clinic",
"times_heard": 1,
"independent_origins": 1
},
{
"agent": "agent:npc_red_jacket",
"name": "Vee",
"prob": 0.212,
"confidence": 0.788,
"hops": 0,
"origin": "seed_vee_clinic",
"times_heard": 1,
"independent_origins": 1
}
],
"origins": [
"seed_bar_clinic",
"seed_kane_clinic",
"seed_vee_clinic"
],
"reach": 3,
"first_hand": 3,
"hearsay": 0,
"max_hops": 0
},
{
"key": "was_at(agent=agent:corpo_okada,place=place:clinic,when=last_night)[None,None,None]",
"text": "was_at(agent=agent:corpo_okada, place=place:clinic, when=last_night)",
"predicate": "was_at",
"detail": 3,
"holders": [
{
"agent": "agent:corpo_okada",
"name": "Mr. Okada",
"prob": 0.8005,
"confidence": 0.8005,
"hops": 0,
"origin": "seed_okada_visit",
"times_heard": 1,
"independent_origins": 1
}
],
"origins": [
"seed_okada_visit"
],
"reach": 1,
"first_hand": 1,
"hearsay": 0,
"max_hops": 0
},
{
"key": "was_at(agent=agent:officer_kane,place=place:clinic,when=last_night)[None,None,None]",
"text": "was_at(agent=agent:officer_kane, place=place:clinic, when=last_night)",
"predicate": "was_at",
"detail": 3,
"holders": [
{
"agent": "agent:barkeep_12",
"name": "Honce",
"prob": 0.7905,
"confidence": 0.7905,
"hops": 0,
"origin": "seed_bar_kane",
"times_heard": 1,
"independent_origins": 1
}
],
"origins": [
"seed_bar_kane"
],
"reach": 1,
"first_hand": 1,
"hearsay": 0,
"max_hops": 0
},
{
"key": "whereabouts(who=agent:npc_red_jacket,place=place:bar_back)[None,None,None]",
"text": "whereabouts(who=agent:npc_red_jacket, place=place:bar_back)",
"predicate": "whereabouts",
"detail": 2,
"holders": [
{
"agent": "agent:corpo_okada",
"name": "Mr. Okada",
"prob": 0.868,
"confidence": 0.868,
"hops": 0,
"origin": "seed_okada_hid_milan",
"times_heard": 1,
"independent_origins": 1
}
],
"origins": [
"seed_okada_hid_milan"
],
"reach": 1,
"first_hand": 1,
"hearsay": 0,
"max_hops": 0
}
],
"stories": [],
"transmissions": [],
"knowledge_classes": [
{
"predicate": "clinic_open",
"classification": "common",
"domain": "street",
"access": [],
"locality": [],
"transmissibility": 0.85
},
{
"predicate": "connected_to_attack",
"classification": "common",
"domain": "street",
"access": [],
"locality": [],
"transmissibility": 0.85
},
{
"predicate": "whereabouts",
"classification": "common",
"domain": "street",
"access": [],
"locality": [],
"transmissibility": 0.85
}
],
"circles": [
{
"circle": "district:corpo_plaza",
"members": [
"agent:corpo_okada"
]
},
{
"circle": "district:watson",
"members": [
"agent:barkeep_12",
"agent:dima_broke",
"agent:npc_red_jacket",
"agent:pavel"
]
},
{
"circle": "faction:badges",
"members": [
"agent:officer_kane"
]
},
"... 11 more"
],
"bridges": [
{
"agent": "agent:barkeep_12",
"name": "Honce",
"circles": [
"district:watson",
"place:bar",
"role:bartender",
"role:service"
]
},
{
"agent": "agent:corpo_okada",
"name": "Mr. Okada",
"circles": [
"district:corpo_plaza",
"group:arasaka",
"role:officer"
]
},
{
"agent": "agent:npc_red_jacket",
"name": "Vee",
"circles": [
"district:watson",
"family:k",
"group:reds",
"role:fixer"
]
},
"... 2 more"
],
"contested": [],
"judgements": [],
"occupancy": [
{
"place": "place:bar",
"label": "Bar",
"people": [
{
"id": "agent:son_marko",
"name": "Marko"
}
]
},
{
"place": "place:main_street",
"label": "Main Street",
"people": [
{
"id": "agent:dima_broke",
"name": "Dima"
},
{
"id": "agent:barkeep_12",
"name": "Honce"
},
{
"id": "agent:corpo_okada",
"name": "Mr. Okada"
},
"... 2 more"
]
},
{
"place": "place:market",
"label": "Market",
"people": [
{
"id": "agent:son_ilya",
"name": "Ilya"
},
{
"id": "agent:pavel",
"name": "Pavel"
}
]
},
{
"place": "place:police_post",
"label": "Police Post",
"people": [
{
"id": "agent:officer_kane",
"name": "Officer Kane"
}
]
}
],
"contract_version": "2.0.0"
}The debug HUD lives here: stories grouped by incident, who is a bridge between circles, which claims are contested. Turn it off for a shipping client.
GET /v2/actions/pending200{
"intents": [],
"bridge": {
"enabled": true,
"issued": 0,
"pending": 0,
"... 6 more": "..."
},
"contract_version": "2.0.0"
}Empty here because no world time has passed yet. When a routine moves somebody, an intent appears and the character does NOT move until you report the result — that is how the simulation and the screen are kept from disagreeing.
POST /advance {"minutes": -30}400{
"error": "'minutes' must be >= 0, got -30.",
"code": "minutes_out_of_range"
}World time is monotonic; rewinding it would corrupt every memory activation. Client mistakes come back as typed 4xx with a code you can branch on, never as a 500 or a silently broken world.