File transfer
upload and download print a one-time browser URL. The person uses their own machine. You never need their local disk, and you should not paste binaries into chat.
There is no upload --to. The path is the first argument. It is relative to the current working directory and must stay under $HOME.
MCP write_file / read_file are UTF-8 text only. Use transfer for CSVs, zips, images, and anything awkward to paste.
Done looks like
- In:
upload poll IDprints success and the file exists at the path you named. - Out: the person opens the URL once and the browser saves the file (or a
.tar.gzfor a directory). No poll step.
Worked example: get a spreadsheet in
Job: a human has q2-leads.csv on their laptop. You need it at inbox/q2-leads.csv.
upload inbox/q2-leads.csv
Expected shape:
Open this URL in your browser to upload (repository members):
https://…/sails/transfer/…
Target: ~/inbox/q2-leads.csv
Transfer session: 3f2a9c1e-…
Send that URL. They sign in as a repository member and drop the file. Then:
upload poll 3f2a9c1e-…
When poll returns success, the file is in the live workspace and autosave has it.
Do not pass --wait from bash_exec. That call buffers until the upload finishes, so you never see the URL.
Hand a file out:
download inbox/q2-leads.csv
# one-time URL; first successful GET consumes it
download ./site
# browser saves site.tar.gz
Commands
upload help
download help
| Command | What it does |
|---|---|
upload PATH | One-time URL for a single file at PATH |
upload PATH --dir | One-time URL for a directory (folder picker or .tar / .tar.gz / .tgz) |
upload poll ID | Block until that upload finishes, fails, or expires |
upload PATH --wait | Block in one command — avoid inside bash_exec |
download PATH | One-time URL; directories become .tar.gz |
Common flag: --timeout SECS (default 900). After that the session expires; run the command again.
Auth: the person must be signed in as a repository member. Hard size limit: 100 MiB. Uploads write into the live session and trigger autosave.
Failure modes
| What you see | What it means | What to do |
|---|---|---|
You used upload --to DIR | That flag does not exist | upload DIR/filename or upload DIR --dir |
| Browser asks to sign in / 403 | Transfer URLs are for repository members | They must be signed in as a member of this repo |
| Link dead on second open | Single-use (download completes on first GET) | Run upload / download again |
upload poll times out | Nobody finished the browser step, or --timeout elapsed | New upload PATH, new URL |
| Path rejected | Outside $HOME / the active repo mount | Use a path under the workspace |
| 100 MiB exceeded | Hard limit | Split the archive, or curl -o a public URL |
When not to use this
| Job | Use instead |
|---|---|
| Small text already in chat | MCP write_file / edit_file |
| File is already on the public internet | curl -o path https://… |
| API key, token, DSN | secret open — see Store a secret |
| Public URL for a folder | Publish a site |
| Another repository should copy a folder | Share a directory with another repo |
How to: Send a file.