agenttransfer

command module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 9 Imported by: 0

README ΒΆ

πŸ“€ AgentTransfer

CI

Every AI agent gets an email address. Upload a file, get a link, send it to any agent or any human. Open source, self-hostable.

The address comes with an API key and a folder. Files live in persistent, quota-bound folders; transfers happen over content-addressed links that expire within 24 hours; the handoff travels as ordinary email, so anything with an inbox can receive it. Every action leaves an ed25519-signed, hash-chained receipt.

One static Go binary. One data folder. Goes live from any machine with one command β€” or self-host everything on a $5 VPS with three DNS records.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   upload    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   email (manifest)   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OpenClaw     β”‚ ──────────► β”‚  your AgentTransfer   β”‚ ───────────────────► β”‚ Codex agent  β”‚
β”‚  (agent A)   β”‚             β”‚  instance             β”‚                      β”‚  (agent B)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚                       β”‚ ◄─────────────────── β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚  folders: persistent  β”‚      HTTPS download
        you, CC'd on ──────► β”‚  links: ≀24h, sha256  β”‚      (hash-verified)
        every transfer       β”‚  receipts: signed     β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Why

Agents increasingly need to hand artifacts to each other: model weights, datasets, build outputs, screen recordings. Across runtimes (OpenClaw ↔ Codex ↔ Cursor), across machines, across organizations. Today that means pasting bytes through context windows, sharing cloud-drive credentials, or standing up S3 + presigned URLs + a notification channel.

AgentTransfer's bet: email is the control plane, HTTPS is the data plane.

  • Email gives you identity, addressing, notification, human visibility, and cross-instance federation for free. Any agent with an inbox can participate; no registry, no SDK.
  • HTTPS moves the bytes: streamed, ranged, fast β€” never squeezed through email or a context window.
  • Content addressing (sha256 everywhere) means every receiver can verify what it got.
  • Signed receipts mean you can prove who sent what to whom β€” without trusting the operator.

Try it in 30 seconds

git clone https://github.com/shehryarsaroya/agenttransfer
cd agenttransfer && go build -o agenttransfer .

./agenttransfer demo

The demo spins a throwaway local server, creates two agents, hands a 1 MiB file from alice to bob (upload β†’ send β†’ long-poll β†’ download), verifies the sha256 on both ends, and cryptographically verifies the signed receipt chain. No domain, no keys, no config.

Go live in one command

./agenttransfer serve --connect
# connect: registered β€” this instance is https://quiet-moth-79.agenttransfer.dev

That's a full public instance running on your laptop: world-reachable share links, agents with real email addresses (bot@quiet-moth-79.agenttransfer.dev) that can receive mail immediately β€” even mail that arrives while the laptop sleeps (it queues and delivers on reconnect). One outbound tunnel to a connect host provides the public URL and the mail slot; your files, keys, inboxes, and receipts never leave your machine. Sending email unlocks after a confirm-button owner verification (spam control):

curl -X POST http://localhost:8080/v1/connect/verify \
  -H "Authorization: Bearer <admin token>" -d '{"email":"you@example.com"}'

Connect is optional plumbing, not a dependency: point --connect at your own connect host, bring your own tunnel, or self-host the classic way with nothing borrowed at all. Details, quotas, and abuse safeguards: docs/connect.md.

Or run a purely local instance (dev mode β€” what the demo and tests use):

./agenttransfer serve
# prints your admin token on first boot; API on :8080

The core loop

# 1. Create two agents (admin token from first boot)
curl -X POST http://localhost:8080/v1/agents \
  -H "Authorization: Bearer at_admin_..." \
  -d '{"name":"openclaw-dev"}'
# β†’ { "email": "openclaw-dev@local", "api_key": "at_live_...", ... }
curl -X POST http://localhost:8080/v1/agents \
  -H "Authorization: Bearer at_admin_..." \
  -d '{"name":"codex-bot"}'

# 2. Upload into its folder (persistent, quota-bound)
curl -T ./weights.tar.gz "http://localhost:8080/v1/files/weights.tar.gz" \
  -H "Authorization: Bearer at_live_..."
# β†’ { "sha256": "8f2a41...", "size": 209715200, ... }

# 3. Send it to another agent (or a human)
curl -X POST http://localhost:8080/v1/send \
  -H "Authorization: Bearer at_live_..." \
  -d '{"to":["codex-bot@local"],"file":"weights.tar.gz","note":"training set v3"}'
# same-instance: lands in their inbox instantly, no email involved
# cross-instance / humans: goes out as normal email with a download link

# 4. The recipient long-polls, downloads, verifies
curl "http://localhost:8080/v1/inbox/wait?timeout=60" -H "Authorization: Bearer <their key>"
curl -L "<offer url>?dl=1" -o weights.tar.gz && shasum -a 256 weights.tar.gz

Or skip curl entirely β€” the same binary is the client:

agenttransfer login http://localhost:8080 --key at_live_...
# (on an OPEN_SIGNUP instance, agents onboard themselves in one line instead:)
#   agenttransfer signup https://<instance> --name my-agent --owner you@example.com
agenttransfer put weights.tar.gz --share --ttl 3h    # upload (+ optional link)
agenttransfer send weights.tar.gz --to codex-bot@local --note "training set v3"
agenttransfer inbox --wait 60
agenttransfer get msg_abc123          # downloads and sha256-verifies, always
agenttransfer log --verify            # your signed receipt trail

Connect your agents over MCP

AgentTransfer speaks MCP (Streamable HTTP) natively at /mcp, same bearer key. One entry in your agent's MCP config β€” Codex, Cursor, OpenClaw, and most other MCP-capable runtimes read this shape:

{
  "mcpServers": {
    "agenttransfer": {
      "url": "https://agents.example.com/mcp",
      "headers": { "Authorization": "Bearer at_live_..." }
    }
  }
}

Tools: whoami, list_files, upload_file, share_file, send, check_inbox (long-polls), read_message, download_file, create_upload_request, get_receipts.

The model

Folders are a drive. Links are a WeTransfer. The wire is email.

Thing Lifetime Why
Folder files (verified owner) persistent (quota-bound) it's a drive β€” your agent's artifacts stay
Folder files (owner not yet verified) expire in UNVERIFIED_FILE_TTL (24h); verifying lifts the expiry on everything already uploaded anonymous signups get a scratchpad, not free permanent hosting
Share links ≀ 24h, content-addressed, revocable the public surface is ephemeral: kills link-leak risk, storage abuse, retention anxiety
Unclaimed arrivals (inbound email attachments, upload-request drops) expire in DEFAULT_TTL unless the agent keeps them strangers can't fill your quota
Receipts append-only forever signed + hash-chained evidence

Burn-after-read (?once=1): single-download links for credentials and one-shot handoffs. The share page and HEAD requests never consume the read (link unfurlers are harmless); only a completed byte-stream burns it.

Revocation is real: DELETE /v1/links/{token} (or agenttransfer rm <token>) kills a link now β€” in-flight downloads are severed mid-stream.

Reverse flow: agenttransfer request --note "drop the screen recording here" mints a one-time browser upload page for a human; the file lands in the agent's inbox.

Email: the federation layer

Outbound mail carries a human-readable body plus a machine-readable manifest part (application/vnd.agenttransfer+json) whose parts align field-for-field with A2A TextPart/FilePart, so A2A agents consume AgentTransfer offers natively:

{
  "v": 1,
  "from": "openclaw-dev@agents.example.com",
  "message_id": "msg_7hk2...",
  "parts": [
    { "kind": "text", "text": "training set v3" },
    { "kind": "file",
      "file": { "name": "weights.tar.gz", "mimeType": "application/gzip",
                "uri": "https://agents.example.com/f/nk3Xw9pT2mQe" },
      "metadata": { "agenttransfer.sha256": "8f2a41...", "agenttransfer.size": 209715200,
                    "agenttransfer.expiresAt": "2026-07-03T10:00:00Z", "agenttransfer.once": false } }
  ]
}

Humans just see a normal email with a link. AgentTransfer instances parse the manifest into a structured inbox offer, with DKIM results attached (trusted requires a DKIM pass whose signing domain aligns with the From domain). Threading (In-Reply-To/References) works, so multi-turn agent conversations thread correctly β€” in agent inboxes and in your mail client.

The deliverability split that makes self-hosting sane: receive raw, send via relay. The binary runs its own inbound SMTP listener on port 25 (inbound is easy). Outbound goes through any relay key (OUTBOUND=resend:re_... is one env var with a free tier), so your cheap VPS's IP reputation never matters.

Receipts: portable evidence

Every action (uploaded, sent, received, downloaded, revoked, burned, expired, deleted) appends a receipt signed with the instance's ed25519 key and chained by hash to the previous receipt:

  • signatures prove who did what,
  • the chain proves nothing was quietly deleted,
  • the public key is published at /.well-known/agenttransfer, so anyone can verify offline:
agenttransfer log --verify                        # your slice: signature check
AGENTTRANSFER_ADMIN_TOKEN=... agenttransfer verify https://agents.example.com   # full chain

Self-hosting (the 10-minute version)

Everything Connect borrows, you can own. You need four things: a Linux VPS with inbound ports 25/80/443 open, a domain, an outbound relay key (Resend's free tier works), and Go 1.25+ or Docker to build. Nothing else β€” no database server, no S3, no reverse proxy, no dependence on anyone's hosted service.

# on any VPS with ports 25/80/443 open (a $5 box is plenty)
DOMAIN=agents.example.com OUTBOUND=resend:re_xxx ./agenttransfer serve

Add CONNECT_DOMAIN=agents.example.com (plus wildcard A/MX records) and your VPS is also a connect host β€” your laptops and homelab boxes get instant public subdomains under it: docs/connect.md.

Three DNS records: A agents.example.com β†’ your-ip, MX agents.example.com β†’ agents.example.com, plus the SPF/DKIM records your relay gives you. TLS is automatic (Let's Encrypt via certmagic). Then:

agenttransfer doctor   # checks DNS, port 25, TLS, relay auth β€” with copy-paste fixes

Full guide (systemd, Docker, backups, provider notes): docs/self-hosting.md

Configuration
Env var Default What it does
DOMAIN β€” enables email + autocert (e.g. agents.example.com)
DATA_DIR ./data SQLite + blobs + instance key
HTTP_ADDR :443 with DOMAIN (unless BEHIND_PROXY), else :8080 HTTP(S) listener
SMTP_ADDR :25 with DOMAIN, else off inbound SMTP listener
OUTBOUND β€” resend:re_... | smtp://user:pass@host:587 | smtps://…
ADMIN_TOKEN generated on first boot gates signup + admin endpoints
OPEN_SIGNUP false public signup (per-IP rate-limited; taken names get a random suffix; reserved names blocked)
MAX_FILE_SIZE 5GB per-file cap
STORAGE_QUOTA 20GB per-agent folder cap (verified owners)
STORAGE_QUOTA_UNVERIFIED 200MB folder cap until the owner verifies
UNVERIFIED_FILE_TTL 24h files of unverified-owner agents expire; verifying makes the folder persistent (off disables)
DISK_RESERVE 10% global backstop: uploads are refused (507) while the data volume has less than this free β€” the disk can never fill (50GB absolute also accepted; off disables)
DEFAULT_TTL / MAX_TTL 3h / 24h share-link (and unclaimed-file) lifetimes
SEND_RATE / UPLOAD_RATE 100 / 200 per-agent daily limits
MAX_AGENTS_PER_OWNER 10 open-signup agents per owner email (-1 disables)
IP_RATE 600 per-IP hourly budget on the public pages (/f/, /u/, index); IPv6 keyed by /64; repeat offenders get a 15-minute ban (-1 disables)
UPLOAD_BODY_TIMEOUT 1h slow-upload read deadline β€” bounds body-trickling clients without ever timing out downloads (off disables)
HUMAN_RECIPIENTS_MAX 3 unique remote recipients per agent, ever β€” the circle (owner exempt; -1 disables; raise per agent via POST /v1/agents/{id}/limits)
PUBLIC_URL derived advertised base URL (set behind a proxy)
BEHIND_PROXY false trust X-Forwarded-For, disable autocert
ACME_EMAIL β€” Let's Encrypt account email
METRICS localhost Prometheus /metrics: off | localhost | admin
CONNECT β€” client: borrow a public URL + email from a connect host (serve --connect sugar)
CONNECT_DOMAIN β€” host: offer connect service for *.<domain> subdomains
CONNECT_SEND_RATE / CONNECT_BYTES_PER_DAY 50 / 5GB host: per-instance daily relay + egress caps

Security model

  • API keys and the admin token are stored hashed; rotate with agenttransfer rotate-key.
  • Share tokens are 128-bit random; TTLs enforced server-side; downloads counted and receipted.
  • Signup is admin-gated by default. With OPEN_SIGNUP=true, agents must have a verified human owner before they can send outbound email (owner CCs included) β€” a public instance must not be a spam cannon. Verification lands on a confirm page; the emailed link itself is side-effect-free, so mail scanners that prefetch URLs can't approve on the owner's behalf.
  • Even verified, an agent can only ever email a small circle of unique remote recipients (default 3; the owner is exempt; local agents don't count) β€” a compromised or prompt-injected agent can't become a spam cannon. The operator widens the circle per agent.
  • Every human-bound email carries a per-recipient unsubscribe link (HMAC-signed, so it can't be forged to suppress a victim); suppressed addresses are skipped at send time.
  • Unverified agents get a reduced storage quota (STORAGE_QUOTA_UNVERIFIED) and their files expire within UNVERIFIED_FILE_TTL (24h) β€” anonymous signups get a scratchpad, not free hosting; one owner email can register at most MAX_AGENTS_PER_OWNER agents, so identities aren't free in bulk either.
  • The disk can never fill: a global free-space reserve (DISK_RESERVE, 10% of the volume) refuses uploads with 507 before SQLite is ever at risk; GET /v1/admin/storage shows who holds the bytes; agenttransfer doctor reports the guard's state.
  • The public identity-free pages (/f/, /u/, index) are per-IP rate-limited (IPv6 by /64 β€” full addresses would be 2^64 free identities) with an automatic 15-minute ban for hammering; uploads carry a slow-body read deadline (UPLOAD_BODY_TIMEOUT) while downloads deliberately stream untimed.
  • Agents can be deleted (DELETE /v1/agents/self, or by the admin) β€” everything they own is removed and their links severed, but their receipts stay: the chain is append-only evidence.
  • Inbound SMTP only accepts mail for existing agents; oversized mail is rejected at the socket; DKIM is verified and surfaced (offer.trusted requires a pass aligned with the From domain).
  • The server never fetches foreign URLs from inbound mail (no SSRF surface); cross-instance downloads are the recipient's explicit, hash-verified act.
  • Connect instances are anonymous but fenced: outbound email needs a verified owner, every instance has daily send/egress caps and a suspend switch, and queued mail is parsed (and DKIM-checked) by your machine, not the host. See docs/connect.md.
  • Not yet: encryption at rest (use disk encryption), virus scanning (hook ClamAV in front of /v1/files if you need it), SPF checking (DKIM is enforced instead). See SECURITY.md.

Docs

Development

make test      # unit + end-to-end tests
make demo      # build and run the demo
make lint      # gofmt + go vet

Pure Go (1.25+), no cgo (modernc.org/sqlite), cross-compiles to a single static binary. See CONTRIBUTING.md.

Status & roadmap

Early but complete: files, links, burn-after-read, send/inbox with threading and idempotency, inbound SMTP + aligned DKIM, MCP, signed receipts, Connect (tunnel + store-and-forward email + quotas), demo, doctor. The hosted connect host is planned at agenttransfer.dev; until it's live, --connect needs a host you run.

Deliberately not here yet: inbox webhooks (long-poll covers agents; SSRF-safe webhooks are v1.1), auto-fetching foreign offers (same reason), S3 blob backend, resumable uploads, IMAP (never β€” humans already have inboxes).

License

MIT

Documentation ΒΆ

Overview ΒΆ

Command agenttransfer is file transfer for AI agents: every agent gets an email address and an API key; folders are persistent, share links are ephemeral and content-addressed; email carries the handoff, HTTPS carries the bytes; every action leaves a signed receipt.

One binary contains the server (`agenttransfer serve`), the client CLI, the demo, and the self-host preflight (`agenttransfer doctor`).

Directories ΒΆ

Path Synopsis
internal
cli
Package cli implements the agenttransfer command-line client (and the demo and doctor subcommands).
Package cli implements the agenttransfer command-line client (and the demo and doctor subcommands).
mail
Package mail builds and sends AgentTransfer's outbound email and parses inbound email.
Package mail builds and sends AgentTransfer's outbound email and parses inbound email.
proto
Package proto defines the AgentTransfer wire manifest β€” the machine-readable MIME part attached to every email an agent sends.
Package proto defines the AgentTransfer wire manifest β€” the machine-readable MIME part attached to every email an agent sends.
receipt
Package receipt implements AgentTransfer's signed, hash-chained receipts.
Package receipt implements AgentTransfer's signed, hash-chained receipts.
server
Package server implements the AgentTransfer server: HTTP API + MCP + share pages, inbound SMTP, the TTL janitor, and the long-poll hub β€” one process, one folder of state.
Package server implements the AgentTransfer server: HTTP API + MCP + share pages, inbound SMTP, the TTL janitor, and the long-poll hub β€” one process, one folder of state.
store
Package store is AgentTransfer's persistence layer: one SQLite database plus a sha256-addressed, refcounted blob directory.
Package store is AgentTransfer's persistence layer: one SQLite database plus a sha256-addressed, refcounted blob directory.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL