Runtime Data Shapes
Use this page when authoring function steps, passing persisted refs, or reading
CLI/API output without adding redundant parser code.
Default Assumption
Breyta flow values are usually Clojure maps and vectors already. Prefer map
access over defensive string parsing:
(let [customer-id (get-in input [:invoice :customer-id])
rows (:rows table-result)]
{:customer-id customer-id
:row-count (count rows)})
Only parse JSON when the value is actually a JSON string or bytes.
Common Runtime Shapes
| Source | Shape |
|---|---|
flow/input | run input map declared by :invocations |
| step result | Clojure map, vector, scalar, or persisted ref map |
:http inline result | map with status, headers, and body fields when not persisted |
| persisted blob result | compact ref map with :uri or :resource-uri plus metadata |
| persisted table result | table ref plus preview/count metadata |
| CLI command result | JSON envelope with ok, data, meta, and optional links / error |
Ephemeral Local-Literal Step Runs
breyta flows steps run <slug> <step-id> sends the complete local source as
args.flowLiteral to steps.run. The API validates that literal in memory,
resolves the qualified step id from the top-level :steps vector, and executes
it through the normal runtime without creating or updating a flow draft. The
response identifies this explicitly:
{
"data": {
"stepType": "function",
"stepId": "tools/add-one",
"flow": {
"flowSource": "literal",
"persisted": false,
"sourceHash": "sha256..."
},
"result": {"answer": 3}
}
}
This is a proof surface, not a second manifest. The local .clj file remains
the source of truth; use breyta flows push --file ... when the source should
be persisted as the workspace draft.
Step Run Result Preview
breyta steps run is optimized for authoring loops. Default output omits the
full data.result and returns data.resultPreview instead:
{
"data": {
"resultPreview": {
"binding": "make-output",
"format": "clojure-value-preview",
"value": "{:rows [{:id \"row-1\", :score 0.92}], :summary \"ready\"}",
"truncated": false
}
}
}
Read resultPreview.value as the value shape you would bind from
(flow/step ...) in DSL code. The command still returns JSON as a transport
envelope, but the preview uses Clojure map/vector notation so access patterns are
obvious:
(let [make-output (flow/step :function :make-output {...})
first-row (get-in make-output [:rows 0])]
{:id (:id first-row)})
For selective expansion:
--result-path rows.0or--result-path '[:rows 0]'previews one branch--preview-depth,--preview-items, and--preview-runesraise bounded caps--result-file ./tmp/result.jsonwrites the full result locally without
putting it in the CLI output--fullrestores fulldata.resultoutput
Run and step preview surfaces redact secret-like map values before returning
them to CLI/API/UI clients. Keys such as authorization, developer-token,
api-key, token, password, and secret render as [REDACTED] in
resultPreview, run events, run step output, and run inspection output.
Inline --params '<json>' is fine for small input maps. Use --params-file for
larger or reused inputs.
Resource Refs
Persisted outputs are passed as compact refs, not full payloads. Treat any
res://... URI or map with :uri / :resource-uri as a handle that can be
read later.
In source, pass the step result map forward:
(let [resp (flow/step :http :fetch
{:url "https://api.example.com/export"
:method :get
:persist {:type :blob}})
summary (flow/step :function :summarize
{:input {:resp resp}
:load [:resp]
:code '(fn [{:keys [resp]}]
{:bytes (:size resp)
:resource (:uri resp)})})]
summary)
Use :load only where the downstream step needs hydrated content. Many steps
can pass refs through without loading the full body.
For application/json resources, :load [:field] hydrates parsed data. When the
next API needs the original file contents, such as a GitHub Contents update for
package-lock.json, use :load {:field :text} or {:field :raw} to receive the
raw UTF-8 string instead. For binary files (docx, xlsx, pptx, pdf, images) use
:load {:field :bytes}; :text/:raw UTF-8-decode and corrupt them. Pair with
breyta.sandbox/base64-encode for APIs that take base64 or data: URIs.
Blob refs also carry storage-tier meaning: retained/default for durable or
user-visible artifacts; ephemeral for temporary streamed HTTP blobs:
(flow/step :http :download-export
{:url "https://api.example.com/export.zip"
:method :get
:response-as :bytes
:persist {:type :blob
:tier :ephemeral}})
When a later function turns that ephemeral source into a final report, image, or
table for users, persist the derived artifact intentionally on the retained
default path.
JSON And Sandbox Helpers
Inside function steps:
- use
json/parsefor JSON strings or bytes - use
json/write-strwhen a downstream API needs a JSON string - use
breyta.sandbox/*helpers for safe base64, hex, SHA-256, UUID, and
instant parsing utilities - keep functions small and domain-focused
Avoid hand-written parsers for values already represented as maps.
Bounded Output
Inline final output should be compact and user-facing. Large reports, tables,
exports, generated media, and page sets should be persisted and returned as refs
or viewer-friendly artifacts.
For human-readable tables, return a persisted table resource. Do not return a
giant inline JSON table as the final artifact.
CLI/API Envelope
Most CLI JSON output follows this shape:
{
"ok": true,
"data": {},
"meta": {},
"links": {}
}
Use data for facts, meta.nextCommands for the next small command, links
for URLs, and error for failed requests. Search/list commands are compact by
default; use explicit --full, --limit, or read/show commands when deeper
context is needed.