The VOCAB registry is the single table that defines every operation Binions understands. For each verb it records which daemon owns it, which streams carry the request and the reply, and the exact event names involved. One small, curated vocabulary — sixty-four generic verbs, plus the twelve show.* page verbs — covers every use case, instead of thousands of app-specific connectors.
The rule that keeps it small: generic operations. A verb names a capability, never a business outcome. It is
database.write, notdatabase.save_invoice;ai.extractwith afields:argument, notai.extract_invoice. The same handful of verbs compose into invoicing, monitoring, IoT, and everything else.
Each vocabulary entry resolves a playbook's <daemon>.<operation> string into everything the engine needs to route the request and wait for the reply:
| target_service | The daemon that owns the operation, e.g. database-service. |
| action_short | The short name of the daemon's action inbox — drives actions:<action_short>, e.g. database (or schedule for the scheduler). |
| fact_short | The short name of the daemon's fact stream — drives events:<fact_short>, e.g. database. |
| action_event_type | The Action event name, e.g. Database.Write. |
| expected_fact_event_type | The Fact to wait for, e.g. Database.Inserted — a step may override this with an explicit expect: field. |
Two different “shorts”. A daemon's action inbox and fact stream often use different short names.
database-servicelistens onactions:databasebut publishes facts toevents:database;dataanaliser-servicelistens onactions:analyticsbut publishes toevents:dataanaliser. The registry records both so routing is unambiguous.
When you write a playbook step, the engine resolves the verb against the registry and tells you precisely where it stands — a deliberate distinction that turns typos and “not yet” into clear, different messages:
A single verb can reach many different back ends without the vocabulary growing. The right implementation is chosen by a field in the step's arguments rather than by a new verb:
mail.register_mailbox talks to IMAP, MQTT, AMQP, Redis pub/sub, WebSocket, SSE or Kafka depending on a protocol: field.data.upload writes to S3/MinIO, SFTP, FTP, the local filesystem, MongoDB GridFS or an HTTP ingest endpoint depending on a backend: field.traefik.register_route handles http/https, ws/wss, sse, grpc and grpc-web the same way.database.* operation reaches PostgreSQL (default), SQLite, MySQL/MariaDB, MongoDB or Microsoft SQL Server depending on a backend: field — or on a named connection: alias registered once with database.register_connection.The vocabulary is not documentation that can rot — it is code, and the build keeps it honest. The playbook engine's registry and the AsyncAPI generator share the same table; the build pipeline regenerates the AsyncAPI contract from it and fails on any drift. Change a verb's routing or event name in one place without the other, and the snapshot diff stops the merge.
Net effect. The verb you read here, the event your playbook emits, and the channel it lands on are guaranteed to agree with the running platform.