--- title: "probe" description: "Runtime observability for actors" weight: 90 type: "docs" --- Runtime observability for actors. Register named probe functions on any actor and query them over HTTP while the program runs. ```javascript var probe = use('probe') ``` The probe server starts automatically on the first `register()` call, listening on `127.0.0.1:9000`. ## Registering Probes ### probe.register(target, probes) Register a group of probe functions under a target name. Each probe is a function that receives an `args` record and returns a value. ```javascript var probe = use('probe') var world = { entities: [ {id: 1, name: "player", x: 10, y: 20, hp: 100}, {id: 2, name: "goblin", x: 55, y: 30, hp: 40} ], tick: 0 } probe.register("game", { state: function(args) { return world }, entities: function(args) { return world.entities }, entity: function(args) { return find(world.entities, function(e) { return e.id == args.id }) } }) probe.register("render", { info: function(args) { return {fps: 60, draw_calls: 128, batches: 12} } }) ``` A target is just a namespace — group related probes under the same target name. Register as many targets as you like; the server starts once and serves them all. ## HTTP Endpoints All responses are JSON with an `ok` field. ### GET /discover Lists all registered targets and their probe names. Designed for tooling — an LLM or dashboard can call this first to learn what's available, then query specific probes. ``` $ curl http://127.0.0.1:9000/discover ``` ```json { "ok": true, "targets": { "game": ["state", "entities", "entity"], "render": ["info"] } } ``` ### POST /probe Call a single probe function by target and name. Optionally pass arguments. ``` $ curl -X POST -H "Content-Type: application/json" \ -d '{"target":"game","name":"state"}' \ http://127.0.0.1:9000/probe ``` ```json { "ok": true, "result": { "entities": [ {"id": 1, "name": "player", "x": 10, "y": 20, "hp": 100}, {"id": 2, "name": "goblin", "x": 55, "y": 30, "hp": 40} ], "tick": 4821 } } ``` With arguments: ``` $ curl -X POST -H "Content-Type: application/json" \ -d '{"target":"game","name":"entity","args":{"id":1}}' \ http://127.0.0.1:9000/probe ``` ```json { "ok": true, "result": {"id": 1, "name": "player", "x": 10, "y": 20, "hp": 100} } ``` ### POST /snapshot Call multiple probes in one request. Returns all results keyed by `target/name`. ``` $ curl -X POST -H "Content-Type: application/json" \ -d '{"probes":[{"target":"game","name":"state"},{"target":"render","name":"info"}]}' \ http://127.0.0.1:9000/snapshot ``` ```json { "ok": true, "results": { "game/state": { "entities": [ {"id": 1, "name": "player", "x": 10, "y": 20, "hp": 100}, {"id": 2, "name": "goblin", "x": 55, "y": 30, "hp": 40} ], "tick": 4821 }, "render/info": { "fps": 60, "draw_calls": 128, "batches": 12 } } } ``` ### Errors Unknown paths return 404: ```json {"ok": false, "error": "not found"} ``` Unknown targets or probe names: ```json {"ok": false, "error": "unknown probe: game/nonexistent"} ``` If a probe function disrupts: ```json {"ok": false, "error": "probe failed"} ``` ## Example A game actor with a simulation loop and probe observability: ```javascript // game.ce var probe = use('probe') var state = { entities: [ {id: 1, name: "player", x: 0, y: 0, hp: 100}, {id: 2, name: "enemy", x: 50, y: 50, hp: 60} ], frame: 0, paused: false } probe.register("game", { state: function(args) { return state }, entities: function(args) { return state.entities }, entity: function(args) { return find(state.entities, function(e) { return e.id == args.id }) } }) // game loop def tick = function(_) { if (!state.paused) { state.frame = state.frame + 1 // ... update entities, physics, AI ... } $delay(tick, 0.016) } $delay(tick, 0.016) ``` While the game runs, query it from a terminal: ``` $ curl -s http://127.0.0.1:9000/discover | jq .targets { "game": ["state", "entities", "entity"] } $ curl -s -X POST -d '{"target":"game","name":"state"}' \ -H "Content-Type: application/json" \ http://127.0.0.1:9000/probe | jq .result.frame 7834 $ curl -s -X POST -d '{"target":"game","name":"entity","args":{"id":1}}' \ -H "Content-Type: application/json" \ http://127.0.0.1:9000/probe | jq .result { "id": 1, "name": "player", "x": 142, "y": 87, "hp": 100 } ``` Probes run inside the actor's normal turn, so the values are always consistent — never a half-updated frame.