Operate

Installations (End-User Flows)

Quick Answer

Use this guide to model, create, enable, and operate end-user flow installations with profile-scoped inputs and uploads.

An "end-user flow" is a flow intended to be used by others in the workspace.
The end-user tag gates public discover visibility and related install surfaces.

An "installation" is a per-user instance of an end-user flow, backed by an internal
runtime target owned by the subscribing user.

Public Discover Visibility

If an end-user flow should appear in discover/install surfaces, set public discover visibility explicitly.

Authoring options:

{:tags ["end-user" ...]
 :discover {:public true}
 ...}

or after push:

breyta flows discover update <slug> --public=true

Requirements:

  • the flow must be tagged end-user
  • the flow must have an active released version

Checklist to make a flow show up in Discover:

  1. Tag the flow with end-user.
  2. Choose one visibility path:
    • Source-first: add :discover {:public true} to the flow definition before push.
    • Explicit after push: wait until after push, then run breyta flows discover update <slug> --public=true.
  3. Push the flow.
  4. If you chose the explicit path, run breyta flows discover update <slug> --public=true after push.
  5. Release/promote it so there is an installable live version.
  6. Verify it in the web Discover UI. If you have another workspace, you can also confirm with breyta flows discover list or breyta flows discover search <query>.

Use breyta flows show <slug> --pretty to confirm stored metadata includes discover.public.
Use breyta flows discover list or breyta flows discover search <query> to browse the same public installable catalog the web app shows.
This is different from breyta flows search <query>, which only searches approved example flows to inspect and copy from.

Install Surface Copy

Installable flows can expose separate install-facing markdown copy from their normal flow description.

Use:

breyta flows update <slug> --publish-description-file ./publish-description.md

or:

breyta flows update <slug> --publish-description "## Install this flow"

Behavior:

SurfaceCopy source
Discover/install dialogpublishDescription when set
Discover/install dialog fallbacknormal flow description when publishDescription is empty
Discover card/list previewnormal flow description

This lets you keep a short catalog summary while showing richer installation guidance in the dialog itself.

Core Concepts

TermMeaning
End-user flowFlow intended for subscribers.
InstallationPer-user runtime target instance for an end-user flow.
Activation inputsSetup values the installer enters once and reuses on later runs until they change them.
Promote/release behaviorflows promote/flows release advance live and track-latest installations, but do not clear previously configured setup values.

Creator: declare activation inputs (setup form)

Installation setup inputs are declared via :requires with a {:kind :form ...}
requirement. By default, form requirements use :collect :setup, which
means the installer fills them out once during setup and the values are reused
on later runs until the installation is reconfigured.

Use :collect :run when a form input must be provided on each manual run
instead of being saved on the installation. Run-collected form requirements do
not block /launch; they render directly in the launch/run form.

Use :provided-by :author on a requirement when it is satisfied by the flow
author/workspace owner instead of the installation user. Author-provided
requirements do not block end-user setup or /launch.

Example:

{:requires [{:kind :form
             :label "Setup"
             :fields [{:key :region
                       :label "Region"
                       :field-type :select
                       :required true
                       :options ["EU" "US"]}]}]}

{:requires [{:kind :form
             :collect :run
             :label "Run input"
             :fields [{:key :question
                       :label "Question"
                       :field-type :text
                       :required true}]}]}

{:requires [{:slot :ai
             :type :llm-provider
             :label "AI Provider"
             :auth {:type :api-key}
             :provided-by :author}]}

Supported form field types:

:field-typeWhat the installer seesTypical use
:textSingle-line text inputIDs, names, short prompts
:textareaMulti-line text boxLonger instructions or prompts
:selectDropdownRegion, mode, model choice
:booleanCheckboxConfirm/enable flags
:numberNumeric inputLimits, counts, thresholds
:dateDate pickerScheduled/reporting dates
:timeTime pickerClock time inputs
:datetimeDate-time pickerCombined schedule inputs
:resourceSearch/select workspace resourcesFiles or saved results chosen for a run

Resource field notes:

  • Use :field-type :resource with :collect :run.
  • The picker is shown only when a resource field is declared.
  • Use :multiple true when the flow expects a collection of resources.
  • Resource fields default to :file, which covers uploads and persisted blobs.
  • Use :resource-types and :accept only when you need to narrow what the user can select.
  • :accept supports exact MIME types like "application/pdf" and wildcard prefixes like "text/*".
  • When both :resource-types and :accept are present, the selected resource must satisfy both filters.

Example:

{:requires [{:kind :form
             :collect :run
             :label "Run input"
             :fields [{:key :resources
                       :label "Resources"
                       :field-type :resource
                       :required true
                       :multiple true
                       :accept ["application/pdf" "text/plain"]}]}]}

Text-focused example:

{:requires [{:kind :form
             :collect :run
             :label "Run input"
             :fields [{:key :resources
                       :label "Text resources"
                       :field-type :resource
                       :required true
                       :multiple true
                       :accept ["text/*"
                                "application/json"
                                "application/xml"
                                "application/edn"]}]}]}

Inside the flow: how form fields appear in input

Form fields become part of flow/input.

  • :collect :setup fields are available on every run after setup is saved.
  • :collect :run fields are available only for the current run.
  • If both exist, the flow sees one combined input map.

Example:

{:requires [{:kind :form
             :collect :setup
             :fields [{:key :region
                       :field-type :select
                       :required true
                       :options ["EU" "US"]}]}
            {:kind :form
             :collect :run
             :fields [{:key :question
                       :field-type :text
                       :required true}
                      {:key :resources
                       :field-type :resource
                       :required true
                       :multiple true}]}]
 :flow
 '(let [input (flow/input)
        region (:region input)
        question (:question input)
        resources (:resources input)]
    {:region region
     :question question
     :resource-count (count resources)})}

The run input seen by the flow looks like:

{:region "EU"
 :question "What changed since last week?"
 :resources [{:type :resource-ref
              :uri "res://v1/ws/ws-1/file/report-a"}
             {:type :resource-ref
              :uri "res://v1/ws/ws-1/result/summary-b"}]}

Creator: declare per-run inputs for webhook/manual triggers

For triggers that should drive a generic UI/CLI (like an upload form), declare
optional trigger :config :fields.

For manual triggers, the trigger :label is also reused as the primary manual-run CTA
on flow, installation, launch, and setup surfaces. If you define multiple manual
triggers, Resource UI currently uses the first manual trigger label.

Fields are validated and coerced on receipt (for webhooks) and can be used to:

UseDetails
Input UX hintsTell UI/CLI which inputs to request.
File upload shapeEnable multi-file upload with :multiple true.

Example (webhook upload):

{:triggers [{:type :event
             :label "Upload"
             :enabled true
             :config {:source :webhook
                      :event-name "files.upload"
                      :auth {:type :hmac-sha256
                             :header "X-Signature"
                             :secret-ref :webhook-secret}
                      :fields [{:name :files
                                :type :file
                                :required true
                                :multiple true}]}}]}

Notes:

NoteBehavior
:file, :blob, and :blob-ref field typesNormalized as :blob-ref in validation.
Multipart ingestionFlows-api persists file parts and passes blob-ref maps (for example {:path \"...\" :size-bytes 123 ...}).

End user: subscribe + enable (CLI)

StepCommand
1. Create installation (disabled by default)breyta flows installations create <flow-slug> --name "My setup"
2. Provide activation inputs from :requires form fieldsbreyta flows installations configure <installation-id> --input '{"region":"EU"}'
3. Enable installationbreyta flows installations enable <installation-id>

End user: upload files (CLI)

StepCommand
1. Inspect installation triggers and webhook endpointsbreyta flows installations triggers <installation-id>
2. Upload one or more files to webhook triggerbreyta flows installations upload <installation-id> --file ./a.pdf --file ./b.pdf

If the trigger declares exactly one webhook field of type file/blob/blob-ref,
the CLI infers the multipart field name automatically; otherwise pass it:

breyta flows installations upload <installation-id> --file-field files --file ./a.pdf

Related

As of Mar 27, 2026