Introspection
Discover every dispatch command the running binary exposes. Useful
for external tooling that wants to enumerate the surface without a
code-walk through api_dispatch.rs.
GET /api/commands
Auth: bearer.
Response (200):
{
"commands": [
"account_creator_accounts",
"bot_accept_friend",
"bot_active_worlds",
"bot_add_friend",
"bot_chat",
"bot_drop",
"bot_walk_to",
"catalog_block_types",
"catalog_item_database",
"catalog_pack_pool",
"connect_bot",
"disconnect_bot",
"join_world",
"leave_world",
"list_bots",
"seraph_execute",
"spawn_bot_email",
"..."
]
}
The list is alphabetical and reflects the exact set of names that
POST /invoke accepts as cmd. Adding a feature mid-release rotates
this list automatically — the introspection endpoint reads
s.handlers.keys() directly, no manifest to keep in sync.
Calling a discovered command
Every name returned here is reachable via the universal dispatch endpoint:
curl -s -X POST http://localhost:8090/invoke \
-H 'authorization: Bearer <token>' \
-H 'content-type: application/json' \
-d '{"cmd":"<name>","args":<args>}'
<args> is whatever shape the corresponding handler expects. For
zero-arg handlers, send null or {}. For per-bot commands the
common shape is {"id":"bot-1"}. The full argument schema lives in
src-tauri/src/api_dispatch.rs — open the matching register0 /
register1 line and the struct after register1::<...>.
REST sugar vs /invoke
The REST sugar routes (/api/bots/{id}/*, /api/scripts/*, etc.)
are thin wrappers that forward to the dispatcher. Anything they do,
/invoke can do too. If you want to drive every bot from one
generic client, point at /invoke and skip the sugar entirely.