cliconsole is the operator command line for Binions — your control panel from a terminal. It is the binions-cliconsole tool: a single command for checking the health of every daemon, validating a playbook — and proving it can actually run — before you ship it, reading recent events off the bus or tailing them live, and publishing events by hand while you build and debug automations. Anything you can do by hand on the platform, you do through cliconsole.
It is a command, not a background service. Unlike the other daemons, cliconsole does not run all the time. You invoke it, it does its job, and it exits — exactly like
gitorsystemctl. There is no service to start, enable, or watch.
Every other Binions daemon is a long-running background service that reacts to events around the clock. cliconsole is different: it is a hands-on tool you run from a shell whenever you need to inspect the platform or poke it directly. It gives you six things:
status finds every installed daemon, asks each one whether it is ready, and prints a table you can read at a glance.validate checks a playbook file — or a whole ----separated bundle — for shape errors offline, before it ever reaches the platform; add --dry-run and it also proves the playbook can actually run, with the same static feasibility checks the engine applies on entry.ls events pulls recent entries from a stream and prints them as readable JSON, so you can see exactly what flowed through the bus — and with --follow it keeps printing new entries live as they arrive.emit and emit-control let you send Actions, Facts, Logs, and Control commands by hand — the manual equivalent of what a playbook does automatically.schema prints the canonical playbook JSON Schema, ready to wire into your editor for autocompletion and inline validation.cliconsole talks only to the services on the same host, over localhost. It never reaches across the network. Two of its commands — status and validate — do their work entirely on their own and never touch the event bus; the rest read from or write to the bus directly, and can be pointed at any daemon’s own Redis by name with --service (see below).
| What it is | An on-demand operator CLI — the platform’s control panel from a terminal |
| How you run it | binions-cliconsole <command> — runs once and exits, like git or systemctl |
| Commands | status · validate · ls events · emit · emit-control · schema |
| Choosing a Redis | --redis-url beats --service <name> (resolved from the daemon’s own config) beats the environment |
| Talks to | Only local services, over localhost — never across the network |
| Offline commands | status and validate (with or without --dry-run) never touch the event bus |
| Producer name | Everything it sends is stamped cliconsole-service in the event envelope |
| Long-running daemon? | No — there is no binions-cliconsole.service to enable or monitor |
Auto-discovers every installed daemon, probes each one’s readiness endpoint in parallel, and prints a table of service, url, state, and latency. A daemon that answers is UP; one that refuses the connection or times out is DOWN; one that is up but reporting trouble is DEGRADED. cliconsole leaves itself out of the list — it is a tool, not a service to probe. Use --timeout-ms to change how long it waits for a slow daemon (the default is around 1500 ms).
# Health of the whole platform, at a glance
binions-cliconsole status
# Give slow daemons a little longer to answer
binions-cliconsole status --timeout-ms 3000
Reads a playbook file and checks its shape against the platform’s four-step grammar (run, parallel, loop, and wait_for) — entirely offline, without contacting any daemon. Every problem it finds is listed with the exact location in the file, and the command exits with a non-zero status when validation fails. Files that bundle several playbooks separated by --- are read document by document, and findings are reported per document ([doc N]) — one bad playbook cannot hide behind its healthy neighbours.
Grammar is only half the story: a playbook can parse perfectly and still be impossible to run. Add --dry-run and validate also applies the same static feasibility checks the engine runs when a playbook arrives on the platform: verbs that do not exist, ${steps.<id>} references to a step id that is never declared, ${loop.<var>} used outside its loop, wait_for causation targets that do not name a run: step, and interpolation namespaces the platform does not know. All of it still runs offline — the file is proven runnable before it ever reaches the host. Plain validate stays grammar-only.
On the platform itself, a playbook that fails these checks on entry — at boot, on reload, on hot-deploy, or through an MCP deploy — is rejected: the last good version keeps serving, and a Fact.Playbook.Rejected event carries the concrete errors. Run --dry-run first and you read those errors at your desk instead.
# Lint a single playbook (grammar only)
binions-cliconsole validate ./invoice-intake.yaml
# Grammar plus feasibility — the same static checks the engine applies on entry
binions-cliconsole validate --dry-run ./invoice-intake.yaml
# Gate a deploy on it — non-zero exit stops the script
binions-cliconsole validate --dry-run ./invoice-intake.yaml && ./deploy.sh
Tip. Pair
validatewithschema. Point your editor’s YAML support at the schema for live autocompletion as you type, then runvalidate --dry-runin CI as the final gate — grammar and feasibility both. Most mistakes never make it past your editor.
Reads the most recent entries from a stream and prints them as pretty-formatted JSON, oldest-first, so a sequence reads top to bottom in the order things happened. By default it reads the events:logs stream and shows the last 10 entries; point it at any stream with --stream and change the window with --count. Because the output is clean JSON, you can pipe it straight into jq to filter or reshape it. (ls events is the only ls form the tool accepts.)
Add --follow and the command does not exit after the backlog: once the last entries are printed, it keeps a blocking read open on the stream and prints every new entry the moment it lands — a live tail of the bus. That is the debugging companion: leave ls events --follow running in one terminal, trigger your playbook from another, and watch the facts arrive in real time. Stop it with Ctrl-C.
# The last 10 log entries (defaults)
binions-cliconsole ls events
# The last 20 actions sent to the mailbox daemon
binions-cliconsole ls events --stream actions:mailbox --count 20
# Print the backlog, then keep watching live as new facts arrive
binions-cliconsole ls events --stream events:billing --count 20 --follow
# Pull facts and filter them with jq
binions-cliconsole ls events --stream events:billing --count 50 | jq '.[] | .event_type'
Publishes one event onto the bus — the manual equivalent of a step in a playbook. You give it the event type and a JSON payload, supplied inline or read from a file with @. An Action is work addressed to a specific daemon, so it requires --target; Facts and Logs announce something to the whole platform and are broadcast without a target. To thread a hand-emitted event into an existing run for end-to-end tracing, add any of --correlation-id, --causation-id, or --aggregate-id. On success, cliconsole prints the stream it wrote to, the entry id, the event id, and the topic.
# An Action — addressed to one daemon, so --target is required
binions-cliconsole emit Action.Database.Query \
--target database-service \
--payload '{"table":"invoices","limit":1}'
# A Fact — broadcast, no target needed
binions-cliconsole emit Fact.Invoice.Received \
--payload '{"invoice_id":"INV-2041","amount":129.00}'
# Read a larger payload from a file, and thread it into an existing run
binions-cliconsole emit Action.Mailbox.SendEmail \
--target mailbox-service \
--payload @./welcome-mail.json \
--correlation-id 7f3c9a20-1b44-4e8e-9b2a-2c6d8f0a1e55
Publishes a Control event — a runtime operation aimed at a single daemon. The target is always required; the payload is optional and defaults to {}. Control events are routed to that daemon’s own control stream, so they reach it directly. A common use is telling the playbook daemon to reload its configuration from disk after you have edited or deployed a playbook file.
# Tell the playbook daemon to reload playbooks from disk
binions-cliconsole emit-control Control.Playbook.Reload --target playbook-service
# Send a runtime control event to any daemon (general form)
binions-cliconsole emit-control Control.<Daemon>.<Operation> --target <daemon-service>
# A control command that carries a small payload
binions-cliconsole emit-control Control.Logger.SetLevel \
--target logger-service \
--payload '{"level":"debug"}'
Use the right command for the kind of event: emit-control is only for Control.* events, while plain emit is for Action.*, Fact.*, and Log.*. Each command refuses the wrong kind, so you cannot accidentally fire a Control command with emit or an Action with emit-control.
Prints the canonical playbook JSON Schema to standard output. Redirect it to a file and point your editor’s YAML support at it to get autocompletion and inline validation as you write playbooks.
# Save the schema for your editor to use
binions-cliconsole schema > binions-playbook.schema.json
The commands that read or write the bus need a Redis connection, and there are three ways to give them one. With no flags, the connection comes from the environment — the common case on a standard install. The two flags cover everything else:
--service <name> — the comfortable path. Every daemon keeps its own Redis, with its own port and password. Name the daemon — say --service mailbox-service — and cliconsole reads that daemon’s own configuration (/opt/binions/<service>/config/application.toml, the [redis] section’s port and password_file) and connects for you. No hand-assembling a redis:// URL per daemon, no copying passwords around.--redis-url <url> — full control. An explicit URL, for when you want to spell the connection out yourself.Precedence is strict: --redis-url beats --service, which beats the environment. The dead-letter maintenance command purge_dlq resolves a daemon’s Redis the same way automatically — name the daemon whose queue you are clearing and the connection is found for you. (status and validate need none of this — they never touch a Redis at all.)
# Resolve the mailbox daemon Redis from its own config — no URL assembly
binions-cliconsole ls events --service mailbox-service --stream actions:mailbox --count 20
# Same resolution, live: watch playbook lifecycle facts as they happen
binions-cliconsole ls events --service playbook-service --stream events:playbook --follow
# An explicit URL always wins when you need full control
binions-cliconsole ls events --redis-url redis://127.0.0.1:6379 --stream events:logs
When you emit an event, its type decides where it lands on the bus and whether a target is needed. The same routing applies whether the event comes from cliconsole or from a running daemon:
| Event type | Goes to stream | Target required? | Command |
|---|---|---|---|
Action.<Domain>.<Verb> | actions:<domain> | Yes | emit |
Fact.<Domain>.<Past> | events:<domain> | No (broadcast) | emit |
Log.* | events:logs | No (broadcast) | emit |
Control.<Service>.<Verb> | control:<target> | Yes | emit-control |
So Action.Database.Query lands on actions:database and must name its target, while Fact.Invoice.Received lands on events:billing or events:invoice and is broadcast to anything that cares. This is the same map you can explore with ls events — read actions:mailbox to see work queued for the mailbox daemon, or events:logs to follow platform-wide log lines, live if you add --follow.
Everything cliconsole publishes is wrapped in the standard Binions event envelope, exactly like events produced by any daemon: a unique event id, the producer name cliconsole-service, a timestamp, and — when you supply them — correlation, causation, and aggregate ids. That means a hand-emitted event is indistinguishable in structure from one a daemon emitted, and it threads into the same end-to-end traces.
Action.* (with a target), Fact.*, or Log.* via emit; any Control.* (with a target) via emit-control. Always stamped cliconsole-service.ls events, or a live tail of new ones with --follow.status (it probes health endpoints) and validate (it works on a local file, --dry-run included).Local only. cliconsole connects exclusively to services on the same host over
localhost. It opens no outbound network connections and has no remote mode — the events you emit stay on your host, just like the rest of the platform.
You may notice a redis-binions-cliconsole service alongside the other daemons’ data stores. It is reserved for a future interactive mode and is not used by the command today — the binions-cliconsole command you run from the shell does its work and exits without depending on it. There is deliberately no long-running binions-cliconsole.service: cliconsole is something you run, not something that runs.
A handful of invocations cover most day-to-day operator work:
# Is everything healthy right now?
binions-cliconsole status
# Prove a playbook is well-formed AND runnable before deploying it
binions-cliconsole validate --dry-run ./pb.yaml
# Tell the playbook daemon to reload playbooks from disk after an edit
binions-cliconsole emit-control Control.Playbook.Reload --target playbook-service
# See the last 20 actions queued for the mailbox daemon — by name, no URL assembly
binions-cliconsole ls events --service mailbox-service --stream actions:mailbox --count 20
# Watch facts arrive live while a playbook runs
binions-cliconsole ls events --stream events:billing --follow
# Manually drive a database query while debugging
binions-cliconsole emit Action.Database.Query --target database-service \
--payload '{"table":"invoices","limit":1}'
# Export the playbook schema for editor autocompletion
binions-cliconsole schema > binions-playbook.schema.json