Files and media
ECP (Execution Control Protocol) does not shove file bytes through the workflow graph. Steps pass a ticket (FileRef) that says where the bytes live. When a capability needs the file, it turns that ticket into bytes with resolveFile.
Think coat check: the workflow carries the stub; the coat stays in a locker until someone needs it.
FileRef kinds
A browser upload usually becomes:
ecp://browser/... is not Azure and not a filesystem path. It is a private locker id in the run-scoped blob map (ctx.blobs).
Resolve and write
Extensions should not invent their own fs / fetch / artifact maps. Use core:file.path may be a Node path or an ecp://browser/<id> locator. artifact.uri may point at run artifacts, ecp://storage/…, or the same browser locator shape when bytes live in ctx.blobs.
Host disk storage (~/.ecp)
When a step writes media through writeMediaArtifact (Sharp, Azure download, and similar), bytes go through @executioncontrolprotocol/storage on the host:
URI shapes for media:
- Temp:
ecp://storage/temp/<key> - Durable:
ecp://storage/artifacts/<key>
.workflow.ts). Download can export Fluent or a plain workflow manifest JSON. In the browser demo:
- Save (paired with
ecp up) writes Fluent to~/.ecp/workflows/<id>.workflow.ts - Download asks TypeScript (default) or JSON — one representation only
- Open lists host-saved workflows and compiles Fluent back into the editor; drag a
.workflow.tsor.workflow.jsononto the canvas to reload
ecp up creates the home layout and wipes only ~/.ecp/temp. It binds storage so the browser demo can hop write/read, save workflows, and preview via GET /v1/artifacts. For large cloud-to-cloud flows, prefer Azure SAS URLs so bytes never enter the host.
Override the home directory with ECP_HOME when needed.
Browser upload to Azure
@executioncontrolprotocol/azure-blob-storage uploads with a mixed capability: some work stays in the tab, and signing hops to a trusted host.
1. Pick a file
The UI (or your app) createsecp://browser/<id>, stashes the real File in a blob map, and puts only the ticket into workflow input — not base64 in the form.
2. Run mixed upload
On the browser graph,upload reads the stashed file, then calls create-sas-url with write permissions (c + w).
3. Keys stay on the host
create-sas-url is host execution. From the browser that call goes to ecp up, which holds the Azure connection string or account key and mints a temporary SAS URL. The tab never sees the account key.
4. Browser talks to Azure
With the write SAS, the browserPUTs bytes straight to Azure Blob Storage. Bytes go browser → Azure, not browser → ECP host → Azure.
Container CORS must allow your origin for PUT, expose ETag, and allow x-ms-blob-type and Content-Type.
5. Optional read link
IfcreateReadSas is set, the host mints a read SAS. Downstream steps (for example Firefly or Photoshop) get an HTTPS URL they can fetch — still without Azure keys in the browser.
Why this design
- Workflows stay portable — JSON and Fluent carry tickets, not giant payloads.
- The browser stays safer — account keys never leave the host.
- Large files stay efficient — upload goes client → cloud; the host only signs.
- One media language — Sharp, model providers, Azure, and other extensions all use
resolveFile/writeMediaArtifact.
One-sentence model
You upload a file → ECP gives the workflow a coat-check stub (ecp://browser/…) → Azure upload asks the trusted host for a temporary door key (SAS) → the browser opens Azure’s door and hangs the coat itself.
Related reading
- Extensions —
local/host/mixedexecution and package graphs - Environments — bind extensions and secrets on the host
- Security — secrets stay out of workflows
- Browser demo — try uploads in the hosted demo
- Azure Blob Storage extension — bind config and capability details