Skip to main content
Version: v5.6.1

The event system

Included from Basic tier

Events are the server's append-only, typed audit stream: every run and step transition, every supervised verb, every plane lifecycle fact lands as one events row. The stream is what opschain events and the GUI's Activity feed read, what the trigger engine matches (opschain docs triggers), and what chains are threaded from — every event carries a correlation_id and a chain_depth, so any row is a handle into its whole cascade.

Emission, storage and the event shape​

Events are written server-side at the seam the action passes through — the run engine's state machine, the create/admin endpoints, the runner and agent RPC planes, the trigger engine — never by clients, so no client code path can omit its own trail. Rows are stored with UUIDv7 ids (so id order is chronological), a type, the acting username, a JSON data payload, the polymorphic source (source_type/source_id), an event_node_path for scoping, and the chain spine (correlation_id, caused_by_event_id, initiated_by_type/initiated_by_id, chain_depth). Emission is best effort: a failed event insert never fails the operation it narrates. Retention is the retention.events_days config key (opschain docs retention).

One store caveat: the server-emitted lifecycle events — the api:/warn: rows no run writes, such as node delete/restore/destroy, maintenance windows, EULA and licence facts, and database maintenance — are written through the PostgreSQL pool only. On the embedded SQLite (trial) store those operations run but record no event; the operator notice and the relevant status endpoint are the visibility there. Run and step events are store-agnostic and land on both backends.

A serialized event (type event) carries the fixed attributes type, username (nullable), system, event_node_path, created_at, correlation_id and chain_depth, with the payload's own keys spread beside them, plus a source relationship (a link always; the resource identifier too when the request includes source). The full attribute dictionary is opschain docs resources/event.

The audit envelope — actor. Every event a request causes — the api:* mutation audit, the authentication family, the server-emitted lifecycle events (node delete/restore/destroy, maintenance, licence, template-version and actions-refresh lanes, artefact creation) — carries an actor object inside its payload, so an audited action ties to who, from where, with which credential without a join against the request log:

KeyPresent whenMeaning
principal_idthe request authenticatedThe acting user's id (never the username — that is the row's username column, and emails never appear).
session_idthe credential was a native sessionThe auth_sessions row the request rode (opschain docs resources/session).
token_id, token_kindthe credential was anything else (a native API key, a step token, a legacy token)The credential row id and its kind. Basic-auth requests carry neither.
client_addressalways, for a requestThe client address, resolved behind any trusted reverse proxy (server.trusted_proxies, opschain docs config) — the same value the request log's remote_ip records.
user_agentthe request sent oneThe User-Agent header, bounded to 512 characters.
request_idalways, for a requestThe request correlation id the response echoed as X-Request-Id — the join key to the request log line.

The object is absent on engine-originated events (run and step transitions, scheduler and retention roll-ups, trigger firings): no request, no actor. A login attempt carries the origin keys before it has a principal (warn:auth:login_failed names where the attempt came from). An emitter that sets its own actor is never overwritten. The object rides data verbatim into the SIEM forwarder and the events API (payload keys are spread beside the fixed attributes, so actor.client_address is filterable like any payload key), and ages out with the row under retention.events_days — the retention control is the proportionality for holding an address and a user agent in the trail (opschain docs security-audit).

Querying​

  • GET /api/events — newest first, default limit 10, maximum 1000, with the shared Ransack filter grammar (scalar predicates, in/not_in, grouped and/or, sorts) plus the special-cased filter[for_change]=<change id> scope: the change's own events and its steps'.
  • GET /api/events/{id} — one event.
  • EventService.ListEvents / GetEvent / WatchEvents (/api/v2, opschain docs api-v2) — the typed v2 twins: cursor-paginated listing keyed on (created_at, id), and the live stream the GUI feed rides instead of polling — resumable with from_cursor after a disconnect, replaying the missed events oldest first before the tail. Searching by type: type_search matches text anywhere in the type (agent finds warn:agent:halted), resolved against this registry plus the stored types and read through the type index — the audit history search box and opschain audit --type-search.
  • EventService.GetEventStats (/api/v2, admin-scoped) — the aggregation read over the same vocabulary: time-bucketed counts by event class, top types and actors, and an optional payload facet — set-based SQL, never a row fetch. CLI: opschain events stats (opschain docs cli/events-stats).
  • opschain events (opschain docs cli/events) — the estate-wide triage entry point; its --errors convention selects error:/warn: prefixes and :error/:system_error/:pre_execution suffixes.

The type grammar​

Types are namespaced <root>:<area>:<verb>. The roots in use:

RootCarries
api:A performed action or lifecycle fact (create, start, success, applied, …).
audit:A supervised human verb on live work (cancel, pause, resume, approve, …) and the maintenance override.
info:A notice — plane lifecycle, parked automation, governance trails.
warn:A degraded or loud condition that did not fail a request.
error:A failure recorded in its own right.

Steps can emit custom events — the declarative emit: step, or opschain step emit-event (opschain docs cli/step-emit-event) writing to the $OPSCHAIN_EVENTS file the executor folds in on step success. Custom types are free-form namespaced identities matching ^[a-z0-9_]+:[a-z0-9_:]+$ with no registry; the reserved prefixes api: system: info: error: warn: are the server's and are refused at the write gate. A custom event is sourced from the emitting step, placed on the change's target path (so trigger scope matching works), inherits the change's correlation chain, and its data passes the run's secret masker before storage. Local (--local) runs store step-emitted custom events the same way — type-gated, masked, visible in runs show --events — into the local store.

The type registry​

Every event type the server emits, verbatim, grouped by area. (Types that appear only in test fixtures are excluded.)

Run lifecycle (changes and workflow runs)​

The run engine emits these per run; <kind> is changes or workflow_runs:

  • api:changes:create, api:workflow_runs:create — a run was created.
  • api:changes:start, api:workflow_runs:start — the run began executing.
  • api:changes:success, api:workflow_runs:success — the run finished successfully.
  • api:changes:error, api:workflow_runs:error — the run finalised in error.
  • api:changes:system_error, api:workflow_runs:system_error — the run finalised in system error (infrastructure, not the action).
  • api:changes:skip, api:workflow_runs:skip — the run's root step was skipped.
  • api:changes:abort, api:workflow_runs:abort — the run finalised aborted.
  • audit:changes:cancel, audit:workflow_runs:cancel — a cancellation, with actor and reason.
  • audit:changes:pause, audit:workflow_runs:pause — a pause, with actor and reason.
  • audit:changes:resume, audit:workflow_runs:resume — a resume, with actor and reason.
  • error:changes:pre_execution, error:workflow_runs:pre_execution — a step failed before execution started (runner-plane setup: infrastructure, git or secrets).

Step lifecycle​

Steps of both run kinds share one vocabulary:

  • api:steps:start — a step started.
  • api:steps:success — a step succeeded.
  • api:steps:error — a step failed.
  • api:steps:system_error — a step failed with a system error (an infrastructure failure such as a lost runner, not the action's verdict).
  • api:steps:skip — a step was skipped.
  • api:steps:abort — a step was aborted.
  • api:steps:waiting — a step entered the waiting state (a wait step or approval gate); the notification spine's waiting_on_gate condition and the zero-config approvals default consume it.
  • audit:steps:approve — an approval gate was approved (actor, message).
  • audit:steps:continue — a wait step was continued (actor, message).
  • audit:steps:reject — a wait/approval step was rejected (actor, message).
  • audit:steps:cancel — a step was cancelled (actor, message).

Artefacts​

  • api:artifacts:create — an artefact was stored (code, labels, node path, digest, size) — DSL-stored and step-collected artifacts alike (opschain docs artifacts).
  • warn:artifacts:collection — a declared step artifact was not collected without failing the step (an optional declaration, or a required one on a step that already failed); the message names the artifact and the cause.

Triggers​

  • api:triggers:fired — a firing settled (status, matched event, author/executed_as, created object or message).
  • info:triggers:deferred — a firing parked under a maintenance window.
  • warn:triggers:depth_cap — a firing suppressed at the chain-depth cap (trigger-loop damping).
  • warn:triggers:deferral_expired — a released deferral past its window's declared until, suppressed.
  • warn:triggers:identity — a firing's executing identity refused resolution.
  • warn:triggers:engine — the engine failed several consecutive sweeps; event automation is stalled.

Inbound webhooks​

  • external:webhook:received — a signature-verified inbound webhook delivery landed (opschain docs cli/admin-inbound-webhooks): the connection code, the envelope event type, the delivery id and the raw payload under data.payload. Triggers with subject external bind to it, and every firing it causes executes as the connection's service account. A GitHub delivery additionally exposes a normalised typed field set under data.github, and a Jira/JSM delivery (recognised by the payload's webhookEvent) under data.jira (key, project, status, summary, priority, labels, comment id and the internal-note flag).
  • warn:webhooks:refused — an inbound delivery was refused by name (connection, reason: bad_signature, stale_timestamp, replayed_delivery, connection_disabled, unknown_connection, no_signing_secret, payload_too_large, payload_not_json, missing_signature, missing_timestamp) beside the endpoint's typed 4xx — a refusal is never silent. No signature material is recorded.

SIEM export​

  • warn:siem:delivery_failing — a SIEM forwarder connection (opschain docs integrations-siem) failed several consecutive delivery attempts: the connection code and kind, the failure streak and the receiver's last refusal (never credential material). Throttled to one event per connection per window; events queue behind the durable cursor and deliver once the receiver recovers.
  • info:siem:test — the synthetic event opschain admin siem test sends through a connection's real formatter and sender. It is delivered to the receiver only, never recorded on the event stream — listed here so the vocabulary is complete.

Maintenance windows​

  • api:nodes:maintenance_started — a window opened (manual or auto-start).
  • api:nodes:maintenance_ended — a window closed; sweeping it releases the deferred firings.
  • api:nodes:maintenance_scheduled — a scheduled window was created.
  • api:nodes:maintenance_extended — a window's end moved later (manual or auto-extension).
  • audit:maintenance:override — a create was admitted through the gate by an authorised override.
  • warn:maintenance:auto_extend_cap — an auto-extending window ended at its cap with work still running.
  • warn:maintenance:declared_run_failed — a scheduled window's declared workflow could not start.

Infrastructure​

  • api:infrastructure:registered — an infrastructure node was registered through the infrastructure API (data carries the typed request fields and the node path). Re-registering a code a deregistered node holds revives the same row and records the same event.
  • api:nodes:update — an infrastructure node was updated through the infrastructure API (the same family the estate node writes record).
  • api:infrastructure:deregistered — the deregister verb closed the node's estate membership (the soft-close posture; the node row, its history and its events remain queryable).
  • api:infrastructure:provisioned / api:infrastructure:destroyed — reserved for the integration that performs provision and destroy operations and asserts the matching states; nothing currently emits them, and no manual surface can.
  • api:infrastructure:facts — discovered facts landed on the node's properties document and its freshness stamp moved.
  • api:infrastructure:bulk_upsert — a batch register/upsert ran (data carries the item, created, updated and failed counts and the parent path).

Node lifecycle​

  • api:nodes:deleted — a node (subtree) was soft-deleted.
  • api:nodes:restored — a soft-deleted node was restored.
  • api:nodes:destroyed — a node was destroyed permanently.

Workflow lifecycle​

  • api:workflows:destroyed — an archived workflow was destroyed permanently (data: project path, code, name, versions and runs counts, with_runs).
  • warn:workflows:deprecated_approval_gate — a stored workflow version carrying the step-level requires_approval_from: wait gate was composed for a run or a plan. The gate keeps enforcing; the event is the usage evidence behind its staged absorption into approval policies (data: project path, workflow code, version and the gate-carrying step names — never an approver; the conversion path is opschain approval-policies convert-step-gates). Throttled to one event per workflow version per day, estate-wide (the same atomic per-window claim as warn:authz:denied), emitted asynchronously off the compose path.

Templates​

  • warn:template:action_file_invalid — a declarative action file at a template version's pinned commit failed validation or compilation when the version's action catalog was resolved (source: the template version; event_node_path: the owning project; data: file — the repository path, action — the identity it would have listed under, error — the validation error verbatim, template_version_id, template_code, message). Emitted once per template version and file per resolution outcome — the same file with the same error never warns twice, a changed error warns again — never per run or per catalog read; the version's invalid_action_files attribute keeps the list. The broken action lists in the catalog as an invalid entry, a change created from it is refused with the same error, and a workflow step that reaches it ends system_error carrying the error as its last_error_message.

Actions refresh​

  • api:generate_actions_request:create — an actions-refresh task was created.
  • error:generate_actions_request:generate — the refresh failed (with a log excerpt; for a group-routed refresh the fleet cannot serve, the placement verdict naming the required group).
  • api:action_refresh:warn — the refresh completed with a warning.
  • info:action_refresh:skipped — a refresh was skipped (one already in progress for the asset/template-version combination).

Git remotes and credentials​

  • error:git_remote:fetch — a git-remote fetch failed.
  • api:git_credentials:create / api:git_credentials:update / api:git_credentials:destroy — a shared git credential changed (names and kinds only, never values).
  • api:git_credentials:test — a credential's ls-remote probe ran (data: the target url and the outcome).
  • api:git_credentials:extract — a remote's inline credentials were extracted into a shared credential (data: the credential's name/kind, the remote's id).
  • git_credentials:use — a fetch/clone resolved a shared credential (scoped to the remote's project; data: credential id/name, remote name, url).

Authentication​

The client address an attempt came from, resolved behind any trusted proxy, is the actor envelope's client_address ("The audit envelope" above) — the family carries no separate data.source key, so a SIEM rule on the origin of a login keys on actor.client_address.

  • api:auth:login — a successful authentication.
  • api:auth:logout — a caller revoked the session it presented (the AuthService Logout verb — the GUI's logout); data.token_kind names the revoked credential's kind.
  • api:auth:session_refreshed — a session's refresh rotation: the refresh token was redeemed and replaced; data carries the session id, the authentication method and strength and the new refresh generation (the address is the envelope's client_address).
  • api:auth:session_revoked — an explicit session revocation (logout, a self revoke, an admin revoke or the user-disable cascade); data.reason names which.
  • warn:auth:refresh_reuse — reuse detection fired: an already-rotated refresh token was replayed, and the whole session was revoked.
  • api:auth:api_key_created — a native API key was minted (data carries the key id, description and expiry — never the token value).
  • api:auth:api_key_revoked — a native API key was revoked.
  • warn:auth:v1_api_keys_retired — the one-time upgrade report naming the surviving legacy api_key tokens that stopped authenticating, each to be re-minted as a native key.
  • api:auth:mapped_grants_changed — a federated sign-in's mapped grants gained or lost outcomes versus the previous group snapshot: a group edit at the identity provider is a role change the stream attests.
  • warn:auth:login_failed — the provider chain rejected a login (never carries the password).
  • warn:auth:throttled — login backoff engaged (throttling, never hard lockout).
  • warn:auth:provider_unavailable — an identity provider was skipped as unavailable (the mechanical half of break-glass). Throttled to one per 10 minutes against the events table; data.directory names the unreachable directory's host:port, data.error the fault.
  • warn:auth:break_glass — a successful break-glass login; never throttled by sinks.
  • warn:auth:break_glass_refused — a break-glass login refused by the auth.break_glass_networks allowlist.
  • warn:auth:provider_collision — a login whose username an earlier provider in the chain also holds.
  • api:auth:mfa_enrolment_started — a pending TOTP factor was minted for enrolment (the secret never rides the event).
  • api:auth:mfa_factor_activated — a factor was activated by a valid code, with the recovery-code count minted alongside it.
  • api:auth:mfa_factor_removed — a factor was removed from the registry.
  • api:auth:step_up — a session elevation, platform factor and IdP re-authentication alike.
  • warn:auth:step_up_failed — a step-up proof that did not verify (a wrong or replayed code, a mismatched IdP re-authentication).
  • warn:auth:step_up_refused — a floored verb refused for a missing or expired elevation (every expiry-refusal is audited); a refusal driven by an authorisation rule's require_step_up bit names the rule (rule_id, rule_name, rule_path) and the matched action.
  • api:auth:step_up_rule_pass — an authorisation rule's step-up demand met by a live elevation, once per rule and action per request (the rule-layer half of the every-elevation-audited posture).
  • api:users:password_changed — a self-serve password change.

Users, groups and reconciliation​

  • api:users:create — a local user was created.
  • api:users:disable / api:users:enable — a user was disabled/enabled.
  • api:users:update — a user was updated.
  • api:users:reset_password — an admin password reset.
  • api:groups:add_member / api:groups:remove_member — local group membership changed.
  • warn:auth:group_lookup_failed — a group lookup against the directory failed.
  • api:users:create_service_account — a service account was minted.
  • api:users:reassign_automations — a user's standing automations were repointed onto a service account; data carries the target and the per-kind counts.
  • api:users:reconciled — one directory-reconciliation sweep's summary.
  • warn:auth:leaver_disabled — a leaver was disabled by reconciliation.
  • warn:auth:reconciliation_skipped — a reconciliation sweep was skipped.
  • api:auth:identity_rekeyed — a legacy auth_provider='ldap' row linked onto its (connection, entry id) identity (or eagerly by the provider sweep verb).

Authorisation configuration​

  • api:authorisation_policies:create / api:authorisation_policies:update / api:authorisation_policies:destroy — a policy changed.
  • api:policy_assignments:update — a policy's assignment set was replaced.
  • api:authorisation_rules:create / api:authorisation_rules:update / api:authorisation_rules:destroy — a standalone rule changed.
  • api:policy_rules:create / api:policy_rules:destroy — a rule was linked to / unlinked from a policy.

Authorisation denials​

  • warn:authz:denied — a v2 request was refused by the compiled authorisation trie (a deny rendered not_found or permission_denied): the refused procedure, the first denied rule path and action, and the caller's principal id (UUID) and credential kind — never a username or email. Throttled to one event per refused procedure per five-minute window, estate-wide (an atomic per-window claim against the events table, so N replicas emit once): the event is the governance evidence that denials are happening; the Prometheus HTTP counters carry the volume. The emission rides the request tail asynchronously — the decide path itself touches no database. Feeds the dashboard's security-pulse panel and the SIEM lane like any other warn: event. Licence/pack refusals and step-up refusals are not this event — they carry their own types (warn:licence:feature_refused, warn:auth:step_up_refused).

Secrets​

  • api:secrets_providers:create / api:secrets_providers:update / api:secrets_providers:destroy — SecretsProvider connection lifecycle (connection facts only, never a credential; a rotation carries credential_rotated: true).
  • api:secrets_providers:test — a test-verb probe ran; data carries the provider's code and the success flag.
  • api:packs:install / api:packs:pin / api:packs:destroy — installed pack-bundle lifecycle: a verified signed bundle landed in the pack store (name, version, signing key, bundle digest, uploaded filename), a pack's unversioned resolution target was pinned or cleared, or an installed version was deleted. Verification refusals (bad signature, digest mismatch, unknown signing key, missing entitlement, platform too old) are the caller's named error and store nothing.
  • warn:packs:blob_orphaned — a pack-version delete removed the row but the best-effort bundle-blob release failed; the bytes stay orphaned in the blobstore (data.bundle_digest names them) and the delete itself still succeeded. A blob already absent at delete time is a silent no-op, never a warning.
  • api:packs:re_resolve — the bulk re-resolve verb cut new template versions onto an installed pack version; data carries the pack, the target version and one <template code> <new version> entry per cut. Each cut version also carries its own info:template_version:pack_re_resolved event naming the pack, the target version and the source version the cut copied.
  • api:transport_providers:create / api:transport_providers:update / api:transport_providers:destroy — TransportProvider record lifecycle (connection facts and the credential_ref pointer only, never a credential value; an inline rotation carries credential_rotated: true).
  • api:transport_providers:test — a record-validation test ran (no host dialled); data carries the provider's code and the success flag.
  • api:github_connections:create / api:github_connections:update / api:github_connections:destroy — GitHub App connection lifecycle (host, App id, audience and the private_key_ref pointer only, never key material; an inline rotation carries private_key_rotated: true).
  • api:github_connections:test — a record-validation test ran (GitHub never called); data carries the connection's code and the success flag.
  • api:github_trust_policies:create / api:github_trust_policies:update / api:github_trust_policies:destroy — trust-policy lifecycle (claim predicates, service-account id, TTL and enabled state).
  • info:github:token_exchange — a GitHub Actions OIDC token exchanged for a short-lived OpsChain token under a trust policy; data carries the connection, policy, repository, ref, environment, workflow run id, session id and expiry — never token material.
  • warn:github:exchange_refused — a token exchange was refused; data names the connection and the reason (token_invalid, no_policy_match, daily_cap, feature_entitlement, connection_disabled, service_account_unusable) — the licence-side refusals double as uplift telemetry.
  • api:github_connections:provision_webhook — GitHub webhook ingestion was provisioned onto the generic inbound-webhook lane; data carries the connection facts, the inbound connection's code and the executing service account — never the signing secret.
  • info:github:token_mint — a just-in-time GitHub App installation token was minted at step dispatch (the outbound GH_TOKEN lane); data carries the connection, installation id, run id, step id and expiry — never token material.
  • warn:github:mint_refused — a JIT installation-token mint was refused and the step failed by name; data names the connection and the reason (unknown_connection, connection_disabled, feature_entitlement, daily_cap, no_installation_id, key_unresolvable, mint_failed).
  • info:github:attestation — a GitHub-side outcome was attested against a change (AttestGitHubRun / the opschain/attest action); data carries the status, summary, repository, workflow run id and evidence links, sourced at the change.
  • api:jsm_connections:create / api:jsm_connections:update / api:jsm_connections:destroy — JSM connection lifecycle (site base URL, auth mode, project keys and the api_token_ref pointer only, never token material or the account email; an inline rotation carries api_token_rotated: true).
  • api:jsm_connections:test — a record-validation test ran (JSM never called); data carries the connection's code and the success flag.
  • api:jsm_connections:provision_webhook — Jira webhook ingestion was provisioned onto the generic inbound-webhook lane; data carries the connection facts, the inbound connection's code and the executing service account — never the signing secret.
  • info:jsm:internal_comment — an internal note was posted on a JSM request through the audited write door; data carries the connection, request key, comment id and the note's length — never its content (visibility is always internal; the surface has no customer-visible-comment capability).
  • info:jsm:transition — a JSM request moved through a workflow transition; data carries the connection, request key and the transition's id and name.
  • info:jsm:fields — labels/fields were written on a JSM request; data carries the labels and the field names, never field values.
  • info:jsm:resolution — a JSM request was resolved with evidence links: the typed jsm:request reference (relationship resolves) landed on the resolving subject's governance block, the internal evidence comment was posted and the resolving transition performed; data carries the subject, request key, transition, evidence links and the recorded reference, sourced at the resolving subject.
  • api:secrets_provider_bindings:create / api:secrets_provider_bindings:update / api:secrets_provider_bindings:destroy — a scope binding was declared, re-pointed or removed; data carries the scope path and the bound provider's code.
  • api:transport_provider_bindings:create / api:transport_provider_bindings:update / api:transport_provider_bindings:destroy — a transport scope binding was declared, re-pointed or removed; data carries the scope path and the bound provider's code.
  • api:transport_grants:create / api:transport_grants:approve / api:transport_grants:reject / api:transport_grants:revoke — TransportGrant lifecycle (subject, provider pattern, scope, actions, step-up demand and status; a grant carries no credential material). The approve/reject pair is recorded whichever lane finalised the grant: the direct verb or the approvals funnel (quorum completion, rejection, TTL expiry).
  • api:user_vault_credentials:set / api:user_vault_credentials:destroy — a user stored/removed their own interactive-lane vault credential (provider and auth method only, never the value).
  • api:secrets:vault_read — one interactive-lane vault read: the user, the path/key read and which credential identity served it (user | platform) — never a value.
  • api:secrets:decrypt — one interactive cipher-stacking decrypt (the secrets screen's decrypt-for-display): the user, the owner context and the value count — never a plaintext or ciphertext. Encrypt is deliberately un-audited.

Node metadata​

  • api:metadata_profiles:create / api:metadata_profiles:update — a metadata profile was adopted or revised; data carries the key, publisher, version and adoption flag.
  • api:node_metadata:set — field values were written on one node; data carries the node path and every field's before/after.
  • api:node_metadata:bulk_annotate — one node's share of a BulkAnnotate, recorded per node with the same before/after shape plus the selector scope.
  • api:node_metadata:migrate — one node's share of an explicit profile migration, same before/after shape plus the profile key.

All four ride the node's path, so estate-scoped subscriptions match them (object kind node) — "notify security-governance on any reclassification" is one subscription on the metadata event family.

Runner plane​

  • info:runner:registered — a runner registered.
  • info:runner:goodbye — a runner said goodbye (clean stop).
  • info:runner:forgotten — a runner was forgotten by an admin.
  • info:runner:drain_changed — a runner's drain flag changed.
  • info:runner:group_drain_changed — a runner group's drain flag changed.
  • info:runner:group_deleted — a runner group was deleted.
  • info:runner:fleet_quiesced / info:runner:fleet_resumed — this replica's dispatch was held / resumed.
  • warn:runner:fleet_drained — a fleet-wide drain was ordered.
  • warn:runner:aged_out — a registered runner went silent past the liveness window without a goodbye (once per offline episode).
  • warn:runner:log_spool_overflow — a runner's log spool overflowed for an attempt (log lines were dropped).
  • warn:runner:version_skew — a registering or session-establishing runner's build version differs from (or is unknown to) the server's; once per (runner, version-pair), with both builds named in the payload.
  • api:runner_groups:upsert — a runner group was created or updated through the v2 RunnerService (the drain/forget/fleet verbs keep recording the info:runner:* events above).
  • api:runner_attributes:put / api:runner_attributes:delete — a placement-attribute definition was registered or removed through the v2 RunnerService.
  • api:registration_tokens:create — a registration token was minted through the v2 RunnerService; the payload carries the token's fingerprint and scope, never the token value.

Agent plane​

  • info:agent:registered / info:agent:goodbye / info:agent:forgotten / info:agent:revoked — agent lifecycle.
  • info:agent:drain_changed — an agent's drain flag changed.
  • info:agent:channel_opened / info:agent:channel_closed — an agent channel lifecycle.
  • info:agent:chat — an agent chat exchange.
  • warn:agent:transcript_error — a chat exchange's mandatory transcript capture failed to persist (the exchange streamed; the loss surfaces here instead of vanishing).
  • info:agent:adapter_transcript — an AI-type agent's adapter-transit transcript exchange was sealed (lines are redacted before persistence).
  • info:agent:owner_changed — an agent's owning user or team changed.
  • info:agent:invoked — a caller invoked one of an agent's own capabilities through the platform proxy (the minimum-spec surfaces and chat excluded): the chain's root hop for a unit of agent work, carrying the capability, the exchange_id, the caller's principal id and the correlation_id the proxy stamped on the exchange — inherited from the caller's X-Opschain-Correlation-Id, else minted for the invocation.
  • info:agent:request — an agent capability request (a call the agent made through its request lane); carries the correlation_id of the SDK-managed scope it ran under, so the chain reads the agent's governed reads beside the run they led to.
  • warn:agent:request_refused — an agent capability request was refused.
  • warn:agent:type_attestation_refused — the class/type attestation refused an enrolment: an ai-type manifest without its AI disclosures, or a non-ai manifest declaring them.
  • warn:agent:adapter_transit_refused — adapter-transit transcripts arrived from an agent whose manifest does not declare the ai type (the contradiction detected at the adapter seam).
  • warn:agent:tunnel_denied — an agent tunnel was denied.
  • warn:agent:halted / info:agent:halt_resumed — one agent halted / resumed.
  • warn:agent:release_stage_refused — an agent's action, run or governed read was refused by the target environment's release-stage floor: the payload names the release and its stage (empty for an agent enrolled without a release), the floor, the environment and the target path (opschain docs agent-releases).
  • warn:agent:group_halted / info:agent:group_halt_resumed — an agent group halted / resumed.
  • info:agent:rollover_started — a rollover of one lane of the agent to a release started (or was held in the approval funnel: held), with the strategy, the source and target release ids and the rollover's correlation_id — the one chain every step of the rollover joins.
  • info:agent:instance_drained — a rollover drained one instance (instance_id, member_id): in-flight work finishes, nothing new is dispatched to it.
  • info:agent:instance_restarted — an instance re-enrolled from the release its rollover expected (instance_id, the release and its stage).
  • info:agent:canary_held — the canaries run the target release; the rest of the lane waits for continue or abort.
  • info:agent:green_ready — a blue-green rollover's green lane holds the configured number of instances on the target release (green_lane); dispatch still lands on the serving lane and waits for continue (the flip) or abort.
  • info:agent:rollover_flipped — a blue-green rollover flipped dispatch: the two lanes swapped labels in one write (green — the instances now serving, parked — the old ones kept for rollback, relabelled).
  • info:agent:rollover_continued / rollover_aborted / rollover_rolled_back / rollover_finished — the rollover verbs applied; rollover_finished carries the retire_offer (the retirement command offered for the source release, never run).
  • info:agent_release:retired / info:agent_release:revoked (platform path) — a release moved to the ladder's last rung (no new enrolment or rollover to it) / was revoked, with instances_halted — every instance running it halted through the per-agent halt with the typed AGENT_RELEASE_REVOKED reason.
  • warn:agent:rollover_refused — a rollover (or one of its steps) was refused, with a typed reason: stage_policy, release_retired, release_revoked, no_instance, lane_busy, same_release, approverless, strategy, restart_refused (the runtime declined the restart instruction), release_mismatch (an instance came back on a release the rollover did not expect and stays drained), rejected (the funnel refused the held rollover).
  • api:model_providers:create / update / destroy — a model-provider record changed through the v2 ModelProviderService; the payload carries the connection facts only, never the credential. Composed at the API write seam, so these stay out of the fixed-type census below.

Platform postures​

  • warn:platform:halted — a break-glass halt was imposed (actor, plane, scope, reason).
  • info:platform:resumed — a halt was lifted.
  • warn:platform:resume_rate_limited — resume refused by the rate limiter.
  • warn:platform:attempt_disposition — a halt's disposition was applied to a running attempt.
  • warn:platform:agent_verb_escalation — an agent-plane emergency verb escalated.
  • info:platform:attempt_suspended — a running attempt was suspended under a halt posture.
  • warn:platform:halt_fallback — a suspend fell back to a harder disposition.
  • api:platform:quiesced / api:platform:resumed — the system-quiesce barrier closed / reopened.
  • warn:platform:quiesce_aborted — a system quiesce's drain timed out and was aborted.
  • warn:server:secrets_refresh_deferred — a replica's secrets-provider composition refresh failed on a store read (a store outage) and was deferred: the last good composition stayed in force (kept_last_good: true) — or, on a replica that had not yet read a composition from the store, secret resolution refused by name — until the readiness-keyed retry composed afresh. Recorded by the replica (server_name) once the store answers, with failed_at, deferred_for_seconds, failed_reads and the first read's error.

Trust and governance​

  • info:trust:granted / info:trust:revoked — a trust grant was made / revoked.
  • info:trust:grant_proposed / info:trust:grant_approved / info:trust:grant_rejected — the four-eyes grant flow.
  • info:trust:revoke_proposed / info:trust:revoke_rejected — the four-eyes revoke flow.
  • info:trust:assigned / info:trust:unassigned — a trust assignment changed.
  • info:trust:ceiling_set — a per-type tier ceiling was written (the payload carries the previous ceiling).
  • info:trust:node_ceiling_set / info:trust:node_ceiling_removed — a node-classification tier ceiling rule was written / removed (the payload carries the rule's predicates and ceiling, and the previous ones on a rewrite or removal).
  • warn:trust:cap_refused — an agent's governed work request exceeded a grant's rate or budget cap, or a brokered model call exceeded a grant's token budget (the payload names the grant, the cap and the window reset; a token refusal also names the provider and the spend).
  • info:agent_release:ladder_changed — the estate's release stage ladder was replaced (stages, previous) or a rung renamed (renamed_from, renamed_to, releases_attested).
  • info:agent_release:floor_changed — an environment's release-stage floor was set or cleared (environment, floor).

Governance foundation​

  • api:governance_controls:create / update — a control catalog write (retirement is an update).
  • api:attestations:create — an attestation was appended to the evidence ledger.
  • api:evidence_ledger:legal_hold — a ledger row's legal hold was flagged or unflagged (the payload carries legal_hold); both directions are audited administrative acts.
  • api:review_cadences:create / update — a review cadence changed.
  • api:review_campaigns:create / close — a review campaign was opened by hand / closed (closure appends the closing attestation).
  • audit:review_campaigns:approve / reject / flag — a campaign item's decision (retain / revoke / flag) in the shared approval grammar; a revoke's reject payload carries the work_item_id it opened.
  • api:governance_work_items:complete — an operator recorded a work item's by-hand remediation.
  • api:governance_waivers:create — a waiver was granted (never self-granted; time-boxed).
  • warn:review_cadences:lapsed — loud lapse: a review campaign is still open past its due time plus the cadence's grace; emitted once per campaign.
  • warn:governance:ledger_archive_blocked — the retention sweep found the evidence ledger's archivable prefix unverifiable, so nothing was sealed or deleted; restore the database or re-anchor the chain, then the next sweep archives (opschain docs retention).

Change governance​

  • api:approval_policies:create / update / destroy — an ApprovalPolicy write (change-governance determination + step-up).
  • api:asset_owners:create / update / destroy — a subtree owner declaration write (asset-owner determination on /governance/owners<path> + step-up; the update payload carries before/after owners).
  • audit:approvals:pending — a covered create entered the pre-start pending_approval state; the payload carries the fingerprint, the matched policies and the quorum deadline.
  • audit:approvals:approve — an approval row was recorded against the checklist (the lines satisfied and the fingerprint signed ride the payload).
  • audit:approvals:reject — an eligible approver finalised the subject as rejected, with the mandatory reason.
  • audit:approvals:timeout — the quorum TTL expired before the checklist completed; the subject finalised rejected.
  • audit:approvals:lapsed — the approval validity lapsed; every approval row voided and the subject re-gated.
  • audit:approvals:release — an approved subject started (quorum completion, the window sweep, or StartApprovedRun), with its maintenance stamp.
  • warn:approvals:break_glass — the one discretionary lever fired: a held subject released without quorum, with its mandatory reason (never quiet).
  • warn:approval_policies:degraded — policies matched a create while the packs:change-governance entitlement had lapsed; the non-strict create proceeded ungated (the loud-degrade posture).
  • api:governance_metadata:update — a subject's governance block changed; the payload carries before/after.

Recommendations​

  • info:recommendation:filed / accepted / dismissed / expired / superseded — the recommendation lifecycle, one event per transition; the payload carries the filing instance's lane.
  • info:recommendation:duplicate — a second proposal for an open (agent, subject node path, correlation root) key was linked to the open card (duplicate_of) — never a second card, never a second change.

Licence, EULA, packs, database​

  • api:licence:applied / api:licence:removed — a licence was applied / removed.
  • warn:licence:expiring — the licence is in its grace window.
  • warn:licence:expired — the work stop is in force.
  • warn:licence:limit_approaching — usage reached 90% of a finite licensed limit (per-kind used/limit counts), throttled like the expiry warnings.
  • api:eula:accepted — the EULA was accepted.
  • warn:eula:updated — the bundled EULA changed after acceptance.
  • warn:packs:unverified_manifest — a pack's manifest failed signature verification (the pack still runs, ungated and loudly).
  • api:database:maintenance — a database-maintenance run completed.
  • api:database:analyze — an operator ran ANALYZE through the admin plane (v2 SystemService.AnalyzeDatabase or the REST twin); the payload carries the trigger, duration, table count and failures.
  • api:database:vacuum — an operator ran VACUUM through the admin plane; same payload shape.
  • api:database:migrations — an operator applied pending schema migrations through the admin plane; the payload lists the applied versions.
  • warn:database:maintenance — a database-maintenance statement failed.
  • api:logs:migration — a log_lines-backfill phase changed state (started/paused/resumed/completed). The completed event is the verdict: owners verified, lines and bytes written, failures and skips for the migrate phase, owners and lines deleted — plus owners_held, the owners an active legal hold kept unpurged — for the purge phase.
  • warn:logs:migration — the backfill skipped or failed something loudly: a family of groups whose rows cannot become segments, an owner whose pre-existing segments do not match its source rows, a purge owner whose rows drifted from the verified count, a purge owner under an active legal hold (action owner_held — left untouched and unstamped until the hold lifts), or a phase that paused itself on an error.
  • api:logs:migration_start / api:logs:migration_pause / api:logs:migration_resume / api:logs:purge_start — an operator drove the backfill control plane (v2 SystemService log-migration verbs); the payload carries both phase states after the flip.
  • warn:logs:chunks_dropped — log chunks of a step attempt were given up and the attempt's log carries a *** log gap: <n> chunk(s) <first..last> not delivered — <reason> *** marker in their place (step_id, attempt, runner_id, reason, count, first_seq, last_seq — ids and counts only, never log content). The reason class says who gave up: refused_invalid_argument / refused_unauthenticated / refused_permission_denied (the server refused the chunk or the job credential by verdict and the runner reported the loss), spool_unreadable (the runner's on-disk spool entry could not be read back), seal_timeout (the runner's end-of-step flush timed out with chunks still spooled, reported on its result submission), sealed (a chunk reached the server after the attempt's log was sealed — a runner that lost its lease, or a straggler). Once per attempt and reason class, so a burst of refused chunks is one event while every chunk keeps its own marker. A step never fails for a dropped chunk; the marker and this event are the audit record of the loss.
  • warn:logs:ingest_forward_failed — in a multi-replica estate a step's log chunk (or its end-of-attempt seal) reached a server replica that does not hold the attempt's log and could not be forwarded to the replica that does (owner_replica_id, operation chunk or seal, message). The runner keeps re-uploading, so no line is lost while the owner is live; once per attempt per minute. A persistent stream means the owner's peer_url is unset or unreachable from its peers.
  • warn:database:schema_ahead — the server booted against a database schema newer than its own migration set (rollback mode): a newer build migrated this database. Boot proceeds — migrations are additive-only — and the payload carries the database's newest applied migration, the binary's, and the newer versions. Emitted once per boot.
  • warn:database:version_n_minus_1 — the server booted against a PostgreSQL major that is supported only as the previous major (N-1 — 17 while 18.6+ is the minimum for new deployments): boot proceeds, and the payload carries the server version, its numeric form and the minimum so operators can plan the upgrade. Emitted once per boot; an older major refuses the boot instead.
  • warn:database:plan_invalidated — a store transaction failed because PostgreSQL refused a cached query plan whose result type changed under it (cached plan must not change result type, SQLSTATE 0A000 — a column type altered by a migration another replica applied mid-roll) and the server retried it once; the payload carries operation (read/write), sqlstate and the database's message. Emitted once per replica per boot — the first invalidation is recorded, later ones in the same roll are retried silently; the serving pools plan queries so that a column type change cannot raise it, so this event means the retry caught something the plan posture did not.
  • retention:sweep — a retention sweep deleted, expired or released something; the payload is the sweep summary (opschain docs retention).
  • warn:retention:blob_missing — the retention sweep found expiring rows whose blobs are absent from the blobstore: the rows are skipped, never deleted, and the payload names each withheld row and its missing digest.

Notifications​

The notification engine consumes this stream (see reference/resources/notification); its own happenings:

  • api:notification_subscriptions:create / update / destroy / mute / snooze — a subscription changed through the v2 NotificationService.
  • api:notification_routes:create / update / destroy — a delivery route changed.
  • api:notification_team_subscriptions:create / update / destroy and api:notification_team_routes:create / update / destroy — a group-owned team subscription or route changed.
  • api:notifications:read / api:notifications:archive — feed rows were marked read / archived (counts only, never the summaries).
  • api:notification_connectors:create / update / destroy — a channel connector changed through the v2 NotificationAdminService (names and ids only — never allowlists, headers or the signing secret).
  • api:notification_connectors:test — an admin sent a signed test delivery (the target URL and whether it was delivered).
  • api:notification_mandates:create / update / destroy — a mandated subscription changed through the v2 NotificationAdminService (admin + packs:security-governance); deleting one keeps its dispatched evidence rows.
  • api:notification_retention:update — the feed/evidence retention tunables changed.
  • warn:notifications:engine — the engine failed several consecutive sweeps; notification dispatch is stalled.
  • notifications:retention:sweep — the hourly notification-retention sweep archived feed-expired rows and/or deleted evidence-expired rows (emitted only when a pass changed something; the payload carries the effective policy and the counts).

The fixed-type census​

The registry above is prose; the census below is mechanical: every fixed event-type constant in the server source, verbatim. The families composed at runtime — the run, step and API write seams' api:<resource>:<verb> types — are described in their registry sections above and do not appear here. A census gate in the server's own test suite pins this list against the source, so a new fixed event type cannot ship until this page is regenerated with it.

  • api:action_refresh:warn
  • api:admin_queue:sweep
  • api:admin_queue:terminate
  • api:artifacts:create
  • api:auth:api_key_created
  • api:auth:api_key_revoked
  • api:auth:identity_rekeyed
  • api:auth:login
  • api:auth:logout
  • api:auth:mapped_grants_changed
  • api:auth:mfa_enrolment_started
  • api:auth:mfa_factor_activated
  • api:auth:mfa_factor_removed
  • api:auth:session_refreshed
  • api:auth:session_revoked
  • api:auth:step_up
  • api:auth:step_up_rule_pass
  • api:database:maintenance
  • api:database:migrations
  • api:eula:accepted
  • api:generate_actions_request:create
  • api:git_credentials:extract
  • api:governance_metadata:update
  • api:groups:add_member
  • api:groups:create
  • api:groups:delete
  • api:groups:remove_member
  • api:licence:applied
  • api:licence:refreshed
  • api:licence:removed
  • api:logs:migration
  • api:nodes:deleted
  • api:nodes:destroyed
  • api:nodes:maintenance_ended
  • api:nodes:maintenance_extended
  • api:nodes:maintenance_scheduled
  • api:nodes:maintenance_started
  • api:nodes:restored
  • api:notification_connectors:test
  • api:platform:quiesced
  • api:platform:resumed
  • api:secrets:decrypt
  • api:secrets:vault_list
  • api:secrets:vault_read
  • api:steps:abort
  • api:steps:retry
  • api:steps:skip
  • api:steps:start
  • api:steps:success
  • api:steps:waiting
  • api:transport_grants:approve
  • api:transport_grants:create
  • api:transport_grants:reject
  • api:triggers:fired
  • api:users:create
  • api:users:disable
  • api:users:enable
  • api:users:password_changed
  • api:users:reconciled
  • api:users:reset_password
  • api:users:update
  • api:workflows:destroyed
  • audit:approvals:approve
  • audit:approvals:lapsed
  • audit:approvals:pending
  • audit:approvals:reject
  • audit:approvals:release
  • audit:approvals:timeout
  • audit:maintenance:override
  • audit:steps:approve
  • audit:steps:cancel
  • audit:steps:continue
  • audit:steps:reject
  • error:generate_actions_request:generate
  • error:git_remote:fetch
  • error:mint_model_concretise_task:concretise
  • error:template_version:refresh_cancelled
  • info:action_refresh:skipped
  • info:agent:adapter_transcript
  • info:agent:canary_held
  • info:agent:channel_closed
  • info:agent:channel_opened
  • info:agent:chat
  • info:agent:drain_changed
  • info:agent:forgotten
  • info:agent:goodbye
  • info:agent:green_ready
  • info:agent:group_halt_resumed
  • info:agent:halt_resumed
  • info:agent:instance_drained
  • info:agent:instance_restarted
  • info:agent:invoked
  • info:agent:model_call
  • info:agent:owner_changed
  • info:agent:registered
  • info:agent:request
  • info:agent:revoked
  • info:agent:rollover_aborted
  • info:agent:rollover_continued
  • info:agent:rollover_finished
  • info:agent:rollover_flipped
  • info:agent:rollover_rolled_back
  • info:agent:rollover_started
  • info:agent_release:created
  • info:agent_release:floor_changed
  • info:agent_release:key_registered
  • info:agent_release:key_status_changed
  • info:agent_release:ladder_changed
  • info:agent_release:promoted
  • info:agent_release:promotion_held
  • info:agent_release:promotion_rejected
  • info:agent_release:retired
  • info:agent_release:revoked
  • info:github:attestation
  • info:github:token_exchange
  • info:github:token_mint
  • info:jsm:fields
  • info:jsm:internal_comment
  • info:jsm:resolution
  • info:jsm:transition
  • info:platform:attempt_suspended
  • info:platform:resumed
  • info:recommendation:accepted
  • info:recommendation:dismissed
  • info:recommendation:duplicate
  • info:recommendation:expired
  • info:recommendation:filed
  • info:recommendation:superseded
  • info:runner:drain_changed
  • info:runner:fleet_quiesced
  • info:runner:fleet_resumed
  • info:runner:forgotten
  • info:runner:goodbye
  • info:runner:group_deleted
  • info:runner:group_drain_changed
  • info:runner:registered
  • info:server:node_quiesced
  • info:server:node_resumed
  • info:server:site_quiesced
  • info:server:site_resumed
  • info:siem:test
  • info:template_version:refresh_cancelled
  • info:transport:session
  • info:triggers:deferred
  • info:trust:assigned
  • info:trust:ceiling_set
  • info:trust:grant_approved
  • info:trust:grant_proposed
  • info:trust:grant_rejected
  • info:trust:granted
  • info:trust:node_ceiling_removed
  • info:trust:node_ceiling_set
  • info:trust:raise_held
  • info:trust:revoke_proposed
  • info:trust:revoke_rejected
  • info:trust:revoked
  • info:trust:unassigned
  • notifications:retention:sweep
  • retention:sweep
  • warn:agent:adapter_transit_refused
  • warn:agent:group_halted
  • warn:agent:halted
  • warn:agent:model_call_refused
  • warn:agent:model_provider_refused
  • warn:agent:release_stage_refused
  • warn:agent:request_refused
  • warn:agent:rollover_refused
  • warn:agent:transcript_error
  • warn:agent:tunnel_denied
  • warn:agent:type_attestation_refused
  • warn:agent_release:enrolment_refused
  • warn:agent_release:refused
  • warn:approval_policies:degraded
  • warn:approvals:break_glass
  • warn:artifacts:collection
  • warn:auth:break_glass
  • warn:auth:break_glass_refused
  • warn:auth:group_lookup_failed
  • warn:auth:leaver_disabled
  • warn:auth:login_failed
  • warn:auth:provider_collision
  • warn:auth:provider_unavailable
  • warn:auth:reconciliation_skipped
  • warn:auth:refresh_reuse
  • warn:auth:step_up_failed
  • warn:auth:step_up_refused
  • warn:auth:throttled
  • warn:auth:v1_api_keys_retired
  • warn:authz:denied
  • warn:database:maintenance
  • warn:database:migrations
  • warn:database:plan_invalidated
  • warn:database:schema_ahead
  • warn:database:version_n_minus_1
  • warn:eula:updated
  • warn:github:exchange_refused
  • warn:github:mint_refused
  • warn:governance:ledger_archive_blocked
  • warn:governance:ledger_re_anchored
  • warn:licence:expired
  • warn:licence:expiring
  • warn:licence:feature_refused
  • warn:licence:invalid_document
  • warn:licence:limit_approaching
  • warn:licence:revoked
  • warn:licence:verify_failed
  • warn:logs:chunks_dropped
  • warn:logs:ingest_forward_failed
  • warn:logs:migration
  • warn:maintenance:auto_extend_cap
  • warn:maintenance:declared_run_failed
  • warn:mintmodel:actions_unavailable
  • warn:notifications:engine
  • warn:packs:blob_orphaned
  • warn:packs:unverified_manifest
  • warn:platform:agent_verb_escalation
  • warn:platform:attempt_disposition
  • warn:platform:halt_fallback
  • warn:platform:halted
  • warn:platform:quiesce_aborted
  • warn:platform:resume_rate_limited
  • warn:retention:blob_missing
  • warn:review_cadences:lapsed
  • warn:runner:aged_out
  • warn:runner:fleet_drained
  • warn:runner:log_spool_overflow
  • warn:runner:version_skew
  • warn:scheduled_activities:error
  • warn:security:git_remote_refused
  • warn:server:secrets_refresh_deferred
  • warn:siem:delivery_failing
  • warn:template:action_file_invalid
  • warn:transport:cap_refused
  • warn:transport:refused
  • warn:triggers:deferral_expired
  • warn:triggers:depth_cap
  • warn:triggers:identity
  • warn:trust:cap_refused
  • warn:webhooks:refused
  • warn:workflows:deprecated_approval_gate

The retired v1 catalog (removed)​

The parked v1 read families (/api/event_filters, /api/event_subscribers, /api/notification_jobs and their notification_filters/notification_subscribers aliases) are removed (a clean break, no importer). What a filter + subscriber + job expressed is now one v2 NotificationService subscription: the selector grammar picks the events, the subscription's routes pick the channels, and connectors (NotificationAdminService) replace the job/channel catalog. See reference/resources/notification.

Levers, and who owns them​

LeverAuthorityEffect
retention.events_daysconfig.yaml (deploy-authoritative — opschain docs config)Ages events out of the stream (default: never) — and with them the actor envelope's address and user agent.
server.trusted_proxiesconfig.yaml (deploy-authoritative)Which peers' forwarding headers decide the actor.client_address (and every other recorded client address); unset, the TCP peer is recorded.
Notification subscriptions / routes / connectorsv2 NotificationService + NotificationAdminService (opschain docs resources/notification)Who gets notified of what.
emit: steps and opschain step emit-eventThe action author, gated by the custom-type grammar and reserved prefixesPuts domain events on the stream for triggers to match.
Triggersopschain docs triggersTurn events into new runs.

Failure modes​

  • Emission is best effort — a failed event insert is noticed in the server log, never fails the operation it narrates; a degraded database therefore thins the audit trail rather than blocking work.
  • A reserved-prefix custom type is refused at the write gate with the named error (custom event type "<t>" uses the reserved prefix "<p>" — api: system: info: error: warn: are the system's), failing the emitting step rather than polluting the system vocabulary.
  • Secrets never land in the stream: custom event data passes the run's masker before storage.
  • A truncated events page hides older matches — the CLI says so explicitly; raise --limit or tighten --since rather than trusting an empty result.
  • opschain docs resources/event — the full attribute dictionary.
  • opschain docs triggers — matching events into automation, and chains.
  • opschain docs cli/events — the CLI listing and watch loop.
  • opschain docs cli/step-emit-event — emitting custom events from steps.
  • opschain docs retention — how long the stream is kept.