This page is the day-to-day operator handbook for running Binions with binions-cliconsole. It walks through the jobs you actually do every day — checking that the platform is healthy, editing and reloading playbooks, watching the internal event stream, and injecting events by hand — with real commands you can copy. For a field-by-field reference of the tool itself, see cliconsole-service; this page is task-oriented.
Good to know.
binions-cliconsoleis a short-lived command, not a background service — each invocation connects, does one thing, and exits. It runs locally on the Binions host and talks only tolocalhost, so you use it over SSH (or at the console), never across the network.
Binions is event-driven: services exchange Action, Fact, Log, and Control events over a fast internal bus, and playbooks turn those events into work. binions-cliconsole is your window onto that machinery. A typical admin session follows the same rhythm:
emit-control command does the job.Every command is one of the subcommands below. Two of them — status and validate — are read-only and never publish anything to the bus; the rest connect to the per-service Redis and write a single event.
| Subcommand | What it does | Touches the bus? |
|---|---|---|
status | Health roll-up of every daemon, as one table | No (HTTP health probes) |
validate <file> | Offline shape-check of a playbook YAML file | No (reads a local file) |
emit-control <Control…> | Send a runtime control event to a daemon | Yes (writes one event) |
ls events | Print the most recent N events from a stream | Reads only |
emit <Action|Fact|Log…> | Inject a single event into its stream | Yes (writes one event) |
schema | Export the playbook JSON Schema for your editor | No (prints to stdout) |
binions-cliconsole status is the everyday “is Binions OK?” command. It discovers every installed daemon, probes each one’s readiness endpoint over the loopback interface, and renders a single table — service, the URL it probed, the state it found, and how long the probe took:
binions-cliconsole status
service url state latency
─────────────── ─────────────────────────────────── ────────────── ───────
logger http://127.0.0.1:9100/health/ready UP (200) 8 ms
database http://127.0.0.1:9102/health/ready UP (200) 640 ms
playbook http://127.0.0.1:9108/health/ready UP (200) 710 ms
mailbox http://127.0.0.1:9107/health/ready UP (200) 690 ms
webhookcaller http://127.0.0.1:9109/health/ready DOWN (refused) 0 ms
Read the state column like this:
The readiness check does real work — it pings each daemon’s own Redis — so a healthy latency of a few hundred milliseconds is normal, not a warning. The default per-probe timeout is generous; tighten it for fast scripted checks with --timeout-ms:
# Default timeout (1500 ms) — use this interactively.
binions-cliconsole status
# Snappy timeout for a CI or cron health gate.
binions-cliconsole status --timeout-ms 800
Tip.
statusfinds daemons automatically — it scans the installed services and probes whatever it discovers. Install a new daemon and it shows up in the table on the next run, with no change to the tool. (cliconsoleitself is a CLI, so it is intentionally absent from the list.)
If a service shows DOWN or DEGRADED, move on to the journal and the systemd unit — see Health checks and systemd operations.
Playbooks are short YAML files. The safe way to change one is a simple loop that never restarts a daemon: edit the file, shape-check it offline, then save it into the live folder — the playbook engine picks up new and changed files automatically within a couple of seconds. For an immediate reload without waiting, use emit-control as described in the next section.
binions-cliconsole validate <file> parses a playbook and checks its shape without connecting to anything — pure local file work. It confirms the document has a name, a parseable trigger event, at least one step, and that each step uses exactly one of run:, parallel:, loop:, or wait_for:. A clean file prints one line:
binions-cliconsole validate /etc/binions/playbooks/invoice-intake.yaml
OK — invoice-intake (no violations)
A broken file lists every problem with a precise locator, and the command exits with a non-zero status — which is exactly what you want in a script or a pre-deploy check:
FAIL — invoice-intake (2 violations)
• trigger.event: invalid event type: event type must have form '<Kind>.<Domain>.<Name>', got 'NewEmail'
• steps[2]: must use exactly one of run, parallel, loop or wait_for
This is a shape check — it catches authoring typos (a missing field, the wrong event format, a step that uses none of the four valid variants) before they reach the engine. The four step types cover the full range of what a playbook can express:
run: — invoke one daemon operation; in saga mode the run waits for the response fact before the next step.parallel: — a single-level block of run: steps that fire at once (no nesting, no loops inside).loop: — bounded counted iteration; the body contains plain run: steps.wait_for: — in async mode, block until a specific response fact arrives (the join half of a fire-and-forget fan-out).A small, well-formed playbook looks like this:
name: invoice-intake
trigger:
event: Fact.Mail.Received
filter:
mailbox.eq: invoices
steps:
- id: extract
run: ai.extract
with:
schema: invoice
- parallel:
- run: database.write
- run: webhook.send
Once the file validates, copy it into the playbooks directory. The playbook engine watches that directory and loads new or changed files on its own, within a couple of seconds — no systemctl restart, no dropped in-flight work.
sudo install -o playbooksvc -g playbooksvc -m 0640 my-playbook.yaml \
/opt/binions/playbook-service/playbooks/business/
A file in provisioning/ runs the moment it loads; a file in business/ loads and then waits for its trigger.
Always validate before you save. Run
validateon every file you touched and copy them in only once they all printOK. Validating first turns a typo into a one-line error on your screen instead of a surprise the moment the engine loads it.
If you do not want to wait the couple of seconds for the automatic file-watch to fire, you can ask the playbook engine to reload all playbooks right now:
binions-cliconsole emit-control Control.Playbook.Reload --target playbook-service
This sends a Control.Playbook.Reload event directly to the playbook engine, which then re-reads its playbooks directory immediately. The automatic watch and the explicit reload are both safe to use; they do not interfere with runs already in flight.
binions-cliconsole ls events prints the most recent entries from a Redis stream, oldest-to-newest, as a single pretty-printed JSON array. It is your live view of what the platform is doing. With no flags it shows the last 10 log events:
# The default: the 10 most recent log events.
binions-cliconsole ls events
# A specific stream, more entries.
binions-cliconsole ls events --stream actions:mailbox --count 25
Because the output is JSON, pipe it straight into jq to filter or reshape it — for example, to follow one workflow end-to-end by its correlation id:
# Pull just the type and correlation id of recent events.
binions-cliconsole ls events --count 50 \
| jq -r '.[] | "\(.envelope.event_type)\t\(.envelope.correlation_id)"'
# Find every event that belongs to one run.
binions-cliconsole ls events --stream events:logs --count 200 \
| jq '[.[] | select(.envelope.correlation_id == "0190e8c1-7a3b-7c64-9b2a-2f8d4e6a91c0")]'
The streams you will reach for most:
| Stream | What flows through it |
|---|---|
events:logs | Structured log events from every daemon — the default, and the best place to start. |
events:<domain> | Facts a domain has published, e.g. events:mailbox (mail received) or events:database. |
actions:<domain> | Action requests addressed to a domain, e.g. actions:webhook or actions:ai. |
control:<service> | Runtime controls sent to one service, e.g. control:playbook-service. |
Sometimes you need to put an event onto the bus yourself — to trigger a workflow on demand, to feed a new playbook a realistic test event, or to send a runtime control. There are two commands, and which one you use depends entirely on the kind of event. Every event type has the form <Kind>.<Domain>.<Name>.
The one rule to remember. Use
emit-controlfor Control.* events (runtime operations like reloads). Use plainemitfor Action.*, Fact.*, and Log.* events (data and work on the bus). Each command refuses the other’s event kinds, so you cannot mix them up by accident.
emit takes the event type, a JSON --payload (given inline or as @file.json), and routes it to the right stream automatically. The payload is wrapped in the standard event envelope before it is published. An Action.* event must name its recipient with --target; Fact.* and Log.* events are broadcasts and need no target:
# Action — ask the mailbox service to fetch a mailbox now. --target is required.
binions-cliconsole emit Action.Mailbox.Fetch \
--target mailbox-service \
--payload '{"mailbox":"invoices"}'
# Fact — announce something happened. No target; it goes to events:<domain>.
binions-cliconsole emit Fact.Order.Placed --payload '{"order_id":4821}'
# Larger payloads read cleanly from a file with @.
binions-cliconsole emit Action.Ai.Extract \
--target aiinjector-service \
--payload @./sample-invoice-event.json
On success emit echoes the stream it wrote to, the Redis entry id, the envelope’s event id, and the topic — handy for piping into a follow-up ls events or a jq filter:
OK
stream: actions:mailbox
entry_id: 1748645099876-0
event_id: 0190e8d4-2c11-7a90-8e57-b3c9f0a2d641
topic: Action.Mailbox.Fetch
To trace cause and effect across a workflow you can also stamp an event with --correlation-id, --causation-id, and --aggregate-id; left unset, the platform fills in sensible defaults.
emit-control sends a Control.* event to exactly one service, so --target is always required; the payload defaults to an empty object when a control needs no arguments. This is the right tool for any runtime operation, including reloading playbooks:
# Reload all playbooks from disk immediately.
binions-cliconsole emit-control Control.Playbook.Reload --target playbook-service
# General form for any runtime control.
binions-cliconsole emit-control Control.<Daemon>.<Operation> --target <daemon-service>
Test events are real events. Anything you
emitbehaves exactly like an event from a live source — matching playbooks will fire. Inject test events on a host you are happy to exercise, and prefer harmlessLog.*orFact.*events when you only want to watch the wiring rather than do real work.
binions-cliconsole schema prints the canonical playbook JSON Schema to stdout. Save it to a file and point your editor’s YAML tooling at it to get autocompletion and inline validation while you write playbooks — so you discover field names from the editor instead of from memory:
# Pretty-printed by default; use --compact for a single-line schema.
binions-cliconsole schema > binions-playbook.schema.json
Once your editor is wired to that schema and you keep validate in your loop, most playbook mistakes surface before you ever reload. For deeper troubleshooting of a playbook that validates but misbehaves at runtime, see playbook debugging.
Put together, a routine session looks like this — check, change, confirm:
# 1. Is everything healthy?
binions-cliconsole status
# 2. Edit a playbook, then shape-check it.
binions-cliconsole validate /etc/binions/playbooks/invoice-intake.yaml
# 3. Drop it into the playbooks folder so the daemon loads it — no restart.
sudo install -o playbooksvc -g playbooksvc -m 0640 invoice-intake.yaml \
/opt/binions/playbook-service/playbooks/business/
# 4. (Optional) Trigger an immediate reload rather than waiting for the file-watch.
binions-cliconsole emit-control Control.Playbook.Reload --target playbook-service
# 5. Trigger the playbook once and watch what happens.
binions-cliconsole emit Action.Mailbox.Fetch --target mailbox-service --payload '{"mailbox":"invoices"}'
binions-cliconsole ls events --stream events:logs --count 20 | jq -r '.[] | .envelope.event_type'