Skip to main content

Overview

Flows is the customer-facing workspace for reviewing Genesis flow definitions and recent run history. Use it to see step composition, scheduling, runtime placement, last-run status, and graph-based detail views for both definitions and individual runs.
In auth-enabled deployments, opening Flows requires view_flows. Granting a role access to specific Flows also implies view_flows, so the workspace stays visible when those object-level grants are present.

Interrupted copy recovery

If the server restarts while a bulk_copy or sql step is writing to an external table, Genesis leaves the step interrupted and keeps rows_written unknown. While a qualifying interrupted step is waiting, a background check counts the rows currently held by its target within the first six hours after the interruption and adds that evidence to the step summary. For a bulk_copy that copied a whole named source table, the summary also includes the source count. A query-driven copy is reported with the target count only. The check does not change the step status or turn the count into a rows_written result. Append-mode targets can include rows from before the step, so their target and source counts are not expected to match. Configure the check with jobs.flow_interrupted_copy_target_check.enabled (default true) and jobs.flow_interrupted_copy_target_check.interval_seconds (default 120; 0 or less disables the interval) in Advanced Settings.

What the page supports

Managed source scan types can be added later, but removing an enabled scan type from an existing source is not supported. Delete and recreate the source with the desired scan types. include and exclude selectors on a managed flows source narrow which artifacts Genesis discovers and enables. Selectors without glob metacharacters are exact matches; selectors with *, ?, or [...] use shell-style glob matching against artifact_id, artifact_type:artifact_id, path, and artifact_type:path. exclude overrides include when both match. On the next sync, flows that no longer match are retired: Genesis disables the flow, removes its cron job from the scheduler, and clears managed dependency rows for that source. Retirement applies only to flows this managed source created; a local flow with the same name stays enabled and keeps its schedule.

Git-backed vs Genesis-versioned flows

Flows synced from a managed Git repository show a green git-backed badge on the detail header. Flows authored and versioned inside Genesis show genesis-versioned (gray badge). The modes are mutually exclusive: git-backed flows cannot use Genesis version-history promote, revert, restore-to-draft, or discard-working-copy actions until you copy them to a standalone flow. A synced definition held because auto_promote_on_sync is off has its own review-and-promote action; see Multi-Instance Sync for that lifecycle. Click the badge for a short explainer. On git-backed flows, Fork to standalone → in the badge explainer opens a modal to name the new flow (defaults to <flow_name>-standalone). The flow inspector also exposes a Fork to standalone button for git-backed flows. API: POST /api/flows/{flow_id}/fork with body {"new_name":"<flow_name>"} (requires manage on the source). Agents can use flow_action(action="FORK_TO_STANDALONE", params={"flow_id":"...", "new_name":"..."}). Pause and Resume remain available on git-backed flows. Enabling or disabling a flow is runtime instance state, not a versioned definition change, so you can emergency-stop a scheduled git-backed flow without forking first.

Review a synced Flow change

When a managed source has auto_promote_on_sync: false, a flow with a waiting change shows a pending-promotion status in its row and detail header. Open the flow and choose Review and promote to inspect the incoming definition before making it live. If a promotion was applied but its finishing step did not complete, the header offers Finish promotion. These controls require admin or manage_flows permission. To review a new Flow that has no row in the Flows list yet, use Manage Sources in the page header and open the source’s waiting artifacts. A newly synced Flow can be enabled as part of promotion; that option applies only to new Flows.

Inspect a flow or run

From the Flows tab, click a row or flow name to open the definition inspector. Use the Runs picker to choose any recent run, including the current in-progress run, or click a last-run status badge or a row in Run History to open run details. If no runs exist yet, the picker shows No runs yet. Definition and run graphs can also show dedicated data nodes for declared inputs and outputs, observed run outputs, and data references inferred from supported Python database and dataset calls. Hover a data node to see its direction, source, location, and, when available, rows written. On the Flows page and in Deployments → Flows, clicking a step or data node on the definition or run graph opens a focused inspect modal with Input, Logic (SQL, Python, or bulk-copy metadata from the flow definition), Summary, Output samples, and errors. Use the branch icon in the header or open a flow from the list when you need the full multi-pane inspector with version history and scheduling controls. In the full inspector, clicking a data node still jumps to the related step details. When you select a step node, Genesis can show:
  • connection and execution metadata,
  • the step’s SQL query or Python code,
  • run errors or output summaries,
  • sample output data when the run returns previewable results, including single-object payloads or wider tables in the expanded preview.
When a step retries and eventually succeeds, the output summary records Succeeded after N attempts. Failure payloads shown through the UI and API also redact local absolute paths before they reach the client. For a step that writes rows to an external target, a failed write keeps the Genesis-composed refusal context—such as the step’s mode, connection, table, or statement label—whole, while masking any target-provided text attached to it. For failures composed by the target, Genesis keeps the target’s error codes and any recognised column or query details, while masking quoted values, numbers, and echoed statements on a best-effort basis. A quoted target column name from the rows being written remains visible, compared case-insensitively against the write’s schema, so a failed copy can identify the column without exposing the values beside it. If the message cannot be parsed confidently, Genesis withholds the message and shows the codes instead. The full target error remains available in the server log at DEBUG level; the masked or withheld form is what appears in the run record, activity log, and retry notifications.
SQL and Python logic panels include Copy and Expand controls. Data previews include an explicit Expand button that opens a larger modal for wide tables and longer payloads. When a step writes to a Genesis Dataset and no run sample was captured, Genesis can load a short live preview from the dataset (up to 50 rows) with a View in Datasets link. You can resize the inspector side panel by dragging its left edge. In graph views, dashed edges indicate data links and dashed borders indicate references inferred from code; selected steps show a blue outline on the graph. Step edges animate only while their source step is pending or running and the run is still in progress.
For Python step code, the inspector applies Genesis-aware highlighting to these flow references when they appear: tools.call, flow.emit, from genesis_flow import ..., genesis_flow.llm, genesis_flow.tools, genesis_flow.flow, llm.chat, and llm.complete.
Genesis SDK v1 does not replace the flow-step helpers on this page. Inside flow Python steps, keep using genesis_flow.tools, genesis_flow.llm, genesis_flow.flow, genesis_flow.secrets, and the flow-scoped tokens Genesis injects. Genesis.from_environment() is intended for execute_python_code and external Python programs for now.

Python-step LLM calls

Flow runs stay deterministic by default, but a Python step can make a one-shot model call through genesis_flow.llm.ask(...) when the pipeline needs classification, summarization, extraction, or another bounded LLM step. These calls do not run the full chat agent loop; they route through the Genesis model stack and bill like other base LLM usage. With cost accounting enabled, calls without a real conversation thread are recorded as system work in the Cost & Usage cube rather than as conversation-thread activity.
Omit model_tier and provider to inherit the flow authoring thread’s defaults when available; otherwise Genesis falls back to the flow bot’s default tier and provider resolution. Legacy model="fast", model="main", and model="frontier" are still accepted as tier aliases for older flow code. result.usage includes the resolved provider, model_tier, configured_model, model, total_duration_ms, and token counts when the provider returns them.

Chain the model output vs enrichment-only

Treat genesis_flow.llm.ask results as forward when the next SQL step, Python step, condition, or UI state must parse structured output — use response_format when you need JSON and validate before writing result or flow.emit. Treat the call as side-channel when the text is narrative, audit notes, or optional columns that no branch depends on; downstream steps should succeed even if enrichment is empty. Genesis ships the built-in app-flow-llm-usage AgentSkill (default thread-start on new deployments) with the same guidance for Genesis Apps (/llm/call, /llm/direct) and Flow Python steps.

Team Wiki writes from flow steps

When wiki.write_enabled is true in AppConfig, a Flow Python step (or the sandbox execute_python_code runtime) may call wiki_write through the flow tool bridge if wiki_write is on the step’s signed tool allowlist. Genesis stamps each write with a source_channel provenance tag the agent cannot override: flow:<flow_id> for normal flow steps, or runtime:<execution_id> for sandbox Python execution (the bridge reuses the flow identity with step_name="execute_python_code"). Interactive chat writes keep the default chat tag. Background Librarian extraction from conversations is independent and requires wiki.librarian_enabled in addition to wiki.write_enabled; see Advanced Settings → Team Wiki / Librarian settings.

Persist step output

When a step declares an output target, Genesis expects the step result to resolve to tabular rows shaped as a list of objects. Python steps can return rows directly, or return a dictionary with a row field:
Pair dictionary-shaped results with output.from so the runner knows which field to write:
Supported row result shapes include result = rows, {"data": rows}, {"result": rows}, {"rows": rows}, or a nested dictionary selected with a dotted output.from path such as payload.rows. SQL steps already return list[dict] rows directly, so omit output.from for SQL outputs; from: "data" and from: "rows" are tolerated for compatibility. If a step declares an output target but Genesis cannot extract rows, the run fails with an explicit extraction error instead of silently completing without a dataset write. SQL result column casing follows the underlying connector and database conventions. Some backends, especially Snowflake-compatible paths, may return unquoted aliases such as kind and n as KIND and N. Use quoted aliases in SQL when exact column casing matters. In run results, SQL reads report Query returned N rows, with rows_written set to the number of returned rows. SQL writes report Statement wrote N rows and set rows_written when the engine returns a recognized non-negative write count. If the engine does not report one, the summary says Statement completed; rows written: not reported by the engine and rows_written is null. Counts come from the write statement’s result; rows returned by RETURNING are still available as output but are not treated as a write count. For Databricks targets, a completed Flow step can also provide writer evidence to a Prover comparison when its relation and run timing match the target’s last-write reading and the target snapshot is bound to that step’s connection. See how the Prover attributes a clean table. For Genesis Dataset outputs, table_name controls the table inside the dataset snapshot. If you omit it, Genesis defaults to the explicit dataset_id when provided, otherwise a slug of dataset_name such as Root Directories -> root_directories. If dataset_id is provided and no dataset exists yet, Genesis creates that stable dataset id automatically. If only dataset_name is provided, Genesis derives the new dataset id from the same slug and falls back to a UUID only when that id already exists. This keeps flow-populated datasets queryable with predictable table names. For synthetic data or other publish-style Iceberg flows, prefer one publish step per target table: This sample targets the local catalog. In a Databricks App, the built-in iceberg.genesis_iceberg connection is the persistent Genesis lakehouse on Unity Catalog. Flow outputs that omit connection_id use that connection by default; omit namespace as well to write to the App’s lakehouse schema. An explicit namespace must be that schema, because the App identity cannot access other schemas. See Databricks App deployment guidance.
context_output: "metadata" keeps the full row payload out of downstream step context after the publish succeeds, while preserving rows_written, output_target, and output_location. Use context_output: "sample" when later steps need a small preview, and context_output: "full" only for small row sets that downstream steps truly need. Flow Python steps can emit structured metadata with either flow.emit({"key": value}) or flow.emit("key", value). Downstream steps can read selected values through context/steps, or use explicit input mappings such as inputs: {"previous_rows": "producer.rows"}. Use depends_on to declare dependencies; needs is accepted as an alias. SQL steps use query, with sql accepted as an alias for agent ergonomics. on_failure supports continue, log, notify_thread, pause_schedule, retry, and stop. Set run_concurrently: true on consecutive independent steps to run them as a batch. Genesis runs at most 8 steps in one batch and waits for every step in the batch before starting the next step or batch. Use this for independent bulk_copy steps when several tables share the same flow; do not use it when one step reads another step’s output. Within a batch, bulk_copy steps targeting registered connections (output.target: "external") execute up to 4 at once; bulk_copy steps targeting Iceberg tables still execute one at a time.

Move a table between registered connections

To copy a whole table between two registered connections, use a bulk_copy step. The step reads the complete source relation in the worker and chooses the target writer from the target connection type. Use either source_table for a table-wide copy or query when the source relation needs a projection or filter:
The step requires connection_id, plus either source_table or query. Set mode to replace or append. The output.target can be iceberg or external; an external target also requires output.connection_id and output.table. External bulk writers are available for registered Snowflake, Databricks, and SQLite connections. The default timeout_seconds is 1800. When Genesis validates a flow’s dotted connection ids, it also checks the legacy connection store, so seeded demo ids such as sqlite.baseball_sqlite are accepted. If a connection store cannot be read, Genesis reports that id as unchecked rather than claiming it is missing. Genesis uses this value as the worker deadline, converting it to minutes without imposing a one-minute minimum. For SQL and bulk_copy steps, you can also use a bare registered connection name such as workspace_sqlite; Genesis resolves its registered type before executing the step. The same applies to output.connection_id for an external target. If Genesis cannot resolve an external target’s dialect, it refuses the write rather than guessing how to quote SQL identifiers and values. External output configuration refusals are reported as configuration errors, including missing required fields, unsupported mode or identifier_case values, invalid output.table names, and unresolved target dialects. These errors show the step’s configuration details instead of being withheld as possibly row-bearing target text. If a bulk_copy step is cancelled, Genesis tells the worker to stop and waits up to 30 seconds for the worker’s answer. The worker cancels any statement already in flight and refuses the one final statement that would change the target. Therefore, a copy stopped during staging leaves an existing target unchanged, and a missing target is still missing. The run is marked cancelled and its step summary says that nothing was written. A copy that finishes before the cancellation is answered completes with its rows. If cancellation arrives while the final target statement is already running, the database may commit it before the abort takes effect. Genesis reports that the target may have committed and tells you to verify it before relying on the result or rerunning. A cancelled run does not retry the copy. If the step runs past its wait time or the worker shuts down during staging, Genesis also stops the copy before the final target statement. A hard worker shutdown can leave the temporary stage, Volume, or scratch table behind; remove it after checking the target. These are abandoned copies, not target-side failures. For a Databricks target, add output.staging_volume with an existing Unity Catalog Volume when you want to control staging. Use exactly three name parts: catalog.schema.volume. When it is omitted, Genesis creates a temporary Volume in the target schema and attempts to remove it after the copy. replace uses an atomic target write for Databricks and a transaction for SQLite, so a failed load does not first clear the previous target rows. When the target is missing, Databricks creates it together with the loaded rows in the final statement instead of creating an empty table first. If the source contains text values beside numbers and the existing target column is numeric, Genesis checks the target before staging and refuses the copy with the column names, target types, and text value counts; it does not include the values themselves. The result includes rows_written and execution_mode; rows_written is null when the target does not report a count. When a Databricks bulk copy creates a missing table and its final statement returns no count, Genesis retrieves the created table’s count with a COUNT(*) query. If that query fails, rows_written remains null; the completed copy still succeeds. A failed external write reports the count committed by the target, not the number read from the source: it is 0 when the target is unchanged, a partial count when earlier append batches committed, and null when the target may be empty or incomplete. External target steps do not store output row samples in the run record; use the target connection to inspect the data. When SQLite source columns contain only empty values, bulk copy preserves their declared SQLite types instead of inferring a type from those values. For a source column that is numeric apart from empty-string ('') values, SQLite writes each empty string as NULL. The step result includes values_nulled with each affected column and its count, and the step summary explains the conversion; check it before reconciling by row count alone. For a SQLite source, a column with no non-NULL values (including a column in an empty result) keeps its declared SQLite type when one is available, so a valueless numeric column remains numeric. If a column has no value and no declared type, it is written as text; valueless_as_text and the step summary name that column. A source column containing text alongside numbers is also written as text when the target accepts it; text_beside_numbers reports the text count by column and the summary names the affected columns. A Databricks target with an existing numeric column still refuses such a copy before staging, as described above. Bulk copy keeps Infinity, -Infinity, and NaN as numeric values for Databricks, Snowflake, and Iceberg targets. SQLite stores infinities as REAL, but bulk copy refuses a column containing NaN before opening the target database because SQLite would store it as NULL; nothing is written. Replace NaN with NULL or a number in the source query, or use a target that stores NaN. For a Snowflake target, use a two- or three-part output.table name. A two-part name uses the connection’s CURRENT_DATABASE() value; if no current database is available, name the database explicitly. Snowflake stages the Parquet file in an internal stage that Genesis creates and removes for that copy. append loads the stage directly into the target. replace loads a transient scratch table first, then atomically overwrites the target, so a failed copy does not leave the existing target empty. When the target is missing, Snowflake loads a scratch table first and creates the target with its rows in one final statement, instead of creating an empty table first. Snowflake matches staged columns by name without regard to case. Set output.identifier_case to preserve (the default), upper, or lower when you want Snowflake to apply that case to the target and its newly created columns. Databricks and SQLite accept only preserve on the bulk path. A connection type without a bulk loader, or a bulk loader that cannot honor the requested identifier case, fails the bulk_copy step; Genesis does not silently substitute the row-by-row writer. The result’s execution_mode identifies the native path, such as snowflake_stage_copy_into for append or snowflake_stage_insert_overwrite for replace. The get_connection() handle in a Python step is not an alternative for this transfer: it is read-only for this purpose, its response is hard-capped at 200,000 bytes, and a larger read raises instead of truncating. It exposes query(sql) and cursor().execute(sql), but no connection-level .execute() or commit(). Use bulk_copy for large transfers instead of materializing the source through a Python step. For a Lakebase connection using Databricks App identity, use a Flow SQL step or local Python step rather than a Python sandbox step; see Connections — Databricks Lakebase connections. See Snowflake attribution.

SQL step safety

Flow SQL steps can use the normal query surface, but Genesis now blocks namespace-level CATASTROPHIC statements in both definition validation and runtime safeguards. DROP DATABASE, DROP SCHEMA, DROP CATALOG, and CREATE OR REPLACE DATABASE/SCHEMA/CATALOG require an interactive user_override, so they are not allowed inside saved flow definitions or unattended flow runs. If you need one of those operations, run it directly through chat with _query_database after explicit human approval instead of embedding it in a Flow. Older saved Flows that already contain one of these statements now fail closed at run time instead of executing it.

Definition fingerprints

Genesis exposes a canonical definition_sha256 fingerprint when you create, inspect, update, revert, or validate a flow through flow_action (CREATE, GET, GET_VERSION, UPDATE, REVERT, or VALIDATE_DEFINITION). The hash covers portable execution fields — description, parameters / parameters_schema, steps, on_failure, tags, and schedule when present — and excludes the instance-local Flow name. Use it to confirm that a reviewed candidate matches the definition you are about to apply, revert, or promote.

Flow input parameters

Flow definitions can declare optional parameters_schema entries, or the equivalent parameters alias, so each run starts with typed inputs instead of only raw strings. Each parameter can define type, optional default, and optional required. At run start, Genesis fills defaults, rejects missing required values, and coerces primitive int / integer, float / number, bool / boolean, and str / string inputs before exposing them in the initial step context.
Equivalent shorthand using the parameters alias:
execution_target: "sandbox" runs inside an isolated container. Listing / from a sandbox shows the container filesystem, not the host computer. The local execute_python_code executor confines reads and writes to BOT_GIT_PATH, BOT_REPOS_PATH, and BOT_SCRATCH_PATH (import with from genesis import ...), including writes into the repo working tree; paths outside those roots are refused. For local Python process cleanup, see Code Executor Tools.
For sandbox Python steps, prefer step-level python_packages when you need a small number of extra libraries instead of shelling out to pip manually inside your code. Genesis installs only missing packages, and when you keep the default sandbox image plus a supported data-engineering package set or a driver-bearing connection, it can auto-select the prebuilt genesis-sandbox-data-eng:latest image. For repeatable demos or heavier dependency stacks, still choose an explicit prebuilt image.

Automation surface

Programmatic schedule updates

When you schedule a flow through flow_action, Genesis accepts either a structured cron trigger object or flat cron fields. The flat form supports schedule, cron, or cron_expression, with optional timezone that defaults to UTC. Cron strings must contain exactly 5 fields in minute hour day month day_of_week order. For structured Flow cron triggers, use minute, hour, day_of_month, month, and day_of_week; Genesis normalizes day_of_month to the scheduler’s day field when it syncs the saved Flow schedule. Genesis validates cron field ranges and IANA timezones before it saves the schedule. A SCHEDULE call with an unrecognized params key is refused without changing the schedule.
To remove a flow schedule, pass trigger=null and omit other schedule keys. The REST route PUT /api/flows/{flow_id}/schedule uses the same cron payload shape and also accepts {"type":"interval","seconds":<positive_integer>} when you need a fixed interval instead of cron. New or changed Flow schedules that run more often than hourly need a future end_date inside trigger. Runs less than 5 minutes apart require an end date within 7 days of creation or renewal; runs at least 5 minutes but less than an hour apart require one within 30 days. Hourly and slower schedules may omit it. Cron uses the shortest time-of-day gap, including midnight, even when calendar restrictions separate actual runs. These checks run before saving a schedule or selecting a historical version through revert or promotion. For example, a temporary poller can use {"type":"interval","seconds":60,"end_date":"<future ISO timestamp within 7 days>"}. Supply the complete Flow trigger when renewing it, with the new end date. For intentional ongoing automation, set perpetual:true and a nonempty perpetual_reason explaining the lifetime owner, and omit end_date. Managed Jira and ServiceNow polling Flows use this explicit intent and stop when their configuration disables polling. Existing schedules remain operational after startup until their schedule is edited; edits to unrelated Flow details do not impose a new expiration. Choose a cadence that matches the source’s update rate. Frequent LLM-backed work can consume tokens and encounter rate limits; a Flow can perform direct polling without a new LLM decision for each run. For scheduler audit fields and the MODIFY_JOB renewal operation, see Process Scheduler Tools.

Scheduled flows that use Connections

A flow step that uses a saved Connection resolves the connection’s secret in the context of whoever runs the flow. A manual run uses your identity; a scheduled run executes as a system scheduler user instead. If that scheduler user has no RBAC role bound to the connection, the scheduled run fails immediately with an error like Connection '<type>.<name>' is not available or has no secret access key configured — even though the manual run worked. This is a common next-morning surprise when building a first scheduled pipeline. To fix this before the first scheduled tick, grant the connection a role the scheduler user holds (commonly user) under Roles with Access:
  • In the UI: Config → Connections → [connection] → Edit → Roles with Access.
  • From an agent: connections_action(action="UPDATE", connection_type="aws", name="my_conn", roles_with_access=["user"]). GET returns the current bindings, and rbac_action(action="LIST_ROLES") lists valid role names.
See Connections → Roles with Access.

A run started from a chat reports back to it

When an agent starts a Flow from a conversation, that run records which thread and which bot launched it. The moment the run reaches a terminal status — completed, failed, cancelled, or interrupted by a server restart — a notice naming the run id, its kind and its outcome is delivered into that conversation, and the agent’s next turn sees it. This is what lets an agent say “I’ll report when it finishes” and mean it. It applies on success as much as on failure: before it existed, silence meant either “still running” or “finished and nobody said anything”, which is not a signal anyone could act on. Two properties worth knowing:
  • The notice reaches an active thread on its next tool result. If the agent is mid-turn when the run ends, the full run result is attached to the next tool result. If the thread is idle, the notice arrives as a new turn instead.
  • The notice includes the full run result. It carries the same result that GET_RUN returns, so the agent does not need a second lookup before reporting on the run. Flows → Run History remains available for human inspection.
If the server restarts while a step is running, Genesis marks the step interrupted and leaves rows_written unknown (null). The target may have received the complete write, part of it, or none of it, so verify the target before relying on the result or rerunning the step. A step that was still pending never started and wrote nothing. A run with no launching conversation — a scheduled run, or one started over the API — has nobody to report to and stays silent here. This also applies when an outside caller invokes a Flow through MCP or POST /api/tool_call: even if the request carries a thread id, the caller has no Genesis conversation session to receive a wake. Read the outcome with GET_RUN. Operator notifications below cover unattended scheduled failures.

Unattended failure notifications

Scheduled Flows that fail without anyone watching must still reach an operator. Genesis now posts a baseline in-app notification when an unattended run ends in failed status, independent of the Flow’s on_failure setting. This is separate from the opt-in escalation path (on_failure: notify_thread → flow_failure_notifications outbox → Slack drain job), which stays silent on stock configuration until you wire each layer. When a notification fires, the bell shows title Scheduled Flow Failed and a short message naming the Flow and how many scheduled runs have failed in a row. Genesis keeps error text out of the message body (it can carry query fragments) and stores a truncated copy in notification metadata for diagnostics. Open Flows → Run History or the notification entity link to inspect the failed run. Notification policy is driven by flows.failure_visibility in App Config (config/config-example.yaml): Genesis counts consecutive failures since the Flow last completed successfully. cancelled and interrupted runs are skipped — cancelling one run does not reset a genuine failure streak. Manual runs do not match the default unattended trigger set. A Flow that keeps failing on schedule does not ring the bell on every run. The escalation ladder (first_notify_after_failures, repeat_every_failures) and min_seconds_between_notifications floor cap how often Genesis creates a new Scheduled Flow Failed notification. Between those ladder notifications, failed runs stay deliberately quiet because the operator was already told about the current failure streak. The scheduler subprocess also stands down its generic job-failure bell for those quiet runs, so a Flow failing every minute does not produce one generic alert per minute. If the Flow recovers and then fails again, that new streak is treated as a fresh outage and can alert again. Process restart or eviction of in-memory notification state fails open — an operator who might not have been told may receive another alert. After you see an alert, use the evidence-first RCA tools below — not the notification prose alone — before stating a root cause.

Flow failure investigation and RCA

When a Flow step exhausts retries or a run fails with on_failure: notify_thread, Genesis can deliver a trusted failure alert that includes the durable run ID. When the failed run carries an isolated presenter demo_scope (for example from an RCA demo fixture prepared through the presenter routes), the alert also includes a Demo scope line so operators can tell which presenter session produced the failure. Agents investigating that failure must use the evidence-first RCA tools in flow_tools — not the alert prose alone — before stating a root cause. Recommended workflow:
  1. inspect_flow_failure(run_id=...) — load persisted execution evidence (task definition, error log, retry exhaustion, connection identity, preceding-step context) and receive required_citations (exact label=value strings to copy into finalization). Genesis stamps a thread-scoped inspection receipt in the current thread.
  2. Reconcile and correct — derive the cause from the returned evidence, update the Flow to a newer version, and stage the exact correction against the inspected artifact.
  3. run_flow_rca_verification(...) — the combined finalizer. Pass failed_run_id, root_cause, evidence_citations (every value from required_citations), and remediation_summary. Genesis runs or reuses a linked rca_verification run on the newer Flow version, then durably persists the corrected outcome and protected gold record. A successful terminal receipt (task_durably_complete: true) means the RCA is complete; restate the cited result in the next message and do not call record_flow_rca_outcome.
  4. record_flow_rca_outcome(...) — use only when correction cannot run yet (remediation_status='staged') or when manual recovery is needed after a completed linked verification. Staged outcomes do not create protected gold.
Protected gold is immutable once written. If a follow-up model response fails after verification succeeds, retrying run_flow_rca_verification or record_flow_rca_outcome returns the canonical completed outcome without overwriting the protected record. If a downstream tool reports a missing or mismatched inspection receipt, call inspect_flow_failure again in the same thread before retrying finalization. For tool parameters and response fields, see flow_tools RCA tools in the Genbot Toolkit.

Sharing flows across instances

If your organization runs multiple Genesis instances, flows can be sourced from a shared Git repository so they propagate to every instance through normal pull-request review. The flow YAML uses logical refs like @snowflake.warehouse that resolve per-instance via local bindings, so the repository file stays portable. See Multi-Instance Skill, Flow & App Sync. Flow definition files must be valid YAML. Quote scalar values that contain a colon, such as description: "Global policy: all X", so discovery and sync can read the managed source consistently.