# Workflow Operations

<!-- BEGIN GENERATED: guide-map -->
## Guide map

Read only the section needed for the next decision. Line ranges are exact
for this generated runtime target.

| Section | What it covers | Lines |
| --- | --- | --- |
| [Purpose](#purpose) | Scope, ownership, and the central operating question. | 28-40 |
| [Use This When](#use-this-when) | Tasks and conditions that belong in this guide. | 41-52 |
| [Do Not Use This For](#do-not-use-this-for) | Boundaries and the correct routes for excluded work. | 53-72 |
| [Mental Model](#mental-model) | Concepts and state boundaries needed for correct operation. | 73-105 |
| [Preflight](#preflight) | State, authority, inputs, and readiness to verify before execution. | 106-126 |
| [Risk And Side Effects](#risk-and-side-effects) | Effects, approvals, cost, privacy, and retry boundaries. | 127-150 |
| [Workflow Modes](#workflow-modes) | and `side_effects="plan"`; customer-visible effects are blocked. | 151-167 |
| [Canonical Operating Pattern](#canonical-operating-pattern) | The normal end-to-end execution sequence. | 168-204 |
| [Core SDK Surfaces](#core-sdk-surfaces) | Exact source-backed callable contracts owned by this guide. | 205-221 |
| [Low-Level Client SDK Surfaces](#low-level-client-sdk-surfaces) | These are Python objects and methods used inside generated `workflow.py` files. | 222-244 |
| [Data Contracts](#data-contracts) | Required identities, fields, evidence, handles, and durable shapes. | 245-264 |
| [Examples](#examples) | Representative usage patterns and code. | 265-333 |
| [Verification](#verification) | Evidence required before reporting success. | 334-357 |
| [Troubleshooting](#troubleshooting) | Failure diagnosis and corrective routes. | 358-369 |
| [Related References](#related-references) | Adjacent boundaries and when to cross them. | 370-385 |
<!-- END GENERATED: guide-map -->

## Purpose

This guide owns operating an existing workflow root or generated Workflow Play
project: resolve the root, inspect workflow SQLite state, run or resume a
workflow, repair/replay steps, build a status or report output, and hand
off Play sync when the workspace should stay current. It answers “what should
the agent do with this workflow root right now?”

The workflow root is the durable execution unit. Workspace Play sync is a
separate freshness operation owned by `workflow_schedules.md`; it is not the
same operation as provider execution, sequence staging, sequence publish/send,
or mailbox/domain purchase.

## Use This When

- The user asks to run, resume, repair, replay, inspect, export, report, or
  operate a generated workflow project.
- A task references a local workflow root, `workflow.py`, `state/workflow.sqlite`,
  `run.py`, `operate.py`, `build_report.py`, or a Workflow Play run id.
- You need to explain whether a run created rows, built a Play UI/report, synced
  to the workspace Play library, or staged rows to a sequence source.
- You need the source-backed contract for `vf.workflows.*`,
  `vf.local_store.sqlite`, `Workflow`, `WorkflowHandle`, and `WorkflowContext`
  methods.

## Do Not Use This For

- Creating/scaffolding a new generated Workflow Play root. Use
  `workflow_scaffold.md`, then return here once the concrete root exists.
- Designing a new multi-step GTM flow from scratch. Use
  `workflow_composition.md`, then return here once a concrete root exists.
- Source windows, custom acquisition cursors, object memory, `rows_available`,
  or provider artifact checkpointing details. Use `workflow_sources.md`.
  Do not duplicate provider execution in `workflow.py`; call typed provider SDK
  functions and collect their artifacts/rows through the workflow runtime.
  In short: do not duplicate provider execution.
- Final Play UI design, report schemas, row drawers, charts, maps, or sidecars.
  Use `workflow_reports.md`.
- Sequence source mapping, staging, publish/send, audience repair, or copy
  activation. Use `sequences.md` and `sequence_authoring.md`.
- Queueing many workflow roots together. Use `workflow_queues.md`.
- Same-machine live progress telemetry for an instrumented long-running worker
  or SDK job. Use `logging.md`. This guide owns workflow state and operation
  boundaries; `logging.md` owns the `vf.log.*` producer/consumer contract.

## Mental Model

Separate these operations every time:

| Operation | What it changes | Owner |
| --- | --- | --- |
| Workflow run | Local workflow SQLite rows, steps, events, outputs, and possibly typed provider/SDK jobs if the workflow calls them. | This guide plus provider refs. |
| Report or Play UI build | Local static report files under `reports/<run_id>` or configured output dirs. | This guide for entrypoints; `workflow_reports.md` for output design. |
| Workspace Play sync | Backend Play metadata, synced code revisions, and optional eligible completed Local run evidence and output bytes. | `workflow_schedules.md`; this guide only tells you when Local operation should hand off to sync. |
| Sequence/source staging | Sequence source/import rows and source run ids. | `sequences.md`. |
| Sequence publish/send or sender/domain purchase | Customer-visible activation or paid resource mutation. | `sequences.md`, `mailboxes.md`; explicit confirmation required. |

Generated workflow projects normally contain `config.json`, `workflow.py`,
`run.py`, `operate.py`, `approve.py`, `repair.py`, `replay.py`, `status.py`,
`export.py`, `monitor.py`, `build_report.py`, `serve_play.py`, `adapters.py`,
`README.md`, `inputs/`, `reports/`, `views/`, `state/workflow.sqlite`,
`runs/`, `outputs/`, and `tests/`.
`workflow.py` is the source of truth for custom logic. `state/workflow.sqlite`
stores workflow run state.

SDK auth/profile state stays outside the workflow in the normal SDK profile
database.

`workflow_scaffold.md` owns creating this generated Workflow Play root shape
with `vf.play_scaffold.init(...)`. This guide starts once that root exists.
`vf.play_scaffold.init(...)` always registers a new scaffold and persists its
Play id as `VERBIFLOW_PLAY_ID` in the root `.env`; do not register it a second
time as a default operating step. `vf.workflows.register(...)` is only for a
legacy or hand-authored root that has no Play id, or to promote an existing
hidden Play with `visibility="visible"`. Normal reads and provider calls must
never create a backend Play row merely because the current directory resembles
a workflow root.

## Preflight

1. Resolve the exact workflow root. If multiple plausible roots exist, print the
   root path, workflow name, latest run ids, and one-line purpose for each before
   choosing.
2. Open the root with `vf.workflows.open(path_or_id)` and print
   `workflow_id`, `workflow_name`, `root_path`, `state_path`, `profile`,
   `org_id`, `base_url`, and `last_run_id`.
3. From inside the workflow root, verify workspace identity with `vf.auth.status()`
   and `vf.session.init()`. If slug focus fails, use the workspace UUID from the
   session payload and verify final `org_id`, `org_slug`, and base URL.
4. Read `config.json` and `workflow.py` before running. Print the intended
   source window, mode, final output tables, report path, target sequence id,
   source node id, ingress id, and declared step effects when present.
5. Check provider readiness only for providers the workflow will call, such as
   `vf.crm.status(...)`, `vf.linkedin.status(...)`, `vf.senders.status(...)`, or
   `vf.host.chrome.status(...)`.
6. Before reusing old local rows, prove they satisfy the current source
   contract. If the source contract changed, old downstream rows are not valid
   cache until sampled rows show the required fields and provenance.

## Risk And Side Effects

| Risk class | Examples | Rule |
| --- | --- | --- |
| Local state | `vf.local_store.sqlite`, `workflow.run` with local-only steps, `workflow.reset`, `workflow.export`, status/report files | Safe after root and run id are verified; preserve output paths. |
| Provider or credit job | Workflow steps calling CRM, source, enrichment, web, LinkedIn, host, or artifact jobs | Preview inputs, limits, workspace, `job_id`, `artifact_id`, and row counts first. |
| Workspace Play registration | `vf.play_scaffold.init` (always registers; default `visibility='local_only'`); `vf.workflows.register` only for an unregistered legacy/hand-authored root or visibility promotion | Platform write to Play identity/control metadata. Use the runtime's established authority, preserve the returned Play identity, and never perform a redundant registration after scaffold. |
| Cross-workspace Play transfer | `vf.workflows.transfer(play, target_workspace_id)` | Platform write across the workspace Play record and four credit ledger tables (source/enrichment/enrichment reservations/growth). Caller must be a member of both workspaces. Use only to fix a wrong-workspace registration; the move is atomic but the source workspace loses the historical attribution. |
| Workspace Play sync | `vf.workflows.sync`, `vf.workflows.operate(sync=True)` | Platform write to changed code revisions and optional eligible completed Local run evidence/artifacts. Preview skips final output snapshots. This does not stage, publish, send, or purchase by itself. |

An unchanged local snapshot hash is only a cache hint. Before returning an
unchanged output receipt, the SDK resolves every cached output id from the
durable server run. A deleted or mismatched server output causes an idempotent
republish; an unreachable server fails closed instead of issuing a verified
receipt from local state alone.
| Sequence/source staging | Workflow steps with `effects=("sequence_stage",)` and typed `vf.sequences.*` staging calls | Must use mode/effect policy, idempotency claims, preserved source run ids, and post-stage verification. |
| Customer-visible activation | sequence publish/send, direct sends, sender/channel changes, purchases | Requires explicit human confirmation immediately before the typed SDK call. |

Preview mode must not perform customer-visible mutations. Batch and production
may stage/promote rows only when the workflow declares the effect and uses
claim/idempotency gates. Do not add environment flags that silently skip
batch/production staging; that makes agents confuse “Play sync succeeded” with
“the sequence source was updated.”

## Workflow Modes

- `preview`: small actual run for validation. It uses preview checkpoint scope
  and `side_effects="plan"`; customer-visible effects are blocked.
- `batch`: bounded live/provider acquisition and normal staging boundaries.
  `WorkflowPolicy.batch(...)` defaults to production checkpoint scope and
  confirmation semantics for side effects.
- `production`: activation boundary for fully approved workflows. Keep publish,
  send, purchase, and other customer-visible work as explicit top-level steps.
- `pipelined=True`: runtime scheduling for steps written with streaming
  semantics such as `start_when="rows_available"` and `downstream_ready=True`.
  It does not parallelize arbitrary Python loops. A serial `for` loop that
  starts and waits for jobs remains serial.

Use source budgets and item budgets deliberately: `max_source_rows` bounds
source/artifact acquisition; `max_items` bounds downstream fanout and activation.

## Canonical Operating Pattern

1. **Focus your process on the play before any provider/credit call.**
   `vf.workflows.open(<path_or_play_id>)` is the single focus primitive: it
   returns the local handle AND (by default, `bind=True`) `os.chdir`s into
   the play root and sets `os.environ["VERBIFLOW_PLAY_ID"]` so every
   subsequent SDK call is tagged to this play in the credit ledger. Without
   this, calls made from the agent shell's default cwd write
   `play_id = NULL` and disappear from `vf.billing.cost_by_play(...)`. Pass
   `bind=False` only for pure read-only inspection that must not mutate
   process state.
2. Inspect identity: `vf.workflows.open(...)`, `handle.status()`,
   `handle.errors()`, generated `status.py`, and generated `export.py --json`.
3. Choose the action: new run, resume, repair, replay/reset, status report,
   business report, sync handoff, or sequence activation. Do not combine
   unrelated actions in one hidden helper.
4. For a new run, use `vf.workflows.operate(...)` as the agent path. For
   low-level custom code, use `workflow.run(...)` with an explicit mode/policy.
   Generated `operate.py` is a Local terminal adapter for humans or constrained
   environments.
5. For repair, remember that `retry_errors=True` retries failed work only. A
   completed step will not rerun just because code changed; use `workflow.reset`
   or generated `replay.py --reset-step <step>` before expecting new step code.
6. Build or refresh the report before sync when a Play UI output is expected.
   Preview runs are not final output; run batch or production mode first.
7. Use `vf.workflows.operate(..., sync=True)` as the Local finishing path.
   Inspect its `completion` receipt before reporting success. A final Local Play
   operation is verified only when it names the canonical Play, immutable code
   revision, completed run, and at least one synced declared output. A preview
   has its own `verified_preview` state and must not be described as published.
8. Hand off to `workflow_schedules.md` for recurrence or an explicit hosted
   run. Sync again after any later staging/promotion side effect so `/plays`
   reflects the final source run ids, counts, outputs, and status.
9. Print `run_id`, status, row counts, output paths, `job_id`, `artifact_id`,
   report URL/path, snapshot hashes, Play id, synced output ids, and
   sequence/source ids as applicable.

## Core SDK Surfaces

<!-- BEGIN GENERATED: core-sdk-surfaces -->
| Function | Use When | Inputs | Output And Handles To Preserve | Side Effect | Source |
| --- | --- | --- | --- | --- | --- |
| `vf.local_store.sqlite` | Create or open a workflow-local SQLite store for durable generated workflows. | <strong>Required</strong>: `path` (str \| Path; required): Workflow-local SQLite path used for rows, steps, outputs, and events. Do not point this at the SDK auth/profile database.<br><strong>Optional</strong>: none | `local_store` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.workflows.define` | local_file_write | installed SDK: `verbiflow/local_store.py:29-55` |
| `vf.workflows.list` | List cataloged local workflows. | <strong>Required</strong>: none<br><strong>Optional</strong>: `include_missing` (bool; optional; default `False`): Include catalog records whose root or state file no longer exists. Defaults to false so lists show runnable local workflow projects.; `limit` (int; optional; default `50`): Maximum number of records, preview rows, or results to request.; `tag` (str \| None; optional; default `None`): Optional tag filter. | `workflow_records` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.workflows.open` | read | installed SDK: `verbiflow/workflows.py:443-481` |
| `vf.workflows.open` | Open a workflow and focus the calling process on it: returns the local state handle and (when bind=True, the default) chdir-s into the root + sets VERBIFLOW_PLAY_ID so subsequent SDK calls tag credit to this play. | <strong>Required</strong>: `path_or_id` (str \| Path; required): Workflow root path, state SQLite path, local catalog id, or backend play_id (e.g. `wfp_<slug>_<hex>`). A backend play_id is resolved by scanning the local workflow catalog for a root whose .env carries that VERBIFLOW_PLAY_ID.<br><strong>Optional</strong>: `bind` (bool; optional; default `True`): Focus the current Python process on this play (default true). When true, `open()` `os.chdir`s into the play root and sets `os.environ[VERBIFLOW_PLAY_ID]` so every subsequent `vf.*` call (and any subprocess) tags credit to this play. Pass `bind=False` for a pure read-only inspection that must not mutate process state.; `run_id` (str \| None; optional; default `None`): Optional run id to attach in the opened store. | `workflow_handle` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.workflows.define`, `vf.local_store.sqlite` | local | installed SDK: `verbiflow/workflows.py:795-846` |
| `vf.workflows.operate` | Run or resume an agent-first workflow operation and sync the Play. | <strong>Required</strong>: `path_or_id` (str \| Path; required): Workflow project directory, catalog id, or generated workflow path to operate.<br><strong>Optional</strong>: `auto_repair` (bool; optional; default `True`): Attempt workflow repair actions before resuming the selected run.; `build_report` (bool; optional; default `True`): Build the generated HTML report after the workflow operation.; `dry_run` (bool; optional; default `False`): Validate and summarize the operation without uploading Play sync artifacts.; `mode` (preview \| batch \| production; optional; default `'preview'`): Execution mode for a new workflow run.; `no_network` (bool; optional; default `False`): Do not start a generated workflow run when network isolation cannot be enforced. Existing completed runs may still build local reports while Play sync is skipped.; `register_play` (bool; optional; default `True`): Register/update the workspace Play identity even when the selected run is not eligible for final output sync. Defaults to true, including preview.; `resume` (bool; optional; default `True`): Resume the selected run instead of starting a fresh run.; `run_id` (str \| None; optional; default `None`): Existing local workflow run id to resume, repair, report, or sync.; `sync` (bool; optional; default `True`): Sync changed Play code and eligible completed run output to the workspace. | `workflow_play_operation_result` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data. | platform_write | installed SDK: `verbiflow/workflows.py:2417-2623` |
| `vf.workflows.recent` | List recently updated local workflows. | <strong>Required</strong>: none<br><strong>Optional</strong>: `include_missing` (bool; optional; default `False`): Include catalog records whose local files are missing.; `limit` (int; optional; default `10`): Maximum number of records, preview rows, or results to request. | `workflow_records` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.workflows.open` | read | installed SDK: `verbiflow/workflows.py:501-529` |
| `vf.workflows.register` | Register a local workflow as a workspace Workflow Play. Always writes a play_id so credit attribution works; pass visibility='local_only' to keep the play hidden from the workspace UI. | <strong>Required</strong>: `path_or_id` (str \| Path; required): Workflow project directory, catalog id, or generated workflow path to register.<br><strong>Optional</strong>: `auto_sync` (bool; optional; default `False`): Whether the local Verbiflow daemon workflow-sync service should keep this Play's executable code and eligible completed run outputs current. This is not a server schedule and does not start workflow runs.; `description` (str \| None; optional; default `None`): Workspace-facing Workflow Play summary for reviewers.; `title` (str \| None; optional; default `None`): Workspace-facing Workflow Play title to show in the catalog.; `visibility` (visible \| local_only; optional; default `'local_only'`): Workspace UI visibility. `visible` shows the play in /plays; `local_only` keeps the play registered (and billable) but hides it from the workspace listing. Re-register with `visibility='visible'` to promote a hidden Play once it is ready to share. Synchronization preserves the Play's current visibility unless explicitly changed. | `workflow_play_registration` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data. | platform_write | installed SDK: `verbiflow/workflows.py:1131-1235` |
| `vf.workflows.snapshot` | Build a deterministic local Workflow Play snapshot from local workflow state without uploading it. | <strong>Required</strong>: `path_or_id` (str \| Path; required): Workflow project directory, catalog id, or generated workflow path to snapshot.; `run_id` (str; required): Local workflow run id whose completed state should be snapshotted.<br><strong>Optional</strong>: `allow_non_terminal` (bool; optional; default `False`): Whether draft or diagnostic snapshots may include non-terminal workflow runs.; `include_previews` (bool; optional; default `True`): Whether to include preview rows and table excerpts in the snapshot payload.; `include_runtime` (bool; optional; default `False`): Whether to include runtime diagnostics in the snapshot payload.; `report_dir` (str \| Path \| None; optional; default `None`): Optional generated report directory to bundle with the snapshot.; `snapshot_state` (Literal['final', 'draft', 'diagnostic'] \| None; optional; default `None`): Snapshot lifecycle state to build: final, draft, or diagnostic. | `workflow_play_snapshot` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.workflows.sync` | read | installed SDK: `verbiflow/workflows.py:1060-1128` |
| `vf.workflows.status_report` | Use to render a local static workflow status dashboard from workflow-local SQLite run state. | <strong>Required</strong>: `output_dir` (str \| Path; required): Absolute directory where index.html and sidecar JSON files are written.; `path_or_id` (str \| Path; required): Catalog id, workflow root path, or state SQLite path.<br><strong>Optional</strong>: `run_id` (str \| None; optional; default `None`): Optional run id. Defaults to the latest known run. | `dict` with `html_path`, `status_json_path`, `outputs_json_path`, `events_json_path`, `manifest_path`, run id, status summary, and next action. | local_file_write | installed SDK: `verbiflow/workflows.py:981-1016` |
| `vf.workflows.transfer` | Move a registered workflow play (and every credit ledger row tagged with its play_id) to a different workspace. When called with a local path, also re-pins the play root to the new workspace so future SDK calls bill to the new org. | <strong>Required</strong>: `play` (str \| Path; required): Either the backend play_id (e.g. `wfp_<slug>_<hex>`) or a local path/catalog id. A backend play_id is sent straight to the transfer endpoint; a path/catalog id is resolved through the local catalog so the play_id is read from `<root>/.env` and the play root is re-pinned to the new workspace after the move.; `target_workspace_id` (str; required): Workspace UUID or slug to move the play (and its credit rows) to.<br><strong>Optional</strong>: none | `workflow_play_transfer_response` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data. | platform_write | installed SDK: `verbiflow/workflows.py:1297-1387` |
| `vf.workflows.validate` | Validate a Workflow Play's Python structure and durable runtime contracts before execution. This catches provable structural problems without running the workflow or claiming to verify its business semantics. | <strong>Required</strong>: `path_or_id` (str \| Path; required): Workflow project directory, state path, catalog id, or Play id.<br><strong>Optional</strong>: none | `workflow_validation_report` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.workflows.operate` | read | installed SDK: `verbiflow/workflows.py:849-878` |
<!-- END GENERATED: core-sdk-surfaces -->

## Low-Level Client SDK Surfaces

These are Python objects and methods used inside generated `workflow.py` files.
They are not generated from `@sdk_function` metadata, but they are part of the
workflow authoring contract.

| Client SDK Surface | Use When | Inputs | Output And Handles To Preserve | Side Effect | Source |
| --- | --- | --- | --- | --- | --- |
| `Workflow.step(..., modes=None, effects=(), concurrency=1, batch_size=None, reads=None, writes=None, key=None, start_when="upstream_completed")` | Declare step dependencies, row IO, modes, effects, and streaming readiness in `workflow.py`. | Optional step name/dependencies plus row/effect metadata. `start_when="rows_available"` requires `reads=...`. | Registered step spec becomes part of snapshots and status. Preserve step names because reset/replay uses them. | Definition only until run. | Inspect the installed class source when needed. |
| `Workflow.run(step=None, run_id=None, new_run=True, resume=False, retry_errors=False, limit=None, pipelined=False, policy=None, mode=None, source_window=None, batch_window=None)` | Execute or resume low-level workflow code. | Optional step/run controls, policy/mode, source/batch windows, and retry/pipeline flags. | Returns `WorkflowResult` with `run_id`, `status`, `policy`, `steps`, `errors`, and `.to_json()`. | Local state writes; provider/platform effects depend on step code and policy. | Inspect the installed class source when needed. |
| `Workflow.status(...)`, `Workflow.errors(...)`, `Workflow.next_step()`, `Workflow.rows(...)`, `Workflow.export(...)`, `Workflow.reset(step)` | Inspect, export, or rerun local workflow state. | `run_id`, table/status/limit, export path, or step name depending on method. | Preserve status JSON, error rows, `RowSet` outputs, export path, and reset result. Use `.to_list()` on `RowSet`; do not invent `.records`. | Read or local state write for export/reset. | Inspect the installed class source when needed. |
| `WorkflowHandle.status(...)`, `.errors(...)`, `.latest_run()`, `.status_report(...)`, `.to_json()` | Inspect a cataloged workflow without importing its `workflow.py`. | Optional `run_id`; status report `output_dir`. | Preserve record identity, latest run id, status JSON, error list, and status report paths. | Read or local file write for status report. | Inspect the installed class source when needed. |
| `WorkflowPolicy.preview(...)`, `.batch(...)`, `.production(...)` | Make mode/side-effect/checkpoint semantics explicit. | Optional `source_window`, `batch_window`, `max_source_rows`, `max_items`, `allowed_effects`, `credit_budget`, `pipelined`, `retry_errors`; batch/production also accept `side_effects` and `promotion_source_run_id`. | Preserve `policy.to_json()` in run output and snapshots. | Policy object only. | Inspect the installed class source when needed. |
| `WorkflowContext.rows(table, status=None, limit=None)` / `ctx.save_rows(table, rows, key=...)` | Read/write deterministic local row tables. | Table name; optional row status/limit; write rows as `RowSet` or sequence of mappings plus key. | Returns `RowSet` or upsert result; preserve row counts and table/key names. | Local row read/write. | Use `vf.sdk.describe("ctx.rows")` or `vf.sdk.describe("ctx.save_rows")`. |
| `Workflow.declare_output(...)` / `workflow.declare_output(...)` | Declare the exact final files or inline text that Local sync and Hosted execution must publish. | Stable output id, one of the supported artifact kinds, label, and either `path`, inline `content`, or HTML `entrypoint` plus HTML-only `assets`; optional description and file/HTML row count. | Returns a `WorkflowDeliverable`. The run definition and terminal `WorkflowResult` preserve the same declaration envelope so a reopened Local snapshot or Hosted finalizer publishes it. | Workflow definition only. Publication occurs during sync or Hosted finalization. | Use `vf.sdk.describe("workflow.declare_output")` and `vf.sdk.read_source(...)`. |
| `WorkflowContext.track_job(job, name="job", wait=True, table=None, key=None, materialize_batches=False, downstream_ready=False, ...)` | Track one already-started job and optionally materialize artifact batches for a one-run flow. | `job` (`PendingJob \| Mapping \| str`); optional wait/timeout/preview controls; table/key/materialization controls. `materialize_batches=True` requires table/key. | Records job output, latest status, optional materialized row count, `job_id`, and `artifact_id`. | Local writes plus job polling; provider job already exists. | Use `vf.sdk.describe("ctx.track_job")`. |
| `WorkflowContext.record_job(...)`, `ctx.save_job(...)`, `ctx.record_artifact(...)`, `ctx.save_artifact(...)`, `ctx.save_output(...)` | Preserve job and artifact handles plus durable workflow outputs for status/report visibility. | Names plus `job_id`, `artifact_id`, or an output kind and payload. | Returns durable output records. Preserve output id, job/artifact ids, and payload shape. | Local workflow DB write. | Use `vf.sdk.describe("ctx.<method>")` for the exact method. |
| `WorkflowContext.claim_once(...)`, `ctx.claim_once(...)`, `ctx.complete_claim(...)`, `ctx.fail_claim(...)`, `ctx.confirm_required(...)`, `ctx.interrupt(...)`, `ctx.require_effects(...)` | Make side effects replay-safe and approval-gated. | Claim kind/key, claim token, approval message/key/channel, required effect names. | Preserve `claim_token`, approval key, claim result, and interruption payload. | Local claim/approval state; protects downstream mutation calls. | Use `vf.sdk.describe("ctx.<method>")` for the exact method. |

Progress, milestones, metrics, events, and operation telemetry belong to
`logging.md`. Use that owner for `ctx.progress(...)`, `ctx.milestone(...)`,
`ctx.record_metric(...)`, `ctx.event(...)`, and related contracts.

## Data Contracts

- Preserve identity: workflow root path, `workflow_id`, workflow name,
  `state_path`, runtime authority, `org_id`, org slug, base URL, `run_id`, and
  mode.
- Preserve execution handles: `job_id`, `artifact_id`, output ids, source refs,
  cursor keys, report paths, snapshot hashes, bundle hashes, Play ids, synced
  output ids, sequence ids, source node ids, ingress ids, source run ids, lead
  list/import ids, and credit/usage summaries.
- `vf.workflows.operate(...)` returns a discriminated `completion.state`:
  `verified_preview`, `verified_play`, or `incomplete`. `incomplete` includes
  exact missing receipts and is never a success synonym.
- Canonical rows live in workflow state tables and `workflow_items.payload_json`.
  First-class `data_*` SQLite tables are inspection/materialization snapshots.
- Workflow Play snapshots contain play identity, run summary, steps, operations,
  usage, metrics, outputs, table previews, provenance, definition, and optional
  output bundle files. They must not rely on a local dev server.
- `vf.jobs.result(...)` job handles have no `.status()` or `.to_json()`.
  Workflow run results do have `.to_json()`.

## Examples

Create a minimal local workflow:

```python
from __future__ import annotations

import verbiflow as vf

store = vf.local_store.sqlite("./state/workflow.sqlite")
workflow = vf.workflows.define("audience-build", store=store)

@workflow.step()
def load_inputs(ctx: vf.workflows.WorkflowContext) -> None:
    ctx.save_rows(
        "companies",
        [{"company_domain": "acme.com", "user_count": 5}],
        key="company_domain",
    )

@workflow.step(depends_on=("load_inputs",))
def inspect_companies(ctx: vf.workflows.WorkflowContext) -> None:
    companies = ctx.rows("companies").take(10)
    print("companies:", companies.to_list())

if __name__ == "__main__":
    result = workflow.run()
    print(result.to_json())
```

Plan a high-level operation without running or uploading:

```python
import verbiflow as vf

plan = vf.workflows.operate(
    "/absolute/path/to/workflow-root",
    mode="batch",
    dry_run=True,
)
print(plan["workflow"], plan["would_run"], plan["would_register_play"], plan["would_sync"])
```

Run a bounded batch through low-level workflow code when you are already inside
`workflow.py`:

```python
result = workflow.run(
    policy=vf.workflows.WorkflowPolicy.batch(max_source_rows=250, max_items=100),
    pipelined=True,
)
print(result.to_json())
```

For the common shorthand when the workflow already has a safe default policy:

```python
print(workflow.run(mode="batch", pipelined=True).to_json())
```

The generated Local terminal adapter equivalent is
`python run.py --mode batch --pipelined --json`; agents should call the typed
SDK path unless the environment cannot call the SDK directly.

For source checkpointing examples using `ctx.collect_artifact_job(...)`,
`ctx.collect_host_rows(...)`, `ctx.track_job(..., materialize_batches=True,
downstream_ready=True)`, `object_type="account"`, `identities=("company_domain",)`,
and `start_when="rows_available"`, read `workflow_sources.md`.

## Verification

- Local run: print `run_id`, `status`, failed step/error summaries,
  `workflow.status()`, and `workflow.next_step()` or `handle.status()`.
- Rows: inspect `workflow.rows(table).to_list()` for small samples, row counts
  in status JSON, generated `export.py --all-tables --sql --json`, or
  `store.materialize_sql_table(...)` for SQL inspection.
- Jobs/artifacts: preserve and print `job_id`, `artifact_id`, status, row count,
  and any artifact export path. Use `artifacts_jobs.md` for paging/export.
- Workflow-local progress/events: inspect `workflow.status()`,
  `handle.status()`, generated `status.py`, status-report `events.json`, and
  `outputs.json` for `ctx.progress(...)` records. Use `logging.md` only when a
  separate worker explicitly emits `vf.log.*` JSONL events.
- Report/Play UI: verify generated `index.html`, `play_spec.json`, sidecars,
  row/table counts, and report directory under `reports/<run_id>` or configured
  output dir. Use `workflow_reports.md` for report contract details.
- Workspace Play sync handoff: for `dry_run=True`, verify `code.status`,
  `outputs`, `schedule_ready`, `skipped_reasons`, and `errors`. For real Local
  sync, verify `play_id`, the uploaded code revision, any artifact ids, and
  synced output run ids.
- Activation Gate: if a run staged/promoted sequence rows, verify the typed
  sequence result, source run id, lead list/import ids, row counts, and then
  run Play sync.

## Troubleshooting

| Symptom | First checks | Likely fix |
| --- | --- | --- |
| Wrong workspace or Play appears under another org | Compare root `.verbiflow/context.json`, workflow catalog `org_id`/`base_url`, `vf.auth.status()`, and `vf.session.init()`. | If the Play is already registered in the wrong workspace, move it (and every credit ledger row tagged with its play_id) with `vf.workflows.transfer(<play_id_or_root>, <target_workspace_id>)`. The caller must be a member of both workspaces. For a fresh scaffold, prefer `vf.play_scaffold.init(..., workspace_id=<uuid_or_slug>)` so the play is created in the right org from the start. |
| Code changed but run output did not | Check whether the step was already completed and skipped by resume. | Use `workflow.reset(step)` or generated `replay.py --reset-step <step>`; `retry_errors=True` only retries failed work. |
| Play sync succeeded but sequence did not change | Inspect side-effect outputs for `sequence_stage`, `sequence_import`, source run id, lead list/import id, and row count. | Run or repair the sequence staging step under batch/production policy; Play sync alone never stages rows. |
| Final sync has no Play UI output | Check `reports/<run_id>` and generated `build_report.py` output. | Build the report first, or sync intentionally as evidence-only through the normal `vf.workflows.sync(...)` result contract. |
| Rows are stale after a source-contract change | Sample local rows and provenance fields. | Reset/replay from the changed source step; do not reuse downstream rows that lack required fields. |
| Pipelined run is still slow | Look for serial loops that start and wait for provider jobs one chunk at a time. | Use provider bulk calls, `ctx.collect_artifact_job(...)`, `vf.jobs.stream_rows(...)`, or explicitly bounded concurrency plus `vf.jobs.wait_many(...)` where the provider surface supports it. |
| Play sync accepts the wrong payload | Check that the local workflow has a valid `WorkflowPlaySnapshot` from `vf.workflows.snapshot(...)` and a publishable report bundle when needed. | Use `vf.workflows.sync(...)` for the normal path; do not call private snapshot upload helpers directly. |

## Related References

| If you are doing this | Read next |
| --- | --- |
| Broad workflow/play routing | `workflows.md` |
| Creating a new generated Workflow Play root | `workflow_scaffold.md` |
| Source windows, checkpointing, object memory, `rows_available`, artifact collection patterns | `workflow_sources.md` |
| Designing or refactoring a multi-step GTM workflow | `workflow_composition.md` |
| Queueing several workflow roots | `workflow_queues.md` |
| Recurring/later execution or workspace server schedule CRUD | `workflow_schedules.md` |
| Final Play UI/report output design | `workflow_reports.md` |
| Job/artifact wait, page, stream, export, or staging handles | `artifacts_jobs.md` |
| Same-machine live progress telemetry for an instrumented long-running job | `logging.md` |
| Already-acquired row shaping or qualification | `row_operations.md` |
| Sequence staging, publish/send, and audience repair | `sequences.md` |
| Workspace auth/profile/root-context safety | `auth.md` |
