Private file hosting for agents.Your bucket, your subdomain.

A file host your agents publish to. Every File gets a permanent URL on your own subdomain, and stays private until you say otherwise.

Claim your subdomainnpm i -g @vaut/cli
YouRun the checkout tests and send Sam the report.AgentCheckout suite passed, 14 of 14. Publishing the report.● Bash vaut put .context/qa-checkout.html --at reports/qa-checkout.html
  ⎿ https://acme.vaut.dev/reports/qa-checkout.html
● Bash vaut share reports/qa-checkout.html --email sam@example.com --expires 7d --notify
  ⎿ shared with sam@example.com until Oct 26 - email sent
The QA report is at https://acme.vaut.dev/reports/qa-checkout.html. It is private; Sam can open it until Oct 26.

The vaut-file-hosting skill, in a coding agent's session. The URL is printed once and never changes.

How it works

  1. First, sign in.

    npm i -g @vaut/cli && vaut login opens vaut.dev/device with a code and mints a CLI Token for your Org.

    acme.vaut.dev /0 Files⌘K
    $ npm i -g @vaut/cli && vaut loginadded 1 package in 2sOpened vaut.dev/device. Code QXRT-4821Signed in to acme.vaut.dev
  2. Then publish. It answers with a URL.

    vaut put plan.html --at docs/plan.html prints one permanent URL per line. Nothing is public yet: signed out, the URL answers 302.

    acme.vaut.dev › docs › plan.htmlprivatev1 · just now⌘K
    $ vaut put plan.html --at docs/plan.htmlhttps://acme.vaut.dev/docs/plan.html$ curl -I https://acme.vaut.dev/docs/plan.htmlHTTP/2 302location: https://vaut.dev/login?next=acme.vaut.dev%2Fdocs%2Fplan.html
  3. Then share it, by name.

    vaut share opens the File to sam@example.com for 7 days and sends the Share Email. Sam gets the File, not your folders.

    acme.vaut.dev › docs › plan.htmlsharedsam@example.com · Oct 26⌘K
    $ vaut share docs/plan.html --email sam@example.com --expires 7d --notifyshared with sam@example.com until Oct 26 - email sent
  4. When it is ready, make it public.

    vaut visibility set docs/plan.html public. The URL never changes, so switching back is the same one line.

    acme.vaut.dev › docs › plan.htmlpublicv1 · just now⌘K
    $ vaut visibility set docs/plan.html publicpublic: https://acme.vaut.dev/docs/plan.html (the URL never changes)
  5. Now anyone can read it, sandboxed.

    It answers 200 with a sandbox policy and no allow-same-origin, so the HTML gets an opaque origin and never runs with your login.

    acme.vaut.dev › docs › plan.htmlpublicv1 · just now⌘K
    $ curl -I https://acme.vaut.dev/docs/plan.htmlHTTP/2 200content-type: text/html; charset=utf-8content-security-policy: sandbox allow-scripts allow-popups allow-popups-to-escape-sandbox allow-modals allow-downloads allow-forms
acme.vaut.dev /0 Files⌘K
acme.vaut.dev/

Signed in · 1 Member · bucket acme-vaut (Cloudflare R2)

No Files yet. The first vaut put prints the first URL.

$ npm i -g @vaut/cli && vaut loginadded 1 package in 2sOpened vaut.dev/device. Code QXRT-4821Signed in to acme.vaut.dev

Private until you say so

Three Visibilities, one per File. No stamp means private, so a File with missing metadata stays closed. Change it below and read who can open it.

Who can open docs/plan.html · 24.1 KB, v3

YouMember of acmeThe File Page, with its Banner, Versions and Share
sam@example.comGuestRaw of this File, until Oct 26. Signs in with Google or an emailed code.
lee@example.comGuestRaw of this File, until Oct 26.
Anyone with the URLSigned outNo. HTTP/2 302 to vaut.dev/login.
Its Versionsv2, v1 in archive/Only you, whatever the File's Visibility.
$ vaut share docs/plan.html --email sam@example.com --email lee@example.com --expires 7d --notify
Visibility
sam@example.com
lee@example.com
Expires
Send Share Email
URLacme.vaut.dev/docs/plan.html

A Guest gets the File, raw. Never your folders, never the Banner, never its Versions.

Your bucket, the source of truth

Link Cloudflare R2, Amazon S3 or any S3-compatible bucket. Your Files and their metadata live there; Vaut keeps an Index it can rebuild from it with vaut reindex. Leave any time with everything.

$ aws s3 ls s3://acme-vaut --recursive \
    --endpoint-url $R2_ENDPOINT
docs/plan.html
pr-assets/checkout-before.png
pr-assets/checkout-after.png
pr-assets/cart-empty-state.png
reports/qa-auth-flow.html
mocks/settings-v3.html
2026/10/k3f9q2-trace.json
archive/docs/plan.html/v2
archive/docs/plan.html/v1
$ vaut reindex
reading acme-vaut (Cloudflare R2)
9 objects: 7 Files, 2 Versions
visibility, Share and git context
read from object metadata
Index rebuilt in 0.6s

Every object is plain in your bucket, readable with any S3 tool. The Index is a copy for listings; access is decided by the bucket's own stamps.

Overwrite without fear

Publish to the same path again and the last Version is archived, private. vaut diff docs/plan.html shows what changed.

$ vaut history docs/plan.html
v3  2026-10-19 10:12  24.1 KB  feat/checkout  current
v2  2026-10-18 16:40  22.8 KB  feat/checkout
v1  2026-10-14 09:05  19.2 KB  main

Every upload knows its branch

The CLI records the repo, branch and worktree each upload came from, so an agent's screenshots can be found by the branch that made them.

$ vaut list --branch feat/checkout --type image
pr-assets/checkout-before.png    412 KB  public   2h ago
pr-assets/checkout-after.png     398 KB  public   2h ago
pr-assets/cart-empty-state.png   181 KB  private  3h ago

The same facts, from the API

Every Content Host answers REST under /api with a CLI Token: the record the bucket keeps, branch included.

$ curl -H "Authorization: Bearer $CLI_TOKEN" \
  https://acme.vaut.dev/api/files/docs/plan.html
{
  "key": "docs/plan.html",
  "size": 24678,
  "etag": "\"9b2f4c1e7a0d5e83\"",
  "visibility": "shared",
  "share": {
    "emails": [
      "sam@example.com",
      "lee@example.com"
    ],
    "expiresAt": "2026-10-26T10:12:00Z"
  },
  "versions": 3,
  "git": {
    "repo": "acme/web",
    "branch": "feat/checkout",
    "worktree": "web-checkout"
  },
  "updatedAt": "2026-10-19T10:12:41Z"
}

Also: GET /api/files, PATCH and DELETE /api/files/{key}, GET /api/versions/{key}, POST /api/reindex, GET /api/whoami.

Free, with the limits stated

Hosted on vaut.dev by Connor Chevli. Your storage bill is your bucket's.

Hosted on vaut.devFree

  • ReadsUnlimited

    Public URLs, Guests and the CLI alike.

  • Writes60 a minute

    Per Org. An agent publishing a run of screenshots fits.

  • Uploads100 MB

    The largest single File.

  • Share Emails100 a day

    Only sent when you pass --notify.

  • StorageYour bucket

    Billed by your bucket's provider, not by Vaut.

Self-host itFree

  • LicenceMIT

    github.com/connorch/vaut

  • Cloudflare WorkersSupported

    With an R2 bucket bound to the Worker.

  • NodeSupported

    Any S3-compatible bucket behind it.

  • Members per Org1

    Teams are not built yet, here or hosted.

Questions

Who can see my Files? Only you, until you make a File public or share it.

What does a Guest see? The one File, raw. Never your folders, the Banner or its Versions.

Where are my Files stored? In your bucket. Vaut stores an Index of their metadata, rebuilt from the bucket whenever you ask.

Can an HTML File act as me? No. It runs in a sandbox with its own origin; private images in it are signed for whoever is reading.

Do I need an agent to use it? No. The CLI is for people too. Agents get the vaut-file-hosting skill.

What happens to my Slug if I leave? It is retired. Nobody else can ever claim it.

Can I bring my team? Not yet. Each Org has one Member today.

What are the limits? Unlimited reads, 60 writes a minute per Org, uploads up to 100 MB, 100 Share Emails a day. Storage is billed by your bucket's provider.

How do I report abuse? Email abuse@vaut.dev with the URL.

Claim your subdomain

Your Slug names your Content Host for good. It is never reused, even after you leave.

  • 3 to 32 characters
  • Lowercase letters, digits and inner hyphens
  • At least one letter
  • Not reserved, like www, api, admin or files
Claim your-name.vaut-staging.devThen npm i -g @vaut/cli && vaut login