Skip to main content
The model in one sentence: each conversation has a disk. Add files and attach them to a run; the agent reads them and writes outputs to the disk; everything stays on the disk for the whole conversation. You never create or name a “workspace” on the normal path. A run makes a disk for you, invisibly, and keeps it for the conversation. (The only time a workspace becomes visible is when you deliberately share files across different conversations — see the bottom.)

Where an agent’s answer comes back

Every run has a short result string. For anything bigger, browsercode writes a file, and that’s what you fetch.

Give an agent a file

Two steps: add the file, then attach its id on the run. Adding is a presigned-URL flow — request a URL, PUT your bytes to it.
No workspace_id. Adding a file gets you an id; attaching it on a run is what makes the agent get it. Add many at once ({"files": [{"name":"a.csv"},{"name":"b.csv"}]} → many ids) and attach them all.
Attach a bad id and the run still starts (202) — the unknown ids come back in missingFileIds on the create response. Always check that array; a missing file is not an error status.

Get output files back

Files the agent wrote come back from the run’s files endpoint. Filter kind=output for what the agent produced (kind=input is what you attached).
downloadUrl is a presigned, expiring link you GET directly (the Python SDK exposes it as download_url) — it points straight at storage, not at a Browser Use endpoint. If it expires, re-list to get a fresh one.

Structured output from browsercode — it’s a file

browsercode has no structured_output parameter. To get structured data, put the shape in the task and tell it where to write it, then fetch that file:
browsercode’s output is always files — a CSV, a report, a chart PNG, a schema’d output.json. Name the file in the task, fetch it with ?kind=output. browser-use answers inline via the result string — describe the exact JSON shape you want in the task text and parse result (a structured_output request parameter is not available yet).

Files carry across the conversation

Attach files on the first run, then continue with session_id — later runs share the same disk, so they see everything earlier runs added or produced. To add more files mid-conversation, add them (POST /agents/{agent}/files) and attach them on your next run.
curl
Files share the conversation’s disk, so writing the same path twice overwrites it. If two runs both write output.json, fetch the first run’s output before the second run reuses that name.

Output files vs. browser downloads — two different things

Rule of thumb: the agent made it → output files (?kind=output); a website gave it to the browser → downloads (see Manage a browser).

Hand off from one agent to another

A common workflow: browser-use scrapes data, then browsercode processes it. They’re separate agents, so the handoff is explicit — pass the first agent’s result into the second. The clean way: have browser-use return the data as JSON in its result (describe the shape in the task), then feed it into browsercode’s task or attach it as a file.
Two different agents don’t automatically share a disk — each conversation’s disk is its own. To move data between agents, carry the result across (inline for small data, a file for large). For a disk deliberately shared across agents/conversations, use an explicit workspace (below).

Sharing files across conversations (advanced)

Everything above keeps files on one conversation. If you want a file library reused across different conversations — or to pre-load a large dataset before your first run — create an explicit workspace:
curl
This is the only time you handle a workspace_id. ~95% of usage never needs it — a conversation’s disk is automatic. Create a workspace only for cross-conversation sharing.