Playbook: Author Flows
Load when creating or editing a Breyta flow, adding steps, changing inputs,
copying template patterns, or preparing a draft for release.
Mental Model
Flow definitions are a Breyta DSL with Clojure/EDN syntax. They are not normal
Clojure programs. The DSL describes an orchestration graph plus contracts:
:requires, :invocations, :interfaces, :concurrency, reusable
:templates, :functions, packaged :steps, :agents, and finally :flow.
Author with platform limits in mind: deterministic orchestration, explicit step
boundaries, serializable maps/vectors, bounded loops, persisted large payloads,
and live/install targets that may differ from draft.
For first proof, inline small transform functions and step bodies when that is
the shortest path to a green draft run. Extract repeated or bulky pieces into
top-level :functions, :templates, or packaged :steps after the first proof,
before release or marketplace review.
Default Loop
- Start a small session capsule:
- workspace, flow slug, task mode
- intended interface and target
- refs consulted
- chosen pattern
- next proof command
- risks
- Reuse before writing:
breyta flows search "<integration or pattern>" --limit 5breyta flows grep "<literal>" --surface definition,tools --limit 5when metadata is not enoughbreyta flows templates search "<problem>" --limit 5breyta flows templates grep "<step or config>" --surface steps,tools --limit 5when template metadata is not enoughbreyta resources search "<existing data>" --limit 5when prior uploads, reports, or run outputs may be reused- treat hits like
rg: carry forwardhitRef, matched field/surface,
snippet/preview, andnextCommand; open one focused target, not every hit - for existing-flow edits, inspect the current flow before comparing examples
- in clearly empty hosted workspaces, skip proving absence and start from the requested outcome
- Define the contract before source grows:
:requires:invocations:interfaces:concurrency- output shape
- side effects and failure behavior
- Build a minimal draft slice with one manual interface and one meaningful
boundary. Avoid solving every integration in the first flow version. - Run fast feedback before mutating draft:
breyta flows lint --file ./flows/<slug>.clj --local-onlyfor offline static checksbreyta flows lint --file ./flows/<slug>.clj --serverwhen API context is available and canonical pre-push checks matterbreyta flows push --file ./flows/<slug>.cljbreyta flows configure check <slug>when the flow has required slotsbreyta flows validate <slug>after push for stored draft/live validation
- Prove the same entrypoint a user will exercise:
breyta flows run <slug> --interface-id <id> --input '<json>' --wait- omit
--interface-idwhen the single manual interface can be inferred - keep at most one manual interface; use invocation inputs for mode choices
- use
--target liveor--installation-idfor release/install proof - inspect one step with
breyta runs inspect <workflow-id> --step <step-id>
before expanding the full run payload
Stop Discovery When
- you have current state or a clear blank-workspace signal
- one nearby workspace/template pattern is enough
- docs for touched primitives are known
- the next command is an edit, lint, push, configure check, run, or resource read
Do not repeat identical search/help/docs commands unless state or the question
changed.
If development needs excessive trial/error, docs/help are misleading, a command
shape is blocked or unclear, or examples do not cover the authoring path, submit
breyta feedback send with the commands tried, URLs/workflow ids, expected path,
and the friction. This helps Breyta evaluate whether the agent loop is working.
Complex Flow Phase Gates
Complex flows should still move in small slices. Start with this authoring
playbook, then phase-load only the next surface:
- provider/model/API call:
references/provider-api-freshness.md - paging, fanout, child flows, waits, checkpoints, or retries:
playbooks/advanced-reliability.md - persisted reports, tables, files, media, or large outputs:
references/outputs-and-tables.mdandreferences/runtime-data-shapes.md - release, install, public, Discover, or marketplace work:
the release/public playbooks
Before source grows, define a proof ladder and reuse it across steps run and
flows run:
- skeleton interface run with one safe input
- one-record or one-page local JSON fixture
- representative small batch
- empty/failure fixture
- live or install-shaped input
For irreversible side effects such as email, CRM writes, billing, or external
mutations, build preview/dry-run behavior, an approval wait, or an explicit
author approval checkpoint before real writes. Add idempotency keys or dedupe
guards when retries or reruns can repeat a write.
Progressive Disclosure
Use search result cards first. Open the full template/source only for:
- cross-step architecture reuse
- install behavior
- parent/child or fanout structure
- unclear dependencies
- public/marketplace patterns
Prefer primitive snippets and only copy referenced dependencies:
:requires, :templates, :functions, packaged :steps, and :agents.
Do not open a full template definition unless snippet context is insufficient or
architecture, install behavior, fanout, child-flow structure, or unclear
dependencies require it.
For step config questions, use field lookup before opening a full reference:
breyta docs fields httpfor a compact config-object overviewbreyta docs fields http response-as persist retry --format jsonfor selected
fieldsbreyta docs fields files source paths --section readwhen a step page has
operation-specific tablesbreyta docs show reference-step-http --section "Canonical Shape"only when
the field rows are not enough
Single-Step Development
Use single-step commands to reduce full workflow reruns while developing a
touched primitive:
breyta steps run --type <type> --id <id> --params '<json>'breyta steps run --flow <slug> --source draft --type <type> --id <id> --params '<json>'breyta steps run --flow <slug> --source draft --type <type> --id <id> --params-file ./params.jsonbreyta steps record --flow <slug> --source draft --type <type> --id <id> --params '<json>'
Use --flow when the step depends on flow-local :templates, :functions,
:requires, packaged :steps, or installation bindings. Use --source draft
while iterating on a just-pushed draft; use --source active or --version <n>
when verifying released behavior. Add --installation-id <id> when slot-backed
connections should resolve as they will for an installed run.
Use inline --params '<json>' for small inputs. Switch to --params-file when
the payload is long, reused, or easier to edit outside the command line. Build
the params from the smallest input map that exercises the touched primitive.
Good candidates are pure functions, HTTP/API request shape, LLM prompt shape,
file/resource read/write payloads, and notification payloads. Use care with real
side effects, waits, fanout, child flows, callbacks, and params mostly produced
by previous pipeline state.
steps run accepts JSON but normalizes safe step-config keys to the authored
Clojure shape. For example, responseAs becomes :response-as and
persist.type can become :persist {:type :blob}. HTTP payload surfaces such
as headers, query, body, json, and form keep their exact external key
shape.
steps run returns compact output by default: data.resultPreview.value is an
EDN-style preview of the value as it would appear in a downstream let binding.
Use --result-path rows.0 or --result-path '[:rows 0]' to focus one branch,
--preview-depth, --preview-items, and --preview-runes for bounded
expansion, --result-file ./tmp/result.json to keep the full value locally, and
--full only when the complete data.result belongs in context.
Isolated step runs and stored step test verifies are real executions for
accounting: they authorize against workspace billing state, create an audit
workflowId, and count completed or failed step attempts toward step usage.
Single-step proof is not final proof. After the primitive works, push and run
the authored flow interface with the intended target, input, bindings, and side
effect path.
Interfaces First
New callable flows should use :interfaces and :invocations. --trigger-id
is legacy compatibility. For manual smoke runs, prefer --interface-id <id> so
the CLI exercise matches the authored user entrypoint.
Persist And Resource Refs
Default to :persist for unknown or unbounded payloads: exports, paged API
responses, files, transcripts, generated media, long Markdown, or row sets.
Choose blob tier deliberately: retained/default for durable or user-visible
artifacts; :tier :ephemeral on streaming :http steps for temporary downloads,
exports, generated media, and response blobs. Function/table/KV persists remain
retained/default today.
Persisted step results are compact refs. Downstream steps should pass refs
through maps and explicitly hydrate only where needed, for example a function
step with :input {:resp http-step-result} and :load [:resp].
Function Shape
Most runtime values are already Clojure maps. Keep :function steps small:
- use
get,get-in,select-keys,update,mapv, and destructuring - use
json/parseandjson/write-strfor JSON - use
breyta.sandbox/*helpers for common safe utilities - avoid large custom parser/guard layers unless external input is truly ambiguous
Installable Mindset
Assume a new or edited flow may become installable later:
- keep workspace-specific ids, user ids, secrets, emails, private URLs, and model
choices out of source defaults - put installer/user-specific values in
:requires, setup inputs, run inputs,
connections, or resources - split child flows or packaged steps when isolated testing and reuse are clearer
than one large orchestration - keep
:flowfocused on orchestration; reusable structure belongs in
:requires,:templates,:functions, packaged:steps, and reusable
:agents - grouping is mutable display metadata, not source. Verify
groupFlowswith
breyta flows list --prettyorbreyta flows show <slug> --pretty; runtime
linkage still comes fromflow/call-flow,:fanout, or another primitive