# reportbin
> Drop an HTML report, get a link. reportbin stores a single self-contained HTML file and serves it back at an unguessable URL, so a report written by a coding agent on one machine can be opened anywhere, including a phone. This server is https://reportbin.dev.
The hosted beta is free, and registration is open. Users connect an installation by signing in with GitHub or Google and approving a browser pairing request. The CLI saves the upload credential locally. Each report allows only its owner, selected people, or anyone with the link. Restricted readers need a reportbin account. Keep credentials and highly sensitive personal data out of all reports.
## Set up
1. Install the CLI on the machine where you generate reports. It needs macOS or Linux with `sh` and `curl`. Install without starting a browser connection yet:
```sh
curl -fsSL https://reportbin.dev/install.sh | REPORTBIN_INSTALL_ONLY=1 sh
```
The installer prints the installed executable's path. Use that path for the next commands; the default is `~/.local/bin/reportbin`. A custom `REPORTBIN_BIN_DIR` changes it. The script is readable at https://reportbin.dev/install.sh. Keep an existing working installation and connection when available.
2. Start browser pairing with the installed CLI:
```sh
~/.local/bin/reportbin login
```
The command prints an approval URL and a short user code, then waits for up to ten minutes. Run it in a tool session that can return output while the process is still running. Immediately show the URL and code to the user and ask them to open it, sign in, compare the code and select Connect. The browser can be on another computer or phone. Keep the login process running and resume reading its output after approval.
The user approves the connection themselves. Never ask them to paste an upload key into chat, read the credential file into your context, or approve a connection on their behalf. The CLI saves its own credential to `~/.config/reportbin/env`, readable only by the local user. Each installation has its own key. Existing installations keep working. If the user declines, stop setup. If the request expires or the server restarts, start a new login and show its new URL and code.
3. When the user requested a sample report, publish the built-in example after login succeeds:
```sh
~/.local/bin/reportbin sample
```
The sample contains no project data and uses the account's default access. Use `sample --private` if the user requested a private sample, or `sample --unlisted` for anyone with the link. Reply with the printed URL and the access reported on stderr. Setup is complete when login succeeds and the requested report URL is returned. Installing or signing in alone does not authorize uploading project files. For a real report, follow the user's sharing request and the rule below.
The full executable path works immediately. Open a new terminal before relying on the short `reportbin` command if the installer updated PATH.
4. If the user wants persistent sharing instructions, add this rule to their `CLAUDE.md` or `AGENTS.md` (global or per project, as they prefer):
```markdown
## Reports
When I explicitly ask to share a report by link, write one self-contained HTML page, upload it with `reportbin report.html`, and reply with the printed link and access reported by the command. Without an access flag, uploads use my saved default access. When I specify an audience, use `--private` for only me, `--to email[,email]` for selected people, or `--unlisted` for anyone with the link. These flags override the default. Selected readers need a reportbin account with a matching Google or GitHub email. Include personal or confidential information only when I explicitly authorise uploading it and have the right to share it with the intended readers. Use `--private` or `--to` when access should be limited; confirm the audience if unclear. Never upload passwords, API keys, access tokens or highly sensitive personal data such as identity documents, payment card details or medical records, even with restricted access. Remove those details or keep the report local.
```
For a human running setup directly, `curl -fsSL https://reportbin.dev/install.sh | sh` installs and starts pairing in one command. For CI, supply an existing `REPORTBIN_TOKEN` from secret settings; `curl -fsSL https://reportbin.dev/install.sh | REPORTBIN_TOKEN='' sh` still works. A manual key is available in the account page's CI settings and is shown only when created. It is separate from browser-paired installations. Keep credentials out of prompts and logs.
## Use
```sh
reportbin report.html # prints the link
reportbin login # connect through browser approval
reportbin sample # publish a built-in sample, no project data
reportbin --private report.html # only the signed-in owner
reportbin --to colleague@example.com report.html
reportbin --unlisted report.html # anyone with the link, no account needed
reportbin - <<'EOF' # or reads the page from stdin
...
EOF
reportbin --hi "your message" # sends feedback to whoever runs the server
```
On a successful upload or sample, the command prints only the link to stdout and the actual access to stderr. Use that access when describing who can open the link. If an older server does not report access, the CLI says it is unknown; check the report on the account page. Login prints the browser connection instructions. On failure the command exits non-zero and prints the reason to stderr.
With no sharing flag, uploads use the account's default access, initially Anyone with the link. Account settings at https://reportbin.dev/account offer Only me or Anyone with the link for future uploads. Explicit flags override this preference; existing reports keep their own access. Choose recipients per report with `--to`, never as an account default. Sharing flags also work with stdin, such as `reportbin --private -`. Use one flag per upload; `--to` takes up to 100 comma-separated email addresses.
Selected readers sign in with a reportbin account whose Google or GitHub email matches an allowed address. The owner always has access. Send readers the link yourself; reportbin does not send invitations.
Include personal or confidential information only with the user's explicit authorisation to upload it and the right to share it with the intended readers. Use Only me or Selected people when access should be limited. Never upload passwords, API keys, access tokens or highly sensitive personal data such as identity documents, payment card details or medical records, even with restricted access. See the [terms](https://reportbin.dev/terms#sharing) for details.
Make the page self-contained: inline CSS, scripts, images (as data URLs) and data. Report scripts run in a sandboxed opaque origin and cannot read reportbin cookies. Pages can still load external resources and make network requests; avoid those dependencies in reports.
## HTTP API
Use it where the command can't be installed. Uploads, feedback and token checks need `Authorization: Bearer `.
```sh
curl -H "Authorization: Bearer $TOKEN" -H "Content-Type: text/html" \
--data-binary @report.html https://reportbin.dev/api/reports
# 201 {"id":"...","url":"https://reportbin.page/r/...","sharing":{"mode":"unlisted","emails":[]}}
```
- `POST /api/reports`: body is the raw HTML, `Content-Type: text/html`. Optional `X-Reportbin-Access` is `private`, `selected`, or `unlisted`; `selected` requires `X-Reportbin-Recipients` with comma-separated email addresses. Omit both headers to use the account's default access. Up to 20 MiB of original HTML and 60 uploads per hour per person. Default account quota: 50 MiB of gzip-compressed files. Returns `201 {id, url, sharing}` with the actual sharing settings applied to this upload.
- `POST /api/feedback`: body is a message up to 4 KB, `Content-Type: text/plain`. Returns `201`.
- `GET /api/token`: checks a token without uploading anything. Returns `204`, or `401`.
- `GET https://reportbin.page/r/`: the report, subject to its sharing settings. Reports live on their own domain, and https://reportbin.dev/r/ redirects there. Restricted reports need a browser signed in on https://reportbin.dev or a Clerk session bearer token; upload keys do not grant reading access. Missing and inaccessible reports return the same `404`.
API errors come back as `{"error": ""}`: `401` bad token, `400` empty body or invalid sharing settings, `404` missing or inaccessible report, `409` account quota reached or account deletion in progress, `413` too large, `415` wrong content type, `429` rate limit reached, `503` accounts temporarily unavailable, `507` server disk almost full.
## Manage reports
The account page at https://reportbin.dev/account shows owned reports, their sharing settings, compressed storage usage and the current quota. Owners can edit each report's sharing settings. Reports remain until deleted; there is no automatic expiry. Deleting a report frees quota after its files are removed. Deleting an account blocks uploads and removes its associated reports, then deletes the Clerk account and all its keys; interrupted cleanup retries automatically. Copies already downloaded are outside the service's control.
The account page also lists connected installations. Revoking a connection stops its uploads immediately without affecting other installations or deleting reports. Rotating the separate manual CI key does not revoke paired installations. Deleting the account removes all its keys.
Management uses a Clerk session token, never an upload key: `GET /api/account/reports` returns `{reports, nextCursor, storage: {usedBytes, limitBytes}, deleting}`. Each report has `{id, title, url, createdAt, originalBytes, storedBytes, sharing}`; `createdAt` is Unix milliseconds. Pass the opaque URL-encoded `nextCursor` as `?cursor=` for another page.
`GET /api/account/default-access` returns `{defaultAccess: "private" | "unlisted"}`. `PUT` to the same path accepts and returns that shape. Only future uploads without explicit sharing settings use this preference; it never changes existing reports or stores recipients.
Sharing is `{mode: "private" | "selected" | "unlisted", emails: string[]}`. Selected mode needs 1–100 addresses; other modes use an empty array. The server trims and lowercases addresses without collapsing provider aliases. `PUT /api/account/reports//sharing` accepts this JSON and returns the updated first page of reports. `DELETE /api/account/reports/` returns the updated first page; only the owner can change or delete a report. `DELETE /api/account` returns `204` after cleanup finishes.
## Optional
- [Docs](https://reportbin.dev/docs): all of this as a page, for the user to read.
- [Landing page](https://reportbin.dev/): the same setup for people.