{"name":"singing_bird","version":"0.3.0","description":"Control plane for the Singing Bird embodied simulation kernel","tool_count":46,"tools":[{"name":"list_sessions","method":"GET","path":"/v1/sessions","scope":"read","kind":"read","idempotent":true,"description":"List all active simulation sessions.\n\nReturns session_id, scenario_path, created_at, and paused state for each.\nUse before create_session to see what is already running, or to pick a\nsession_id for ot"},{"name":"create_session","method":"POST","path":"/v1/sessions","scope":"operate","kind":"mutate","idempotent":false,"description":"Start a new simulation from a scenario pack.\n\nIdentify the scenario via `scenario_ref` (preferred) or `scenario_path`\n(legacy alias). Both accept id, filename stem, or a path — all normalize.\nCall lis"},{"name":"get_session","method":"GET","path":"/v1/sessions/{session_id}","scope":"read","kind":"read","idempotent":true,"description":"Get a single session's current state — same shape as get_overview.\n\nExists for REST-idiomatic lookup-by-id; prefer get_overview when you\nare calling by session_id anyway, or list_sessions for discover"},{"name":"close_session","method":"DELETE","path":"/v1/sessions/{session_id}","scope":"operate","kind":"destructive","idempotent":true,"description":"Close a session and release its resources.\n\nDestroys the session's in-memory state. If you may want to go back,\ntake or reference a snapshot first (list_snapshots + restore_snapshot)."},{"name":"get_scenario","method":"GET","path":"/v1/scenarios/{scenario_id}","scope":"read","kind":"read","idempotent":true,"description":"Inspect a scenario pack in detail.\n\nscenario_id accepts id, filename stem, or a scenario_path — all\nnormalize to the same scenario.\n\nview modes (use view='authoring' when you plan to edit and write ba"},{"name":"update_scenario","method":"PUT","path":"/v1/scenarios/{scenario_id}","scope":"operate","kind":"destructive","idempotent":true,"description":"Full replace. The body `content` must match the authoring shape from\nget_scenario(view='authoring') — i.e. the raw YAML dict with\nworld.topology.locations, world.entities, synths, profiles, etc. (NOT\n"},{"name":"delete_scenario","method":"DELETE","path":"/v1/scenarios/{scenario_id}","scope":"operate","kind":"destructive","idempotent":true,"description":"Removes a user-authored scenario. Shipped scenarios cannot be deleted —\nfork them first if you want a deletable copy. Accepts scenario_id (id,\nfilename stem, or scenario_path — all normalize to the sa"},{"name":"list_scenarios","method":"GET","path":"/v1/scenarios","scope":"read","kind":"read","idempotent":true,"description":"List scenario packs available on disk.\n\nMetadata-only — no world is loaded. Use before create_session to\ndiscover what simulations can be started; pass a returned path\nas the scenario_path argument to"},{"name":"create_scenario","method":"POST","path":"/v1/scenarios","scope":"operate","kind":"mutate","idempotent":false,"description":"Author a new scenario. If content is omitted a minimal valid scaffold\n(one location, no entities, no synths) is written so you can fill it in\npiece by piece with the component-level add_* tools.\n\nPass"},{"name":"fork_scenario","method":"POST","path":"/v1/scenarios/{scenario_id}/fork","scope":"operate","kind":"mutate","idempotent":false,"description":"Duplicate the source scenario under new_scenario_id. Optional overrides\nare merged at the top level (e.g. {\"random_seed\": 123}). scenario_id\naccepts id, filename stem, or a scenario_path — all normali"},{"name":"add_location","method":"POST","path":"/v1/scenarios/{scenario_id}/locations","scope":"operate","kind":"mutate","idempotent":false,"description":"Add a location to a scenario"},{"name":"replace_location","method":"PUT","path":"/v1/scenarios/{scenario_id}/locations/{loc_id}","scope":"operate","kind":"destructive","idempotent":true,"description":"Full replace. Every unsent field on the prior location is dropped.\nIf you only want to change a few fields, use patch_location."},{"name":"remove_location","method":"DELETE","path":"/v1/scenarios/{scenario_id}/locations/{loc_id}","scope":"operate","kind":"destructive","idempotent":true,"description":"Remove a location (and its adjacency edges)"},{"name":"patch_location","method":"PATCH","path":"/v1/scenarios/{scenario_id}/locations/{loc_id}","scope":"operate","kind":"mutate","idempotent":false,"description":"Deep-merge partial update. Fields you don't send are preserved.\nSend `{\"key\": null}` to delete a key. Returns the full location after\nthe merge, so you can see both the changed and unchanged fields.\n\n"},{"name":"add_entity","method":"POST","path":"/v1/scenarios/{scenario_id}/entities","scope":"operate","kind":"mutate","idempotent":false,"description":"Add an entity to a scenario (ruleset-validated)"},{"name":"replace_entity","method":"PUT","path":"/v1/scenarios/{scenario_id}/entities/{entity_id}","scope":"operate","kind":"destructive","idempotent":true,"description":"Full replace. Every unsent field on the prior entity is dropped.\nComponents are revalidated against the ruleset. Use patch_entity for\npartial updates."},{"name":"remove_entity","method":"DELETE","path":"/v1/scenarios/{scenario_id}/entities/{entity_id}","scope":"operate","kind":"destructive","idempotent":true,"description":"Remove an entity from a scenario"},{"name":"patch_entity","method":"PATCH","path":"/v1/scenarios/{scenario_id}/entities/{entity_id}","scope":"operate","kind":"mutate","idempotent":false,"description":"Deep-merge partial update. Fields you don't send are preserved.\nIf you include 'components', the whole list is replaced (list merging is\nambiguous). Returns the full entity after the merge.\n\nBody must"},{"name":"add_synth","method":"POST","path":"/v1/scenarios/{scenario_id}/synths","scope":"operate","kind":"mutate","idempotent":false,"description":"Add a synth. Required fields (id, entity, identity) are validated at\nthe edge; the full synth shape — identity, cognition, initial_state\n(affect, beliefs, projects, memories, mental_models) — is publi"},{"name":"replace_synth","method":"PUT","path":"/v1/scenarios/{scenario_id}/synths/{synth_id}","scope":"operate","kind":"destructive","idempotent":true,"description":"Full replace. Every unsent field on the prior synth is dropped. This is\nintentionally risky — use patch_synth when you only want to change a few\nfields (e.g. initial_state.beliefs)."},{"name":"remove_synth","method":"DELETE","path":"/v1/scenarios/{scenario_id}/synths/{synth_id}","scope":"operate","kind":"destructive","idempotent":true,"description":"Remove a synth from a scenario"},{"name":"patch_synth","method":"PATCH","path":"/v1/scenarios/{scenario_id}/synths/{synth_id}","scope":"operate","kind":"mutate","idempotent":false,"description":"Deep-merge partial update of one synth.\n\nBody must be `{\"patch\": {...}}` — wrap your merge under the `patch` key.\nExample to clear James's prior knowledge of the shore without losing\nhis identity, emb"},{"name":"add_adjacency","method":"POST","path":"/v1/scenarios/{scenario_id}/adjacency","scope":"operate","kind":"mutate","idempotent":false,"description":"Add an adjacency edge between two locations"},{"name":"remove_adjacency","method":"DELETE","path":"/v1/scenarios/{scenario_id}/adjacency","scope":"operate","kind":"destructive","idempotent":true,"description":"Remove an adjacency edge (by from+to)"},{"name":"list_snapshots","method":"GET","path":"/v1/sessions/{session_id}/snapshots","scope":"read","kind":"read","idempotent":true,"description":"List snapshots taken for a session.\n\nSnapshots are automatic checkpoints taken at cycle boundaries. Pair\nwith restore_snapshot to undo recent changes or roll back after a bad\npatch or an unintended st"},{"name":"diff_snapshots","method":"GET","path":"/v1/sessions/{session_id}/snapshots/diff","scope":"read","kind":"read","idempotent":true,"description":"Event-level diff between two persisted snapshots (RFC-0001).\n\nGeneralizes get_changes to arbitrary snapshot pairs: returns changed_refs,\nevent counts by type, event details, and compact summaries for "},{"name":"get_snapshot_overview","method":"GET","path":"/v1/sessions/{session_id}/snapshots/{snapshot_ref}/overview","scope":"read","kind":"read","idempotent":true,"description":"RFC-0001 tool #1: full world overview materialized from a past snapshot.\n\nSame shape as get_overview, but read from a persisted snapshot. The live\nsession is not modified — this is how you scrub throu"},{"name":"get_snapshot_object","method":"GET","path":"/v1/sessions/{session_id}/snapshots/{snapshot_ref}/objects/{kind}/{ref}","scope":"read","kind":"read","idempotent":true,"description":"RFC-0001 tool #2: object detail as of a persisted snapshot.\n\nSame shape as get_object. Returns 404 if the object did not exist yet at\nthat snapshot (e.g. an entity created at a later cycle). Read-only"},{"name":"restore_snapshot","method":"POST","path":"/v1/sessions/{session_id}/restore","scope":"operate","kind":"destructive","idempotent":false,"description":"Rewind a session to a previous snapshot — the undo button.\n\nReplaces the current session state with the snapshot; anything after\nthat point is discarded unless it was itself snapshotted. Get\nsnapshot_"},{"name":"step_session","method":"POST","path":"/v1/sessions/{session_id}/step","scope":"operate","kind":"mutate","idempotent":false,"description":"Advance the simulation by n cycles (default 1).\n\nEach cycle runs perception → cognition → intent resolution → commit:\nsynths observe their surroundings, decide, and act. Any stimuli queued\nvia queue_s"},{"name":"pause_session","method":"POST","path":"/v1/sessions/{session_id}/pause","scope":"operate","kind":"mutate","idempotent":false,"description":"Pause a session's auto-advance.\n\nStops any timed cycle loop; manual step_session calls still work.\nPair with resume_session to restart the loop."},{"name":"resume_session","method":"POST","path":"/v1/sessions/{session_id}/resume","scope":"operate","kind":"mutate","idempotent":false,"description":"Resume a session's auto-advance after pause_session.\n\nCycles run on the configured cadence. No-op if the session is already\nrunning."},{"name":"submit_turn","method":"POST","path":"/v1/sessions/{session_id}/turns","scope":"operate","kind":"mutate","idempotent":false,"description":"Inject an external event through the director and run a cycle.\n\nUse for in-world events: a spoken announcement, a narrated action, a\nscripted intervention from the operator. The event flows through th"},{"name":"get_overview","method":"GET","path":"/v1/sessions/{session_id}/overview","scope":"read","kind":"read","idempotent":true,"description":"Compact snapshot of the current session state.\n\nReturns synths (with brief status), environment, time, and locations —\nthe go-to call for a status update. Cheaper than inspecting individual\nobjects; u"},{"name":"resolve_ref","method":"GET","path":"/v1/sessions/{session_id}/resolve","scope":"read","kind":"read","idempotent":true,"description":"Resolve a human-readable name to its stable UUID ref.\n\nPass q (the name) and optionally kind (synth, entity, or location) to\nnarrow the search. Use before any tool that takes a ref argument —\nnotably "},{"name":"get_object","method":"GET","path":"/v1/sessions/{session_id}/objects/{kind}/{ref}","scope":"read","kind":"read","idempotent":true,"description":"Detailed view of a specific synth, entity, or location by ref.\n\nkind must be one of: synth, entity, location.\n- synth: beliefs, mood, memories, available actions.\n- entity: components, location, mobil"},{"name":"get_events","method":"GET","path":"/v1/sessions/{session_id}/events","scope":"read","kind":"read","idempotent":true,"description":"Raw audit events from the session since a sequence number.\n\nFull fidelity — every perception, thought, action, and world change.\nBest for detailed history or debugging. For a narrative summary, use\nge"},{"name":"get_changes","method":"GET","path":"/v1/sessions/{session_id}/changes","scope":"read","kind":"read","idempotent":true,"description":"Structured diff of world state: what refs changed and by how much.\n\nAggregated event counts, short summaries, and the set of changed refs —\nsince a given sequence cursor or against a snapshot (snapsho"},{"name":"get_last_cycle_report","method":"GET","path":"/v1/sessions/{session_id}/reports/last-cycle","scope":"read","kind":"read","idempotent":true,"description":"Narrative report of the most recent cycle.\n\nWorld events, synth speech and actions, belief changes, mood shifts —\nhuman-readable. Call after step_session to see what just happened.\nFor multiple cycles"},{"name":"get_report_since","method":"GET","path":"/v1/sessions/{session_id}/reports/since","scope":"read","kind":"read","idempotent":true,"description":"Narrative report spanning every cycle since a sequence cursor.\n\nLike get_last_cycle_report but multi-cycle — use to catch up after\nseveral steps without walking raw events. Returns summaries, event\nco"},{"name":"stream_events","method":"GET","path":"/v1/sessions/{session_id}/stream","scope":"read","kind":"read","idempotent":true,"description":"SSE event stream. Connect and receive events as they happen."},{"name":"apply_patch","method":"POST","path":"/v1/sessions/{session_id}/patches","scope":"admin","kind":"destructive","idempotent":false,"description":"Apply typed operations to mutate world state directly.\n\nBypasses the perception path — synths do NOT necessarily perceive\nthese changes. For things synths should sense (sounds, sights, smells),\nprefer"},{"name":"queue_stimulus","method":"POST","path":"/v1/sessions/{session_id}/stimuli","scope":"admin","kind":"mutate","idempotent":false,"description":"Queue an external stimulus for delivery through the perception path.\n\nStimuli are mediated: they enter through compose_sensory_bundle on the\nnext step or turn, so synths perceive them naturally — a so"},{"name":"check_llm_health","method":"GET","path":"/v1/health/llm","scope":"read","kind":"read","idempotent":true,"description":"Probe the LLM backend the synths would actually call.\n\nPer ADR-0001, silent cognition failure is an operational hazard. This\nendpoint surfaces reachability + TLS + auth state before anyone tries\nto st"},{"name":"get_tool_manifest","method":"GET","path":"/v1/tooling/manifest","scope":"read","kind":"read","idempotent":true,"description":"Tool manifest generated from the OpenAPI schema (the source of truth).\n\nLists every tool with name, method, path, scope, and description. The\nsame tool set is available over MCP at POST /mcp — MCP cli"},{"name":"get_api_call_log","method":"GET","path":"/v1/admin/logs","scope":"admin","kind":"read","idempotent":true,"description":"Search the API request/response audit log.\n\nEvery HTTP request (REST, MCP, dashboard) produces one JSONL record at\ndata/audit/api_calls.jsonl. MCP JSON-RPC messages produce a second record\nwith type=\""}]}