- CLI Reference
- Commands
- ironflow event
ironflow event
Explain event routing, manage event schemas, test upcasters, and redact events.
ironflow event <subcommand> [flags]events is an alias for event.
ironflow events explain
Section titled “ironflow events explain”Explain current routing eligibility without emitting an event. Supply exactly one stored event ID or proposed event name.
ironflow events explain --event-id evt_123 --jsonironflow events explain --event order.created --data '{"orderId":"123"}' --jsonironflow events explain --event order.created --data-file event.json --version 2| Flag | Type | Default | Description |
|---|---|---|---|
--event-id | string | Stored event ID in the selected environment | |
--event | string | Proposed event name | |
--data | string | {} | Proposed event JSON payload |
--data-file | string | JSON file, or - for stdin | |
--version | int32 | 0 | Proposed schema version; 0 means 1 |
--idempotency-key | string | Use the original event if this key already exists | |
--json | bool | false | Print the canonical response with snake_case keys |
--server, -s | string | Server URL override |
Proposed event flags cannot accompany --event-id. --data and --data-file are mutually exclusive. The command uses the configured credentials and environment, as other event commands do.
The result contains event_id, event_name, and a functions array. Each entry has function_id, name, and one reason.
Without --json, the command prints a table with the columns FUNCTION ID, NAME and REASON.
| Reason | Meaning |
|---|---|
matched | At least one current trigger matches |
no_trigger | No event-name trigger matches, including invoke-target restrictions |
filter_false | A matching trigger’s CEL filter returned false |
cel_error | A matching trigger’s CEL filter could not compile or evaluate |
schema_reject | The current reject-mode schema policy would refuse the proposed event |
duplicate | A run already exists for this function, or the proposed idempotency retry resolves to a processed event |
redacted_or_encrypted | A matching trigger needs an unavailable payload for CEL evaluation |
A successful trigger wins over errors or false results from other triggers. Otherwise CEL errors take precedence over false, then no trigger. Event-name-only triggers and successful CEL expressions retain live matching behavior for unavailable payloads. Structural redaction markers and encryption envelopes are recognized; arbitrary user field names are not treated as redaction.
Stored events and idempotency hits use the original payload and skip ingest schema validation, as dispatch resume does. Existing runs take precedence; an unprocessed event can still be eligible for missing runs. Proposed idempotency retries of processed events return duplicate, because live ingest does not dispatch them again. Stored-ID requests assess current trigger eligibility instead. Schema warn mode permits matching. A registry outage returns an error rather than a schema-rejection reason.
These results describe current eligibility, not historical routing or a guarantee of dispatch. Capacity, debounce, dispatch failures, and concurrent changes can affect execution. The operation creates no event, run, debounce slot, or trace anchor and does not wake waiting workflows.
Requires events:subscribe for the event and functions:list. Only functions the caller can read appear. Cross-environment IDs and definition-history events return not-found. Python exposes rpc.events.explain_match. Go and JavaScript convenience wrappers are not yet available.
ironflow event schema register
Section titled “ironflow event schema register”Register a JSON schema for an event type at a specific version.
ironflow event schema register <event-name> [flags]Arguments:
| Argument | Required | Description |
|---|---|---|
event-name | Yes | The event name (e.g., order.created) |
Flags:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--version | int | Schema version (required) | ||
--file | string | Path to JSON schema file | ||
--schema | string | Inline JSON schema string | ||
--description | string | Schema description | ||
--reason | string | Reason for replacing the schema definition | ||
--server | -s | string | Server URL override |
One of --file or --schema is required. Cannot use both.
Examples:
ironflow event schema register order.created --version 1 --file schema.jsonironflow event schema register order.created --version 1 --schema '{"type":"object"}'ironflow event schema register order.created --version 2 --file schema-v2.json --description "Added address field"The command prints Schema <event-name> (v<version>): created or updated.
The schema must be a JSON Schema the server can compile (draft 2020-12); a
malformed document is rejected. Re-registering an existing (event name, version) overwrites it and reports updated rather than created.
The created/updated distinction is advisory. It is read before the upsert
rather than derived from it, so two registrations racing on the same
(event name, version) can both report created. The write itself is still
correct — last one wins — and this is a display label on a command a human
runs, not a value to branch on.
Registering a schema does not by itself enforce it. See
IRONFLOW_EVENT_SCHEMA_ENFORCEMENT,
which is off by default.
--reason <text> records an optional explanation with the archived old definition.
It does not create a revision when registration leaves the definition unchanged.
ironflow event schema list
Section titled “ironflow event schema list”List registered event schemas.
ironflow event schema list [flags]Flags:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--event | string | Filter by event name | ||
--limit | int | 100 | Maximum number of schemas to return | |
--json | bool | false | Output as JSON | |
--server | -s | string | Server URL override |
Output:
EVENT VERSION DESCRIPTION REGISTEREDorder.created 1 Order created event 2025-01-15 12:00:05order.created 2 Added address field 2025-01-20 09:30:00Examples:
ironflow event schema listironflow event schema list --event order.createdironflow event schema list --jsonironflow event schema get
Section titled “ironflow event schema get”Get detailed information about a registered event schema.
ironflow event schema get <event-name> [flags]Arguments:
| Argument | Required | Description |
|---|---|---|
event-name | Yes | The event name to look up |
Flags:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--version | int | 0 | Schema version (0 = latest) | |
--json | bool | false | Output as JSON | |
--server | -s | string | Server URL override |
Output:
Event: order.createdVersion: 2Description: Added address fieldRegistered: 2025-01-20 09:30:00Schema:{"type":"object","properties":{"id":{"type":"string"},"address":{"type":"object"}}}Examples:
ironflow event schema get order.createdironflow event schema get order.created --version 2ironflow event schema get order.created --jsonironflow event schema delete
Section titled “ironflow event schema delete”Delete a registered event schema.
ironflow event schema delete <event-name> [flags]Arguments:
| Argument | Required | Description |
|---|---|---|
event-name | Yes | The event name to delete |
Flags:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--version | int | Schema version (required) | ||
--reason | string | Reason for deleting the schema definition | ||
--server | -s | string | Server URL override |
--reason <text> records an optional explanation with the archived old definition.
Output:
Deleted schema order.created (v1)ironflow event schema history
Section titled “ironflow event schema history”Read archived definitions for one event name and one numbered schema version.
--version is required and must be positive. Each version has its own revision
sequence, starting at 1. A revision contains the old document preserved before
replacement or deletion, including its description and the mutating actor’s ID.
ironflow event schema history <event-name> --version <version> [flags]| Flag | Type | Default | Description |
|---|---|---|---|
--version | int | Required positive schema version | |
--revision | int64 | Retrieve one positive revision as full JSON | |
--limit | int | 50 | Page size, maximum 200 |
--before-revision | int64 | Exclusive cursor for older revisions | |
--json | bool | false | Full response as JSON |
--server, -s | string | Server URL override |
Lists run newest first. JSON includes entries, has_more, and
next_before_revision, which is zero on the last page. Do not combine --revision
with pagination flags. Missing exact revisions return an error; missing history
returns an empty list. Reads require events:subscribe permission in the selected environment.
Text output has the columns REVISION, VERSION, RECORDED AT, CHANGE, ACTOR and REASON. When more revisions exist, it ends with a Next page: --before-revision <n> line.
ironflow event schema history order.created --version 1 --limit 10ironflow event schema history order.created --version 1 --before-revision 12 --jsonironflow event schema history order.created --version 1 --revision 3 --jsonironflow event schema delete order.created --version 1 --reason "retired producer"Example exact-revision JSON:
{ "entry": { "event_id": "history-event-id", "revision": "2", "previous_definition": { "event_name": "order.created", "environment_id": "env-production", "version": 1, "schema_json": "{\"type\":\"object\"}", "description": "Order payload" }, "actor_id": "api-key-id", "change_reason": "retired producer", "change_type": "deleted", "recorded_at": "2026-10-03T04:00:00Z" }}Protobuf JSON represents int64 revision numbers as strings.
Initial creation and identical registration create no history. History remains readable after deletion; re-creating that same version continues its revision sequence on the next change. Changes made before this feature are unavailable.
ironflow event schema check
Section titled “ironflow event schema check”Report whether event-schema enforcement is actually enforcing anything.
Enforcement is opt-in and off by default, and it has several ways to accept
every payload without validating it. From outside, all of them look exactly
like “every payload was clean”: an operator sets
IRONFLOW_EVENT_SCHEMA_ENFORCEMENT=reject, sees zero rejections, and cannot
tell which they are in. This command tells them apart (#1958).
ironflow event schema check [event-name] [flags]Arguments:
| Argument | Required | Description |
|---|---|---|
event-name | No | Report on one event name only (default: every schema) |
Flags:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--window | int | 0 | Traffic sample window in hours (0 = default, 24) | |
--json | bool | false | Output as JSON | |
--server | -s | string | Server URL override |
Verdicts:
| Verdict | Meaning |
|---|---|
enforcing | Events at this version, all validated against this schema |
partial | Some events at this version validated against this schema |
unvalidated | Events at this version, none validated against this schema |
unused | Events of this name arrive, but at a different version |
no-traffic | No events of this name in the window |
permissive | The schema compiles but accepts every payload |
broken | The stored schema does not compile; enforcement fails open |
permissive is the one to read twice. A JSON Schema that compiles is not
necessarily one that constrains: Draft 2020-12 treats an unrecognized keyword
as an annotation, so {"foo":"bar"} is a valid schema that accepts every
payload, exactly as {} does. Registering a sample payload by mistake succeeds
and enforces nothing. Registration cannot reject these — {} is a legitimate
permissive schema — so this report is where they surface. The check is a
heuristic (it asks whether the schema rejects any of six probe documents), and
it errs toward reporting permissive only when a schema really does accept
every JSON type.
unvalidated means the events reached the store without being checked —
because the mode was off, or the name was ungoverned at the time, or the stored
schema would not compile. It is not a claim that the payloads were bad.
Output:
Enforcement mode: rejectTraffic window: last 24h
EVENT VER HASH VERDICT DETAILorder.created 1 3f2a91c04b7e5d18 enforcing 340 events at v1 in the last 24h, all validated against this schemaorder.created 2 9b1e77c2aa04f6d3 unused 340 events in the last 24h, none at v2 — they arrive at v1 (340). Version matching is exact, so this schema governs none of them.user.signup 1 c40de9f1b2a83057 permissive schema compiles but rejects nothing — every payload satisfies it. Registering a sample payload instead of a schema looks exactly like this.With the mode off, the table still renders and a banner says so — the verdicts then describe what would happen.
Counts are a sample of the newest matching events, not lifetime totals. When
the sample hits its scan cap the header says (sampled).
Examples:
ironflow event schema checkironflow event schema check order.createdironflow event schema check --window 168ironflow event schema check --jsonironflow event upcast
Section titled “ironflow event upcast”Test how an event would be transformed between schema versions.
ironflow event upcast <event-name> [flags]Arguments:
| Argument | Required | Description |
|---|---|---|
event-name | Yes | The event name to upcast |
Flags:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--from | int | Source version (required) | ||
--to | int | Target version (required) | ||
--data | string | Event data as JSON | ||
--data-file | string | Path to JSON file with data (- reads stdin) | ||
--json | bool | false | Output as JSON | |
--server | -s | string | Server URL override |
Data input follows the same rules as emit (flag or file, --data-file - for stdin).
Output:
Steps applied:FROM TO DESCRIPTION1 2 added priority field
Result data:{ "orderId": "123", "customerId": "456", "priority": "normal"}Examples:
ironflow event upcast order.created --from 1 --to 2 --data '{"orderId":"123"}'ironflow event upcast order.created --from 1 --to 2 --data-file event.jsonironflow event upcast order.created --from 1 --to 3 --data '{}' --jsonironflow event redact
Section titled “ironflow event redact”Irreversibly replace an event’s data with a placeholder.
ironflow event redact <event-id> [flags]The row keeps its id, name, sequence and entity version, so replay ordering and optimistic concurrency are unaffected and reducers receive the placeholder in the payload’s place. The SDK upcaster chains skip a redacted payload rather than migrate it, so its marker survives. The placeholder is {"$redacted": true, "sha256": "...", "redactedAt": "..."}; the hash is of the original bytes and nothing recovers them from it. SDKs expose isRedacted(payload) so a reducer can tell it from real state.
If the event belongs to an entity stream, that stream’s snapshots are dropped in the same transaction. Their state is derived from the bytes being removed, so leaving them would keep serving the original content and the reducer would never see the placeholder. The next read re-reduces from the events.
Copies that are not yet published change in the same transaction. A pending outbox row and an outbox dead letter both take the placeholder, so the event publishes the placeholder, and so does a later ironflow outbox dlq requeue. An entity row keeps its envelope, with the placeholder in data.
Destructive and irreversible; prompts for confirmation unless --yes is passed. Needs the events:redact action, which only the admin role holds by default.
Four things this does not reach:
- Projection state. A read model that folded this payload into its state keeps it; Ironflow never rewrites projection state. Rebuild the projection if it needs to forget it too.
- The runs the event triggered. A run’s
inputholds a copy of the same payload, and so does itsrun.createdaudit row. Useironflow run redactfor those. - A copy already published to a stream, which survives until its own retention window expires (seven days on PUBSUB; EVENTS has no age expiry and requires terminal reclamation). A subscriber that received it keeps it. The worker reads each row just before it publishes. A publish past that read when the redaction commits counts as published, so it can still send the original.
- An object-storage copy whose cleanup fails. Snapshot blobs are swept on a best-effort basis after the rows are scrubbed; a failed sweep is logged and the object is left behind with nothing to reclaim it.
Arguments:
| Argument | Required | Description |
|---|---|---|
event-id | Yes | The event ID to redact |
Flags:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--server | -s | string | Server URL override | |
--yes | bool | false | Skip confirmation prompt |
Output:
Redacted event ev-abc123Examples:
ironflow event redact ev_abc123ironflow event redact ev_abc123 --yes