Publish an AI agent's HTML report to a live URL with one curl call
Agents are good at producing HTML: test summaries, research briefs, dashboards, small prototypes. Getting that file onto a URL someone can open usually takes longer than writing it. You have to pick a host, sign up, set up a CLI or connect a repo, then wait for a build. This walkthrough uses deed.p

Agents are good at producing HTML: test summaries, research briefs, dashboards, small prototypes. Getting that file onto a URL someone can open usually takes longer than writing it. You have to pick a host, sign up, set up a CLI or connect a repo, then wait for a build.
This walkthrough uses deed.page, a static host built for this case. You can publish without an account, the response is JSON an agent can parse, and updates are versioned, so a script can safely overwrite its own report every night.
Everything below is plain curl. You can run it yourself or give it to an agent as a shell tool.
cat > report.html << ' HTML ' <!doctype html><html><head><meta charset="utf-8"><title>Nightly test report</title></head> <body><h1>Nightly test report</h1><p>412 passed, 3 failed.</p></body></html> HTML Enter fullscreen mode Exit fullscreen mode 2. Publish it SLUG = agent-report- $( openssl rand -hex 3 ) curl -s -T report.html "https://deed.page/v1/sites?slug= $SLUG " -H "X-Client: report-bot" > first.json Enter fullscreen mode Exit fullscreen mode curl -T sends a PUT with the file as the body. No API key is needed. The response looks like this (trimmed):
{ "ok": true, "url": "https://agent-report-87cc65.deed.page/", "version": "v1", "version_url": "https://v1--agent-report-87cc65.deed.page/", "token": "deed_tok_…" } Enter fullscreen mode Exit fullscreen mode The site is live right away, and version_url is a permanent link to this exact version.
The token is only shown once, and it's what lets you update or delete the site later. Save it to a file outside the agent's context instead of printing it:
mkdir -p ~/.config/deed-page && chmod 700 ~/.config/deed-page python3 -c "import json;print(json.load(open('first.json'))['token'])" > ~/.config/deed-page/token chmod 600 ~/.config/deed-page/token && rm first.json export DEEDPAGE_TOKEN = $( cat ~/.config/deed-page/token ) Enter fullscreen mode Exit fullscreen mode If an LLM is driving the shell, this matters. A token that shows up in tool output ends up in the transcript, the logs and possibly the next prompt. Keep it in a file and let the tool read it.
The next night the numbers change. Publish to the same slug with the token. Add If-Match so the write only succeeds if the site is still at the version you expect:
sed -i 's/412 passed, 3 failed/415 passed, 0 failed/' report.html curl -s -T report.html "https://deed.page/v1/sites?slug= $SLUG " \ -H "Authorization: Bearer $DEEDPAGE_TOKEN " \ -H 'If-Match: "v1"' # -> "version": "v2" Enter fullscreen mode Exit fullscreen mode If two agents (or two runs of the same cron job) race, the one holding a stale version gets a 409 instead of silently overwriting the other:
{ "code": "version_conflict", "message": "Slug agent-report-87cc65 is at v2, not v1. Re-read and retry.", "version": "v2" } Enter fullscreen mode Exit fullscreen mode The error body tells the agent the current version, so it can re-read the site and retry. If you publish exactly the same bytes again, you get "unchanged": true and no new version.
Every publish is kept as a version (the free plan keeps the last 10):
curl -s "https://deed.page/v1/sites/ $SLUG /versions" -H "Authorization: Bearer $DEEDPAGE_TOKEN " Enter fullscreen mode Exit fullscreen mode Each entry has a permalink like https://v2--agent-report-87cc65.deed.page/. If tonight's report is wrong, restore an older one. The restore becomes a new version, so history is never rewritten:
curl -s -X POST "https://deed.page/v1/sites/ $SLUG /versions/v1/restore" \ -H "Authorization: Bearer $DEEDPAGE_TOKEN " # -> "version": "v3", content equal to v1 Enter fullscreen mode Exit fullscreen mode 5. Clean up curl -s -X DELETE "https://deed.page/v1/sites/ $SLUG " -H "Authorization: Bearer $DEEDPAGE_TOKEN " # -> {"ok":true,"deleted":"agent-report-87cc65"} Enter fullscreen mode Exit fullscreen mode The URL returns 404 a few seconds later.
For a folder (HTML plus CSS, images and JS), pack it and upload the tarball the same way:
tar -C./dist -czf site.tar.gz. curl -T site.tar.gz "https://deed.page/v1/sites?slug= $SLUG " -H "Authorization: Bearer $DEEDPAGE_TOKEN " Enter fullscreen mode Exit fullscreen mode Clean URLs work ( /about serves about.html or about/index.html ), and a root 404.html is used for missing pages. Single-page apps can send X-Spa: 1 so unknown paths fall back to index.html. A single request is capped at 4 MB, and larger sites use the manifest upload described in the docs.
If your agent runs shell commands, the steps above are all it needs. Two guardrails are worth adding:
For agents that speak MCP, deed.page also has an MCP endpoint at https://deed.page/mcp. There's an open-source agent skill that follows both rules at github.com/f-o-x11/deed-page-skill.
The free plan allows 25 sites, 25 MB per site, 60 publishes an hour and 10 versions per site. Free sites show a small "Published with deed.page" badge. The paid plans are listed on deed.page.
Full API reference: deed.page/docs. There's also a plain-text version for LLMs at deed.page/llms.txt.