Skip to main content

Self-hosted file handoff server for AI agents — temporary upload and download links for agent↔user file exchange

Project description

Agent File Bridge

Turn a local file into a temporary download link. Create a browser upload page so someone can send files back. No cloud, no accounts, no re-uploading what's already on disk.

# share a file that's already on the server
afb share ./report.docx --ttl 1h

# let someone upload files to the server
afb upload-session --ttl 1h --max-files 5

Why

Chat platforms have file-size limits, MIME blocks, and silent failures. Worst part: an agent generates a file on a server, you download it from the server, then upload to the chat. Every time.

Agent File Bridge inverts that. The agent runs a tiny server, points at a local path, and gets back a URL. No upload step. No S3 bucket. No cloud.

Agent: "I have a file at /tmp/output.docx"
  → afb share /tmp/output.docx
  → "https://files.example.com/d/abc123" (expires in 1h)
  → send that URL to anyone

Reverse direction works too — someone with a browser uploads files straight to the server's filesystem. Uploaded files get scanned for viruses before the agent touches them.

Quick start

pip install agent-file-bridge

mkdir -p ./uploads
AFB_BASE_URL=http://127.0.0.1:8765 \
AFB_ALLOWED_ROOTS=$PWD,/tmp \
AFB_UPLOAD_DIR=$PWD/uploads \
afb serve --host 127.0.0.1 --port 8765

Or install directly:

curl -fsSL https://raw.githubusercontent.com/wmyung/agent-file-bridge/main/install.sh | bash

Commands

afb serve [--host] [--port]                       # start the server
afb share <path> [--ttl] [--max-downloads]        # create a download link
afb upload-session [--ttl] [--max-files] [--max-size-mb] [--ext] [--webhook-url]  # create an upload page
afb upload-status <session-id>                    # see what files arrived

Each link is a random bearer token. Anyone with the URL can access the file until it expires or hits the download limit.

How it's different

Other tools (transfer.sh, Plik, etc.) make you upload a file to get a link. That works for humans, but it's wasted work for an agent that already has the file on disk.

Tool How it works Best for
transfer.sh, Plik Upload → link Human-to-human
Magic Wormhole CLI-to-CLI tunnel Two technical users
File Browser Full web file manager Browsing files
S3 presigned URLs Signed URL from object storage Cloud workflows
Agent File Bridge Point at a local path → link Agent-to-human, agent receiving files

Network requirements

Both sides of this tool — upload and download — depend on the same thing: the server must be reachable over HTTP. Here is what each direction needs and what changes based on your server environment.

Download (server → someone)

afb share ./report.pdf
# → https://your-server/d/s0meT0ken

Someone with that URL sends a GET request to your server. That is all. No authentication, no client setup.

Upload (someone → server)

afb upload-session --ttl 1h
# → https://your-server/u/s0meT0ken
# → open in a browser → file picker → POST to server

Same requirement as download — the server must accept TCP connections from the person holding the URL.

Environments by network exposure

Server type Public IP Needs extra tooling? Notes
VPS / cloud VM (DigitalOcean, Linode, AWS EC2, GCP, etc.) ✅ Yes Depends on firewall If the firewall allows the port, the URL works globally as-is. If ports are locked down, open the firewall or use a tunnel.
Bare-metal server with public IP ✅ Yes No Best case. afb serve --host 0.0.0.0, open the port, done.
Home server behind NAT ❌ No Yes — tunnel (ngrok, Cloudflare Tunnel, Tailscale Funnel) or port forwarding The server has no public address. A tunnel relays traffic to it.
Office / corporate network ❌ No Yes — same as home NAT, plus possibly corporate firewall rules Same problem as home NAT, often stricter egress rules.
Localhost (same machine) N/A No AFB_BASE_URL=http://127.0.0.1:8765 — only the local machine can reach it. Great for agent ↔ human on the same computer.
LAN / VPN (same private network) N/A No AFB_BASE_URL=http://192.168.x.x:8765 — anyone inside the same network can reach it. No public exposure.

What this means in practice

  • Same machine (localhost): pip install + afb serve → everything works. Agent and user share the same filesystem. This is the simplest setup.
  • Same private network (LAN / Tailscale / ZeroTier): afb serve --host 0.0.0.0 → anyone on the network can download and upload. No tunnel needed.
  • Public access from anywhere: You need a VPS or a server with a public IP, or a tunnel to a NAT-ed machine.
  • Public IP but firewall locked: Open the port in the firewall, or use a tunnel. The server already has a public address — it just needs to be reachable.

Tunnels vs direct access

A tunnel (ngrok, Cloudflare Tunnel, Tailscale Funnel) creates a public URL that relays traffic to your private server. This works everywhere but adds latency, a bandwidth limit, and a third-party dependency.

Direct access (public IP + open port) needs no relay — just the server itself. This is the production setup and what the tool assumes by default.

Summary

Upload and download are the same requirement: can the server accept an HTTP request from the person holding the URL? If yes, both work. If not, neither works. The solution is always the same — give the server a public endpoint, either by using a VPS, opening its port, or putting a tunnel in front of it.

Virus scanning

Uploaded files are sent through ClamAV if clamd is running on the server. Files over 200 MB are skipped (threshold configurable via AFB_SCAN_MAX_SIZE_MB). Scan results appear in upload-status:

"scan": {"status": "clean", "detail": ""}

Possible statuses: clean, infected, unscanned (clamd not configured or file too large), error (clamd unreachable or timed out).

Set AFB_CLAMAV_SOCKET to your clamd socket path (e.g. /var/run/clamav/clamd.ctl) to enable scanning.

Upload webhook

When a user finishes uploading files, Agent File Bridge can POST the results to a URL. Set AFB_UPLOAD_WEBHOOK_URL globally, or pass --webhook-url per session:

afb upload-session --webhook-url http://localhost:8888/upload-callback

The webhook receives {"session_id": "...", "files": [...]}. Errors are non-fatal — the upload always succeeds, the webhook is fire-and-forget.

HTTP API

POST /api/share — create a download link

{"path": "/tmp/file.docx", "ttl_seconds": 3600, "max_downloads": 1}

POST /api/upload-sessions — create an upload page

{"ttl_seconds": 3600, "max_files": 5, "max_size_mb": 500, "webhook_url": "..."}

GET /api/upload-sessions/{id} — check what was uploaded

Returns file paths, sizes, SHA-256 hashes, MIME types, and scan results.

For agents

Three patterns.

Send a file. Call afb share, get a URL, send to the user. Don't expose the local path.

Receive files. Call afb upload-session, send the URL, poll afb upload-status. Check SHA-256 and scan status before processing.

Defaults:

--ttl 1h
--max-downloads 1
--max-files 5
--max-size-mb 500
--ext .pdf,.docx,.xlsx,.csv,.zip,.png,.jpg,.txt

Config

Variable Default
AFB_BASE_URL Public URL shown in generated links
AFB_SERVER http://127.0.0.1:8765 CLI target
AFB_ALLOWED_ROOTS Directories that can be shared (comma-sep)
AFB_UPLOAD_DIR ./uploads Where uploaded files land
AFB_DB ./agent-file-bridge.sqlite3 Database path
AFB_TOKEN_BYTES 24 Random token length
AFB_CLAMAV_SOCKET Path to clamd socket (enables scanning)
AFB_SCAN_MAX_SIZE_MB 200 Skip virus scan for files over this size
AFB_UPLOAD_WEBHOOK_URL Default webhook URL for upload notifications

Upgrade

pip install --upgrade agent-file-bridge

Schema migrations run automatically on server start. Back up your .sqlite3 file before upgrading.

Security

Every URL is a bearer secret. Run behind HTTPS. Restrict AFB_ALLOWED_ROOTS. Use short TTLs. Never execute uploaded files. Enable ClamAV for untrusted uploads.

See SECURITY.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_file_bridge-0.2.0.tar.gz (15.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_file_bridge-0.2.0-py3-none-any.whl (12.5 kB view details)

Uploaded Python 3

File details

Details for the file agent_file_bridge-0.2.0.tar.gz.

File metadata

  • Download URL: agent_file_bridge-0.2.0.tar.gz
  • Upload date:
  • Size: 15.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for agent_file_bridge-0.2.0.tar.gz
Algorithm Hash digest
SHA256 6e8dbcb7b5298f59ce41a1af3a64ba229ebfa454e4d9641fdf4fa9c062f4da69
MD5 28fd349aeeda56d818efa7989242c032
BLAKE2b-256 0204c61237307261df6d0ca3a8bb077d04b2eb644afdd290e550bf9a92144617

See more details on using hashes here.

File details

Details for the file agent_file_bridge-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for agent_file_bridge-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b38b676e791f17557fd7501c95b4bc9ace2a82bc0b036af5cc53e990a3349fa1
MD5 c469717aab5d064e4f294f74c8490eb5
BLAKE2b-256 ce7f002fb735e96a9ee39eb506bbba84de9f54137985eb4edf15d125c3528160

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page