---
name: poof
description: Publish a local directory as an ephemeral public website over SSH using poof (poof.garbas.si) — a temporary URL that auto-expires. Use when the user wants to quickly share a static site, build output, screenshot, report, or any folder as a link that disappears on its own.
---

# poof — ephemeral web sharing over SSH

poof publishes a folder as a static website at `https://poof.garbas.si/<slug>/`
and makes it **vanish** when it expires. There is no account and no web upload:
the SSH key is the credential, transfer is plain `scp`, and the URL is
deterministic from the slug. *Now you see it — now you don't.*

- **Host:** `poof.garbas.si`
- **SSH port:** `1222` (not 22)
- **Limits:** TTL ≤ 30d (default 15m), ≤ 50MB per share

## One-time setup (per SSH key)

The first time a given SSH key is used, verify an email once (interactive):

```sh
ssh -p 1222 poof@poof.garbas.si
```

Enter an email at the prompt, then the 6-digit code that is mailed to it. After
that, every push with that key is instant — no human in the loop again. (If a
push errors with "verify your email first", do this step.)

## Publish a folder

Copy the **contents** of a directory to a slug. The trailing `/.` is required —
it puts files at the slug root so `https://poof.garbas.si/<slug>/` serves
`index.html`:

```sh
scp -O -P 1222 -r ./site/. "poof@poof.garbas.si:my-slug?duration=1d"
```

The page is then live at `https://poof.garbas.si/my-slug/`.

Notes and options (everything after `host:` is `slug?key=val&key=val`):

- **Quote the destination.** `?` and `&` are shell metacharacters.
- `duration` — TTL, e.g. `30m`, `2h`, `7d`, `30d` (max 30d; default 15m).
- `password` — protect the share: `...:my-slug?password=hunter2`. (On the
  command line this leaks into shell history; prefer setting it over SSH, below.)
- `index` — pick which file is served at the bare URL when there's no
  `index.html`: `...:my-slug?index=home.html`. With a single top-level `.html`
  file and no `index.html`, poof auto-selects it, so a one-page upload just works.
- Omit the slug for a random one: `scp -O -P 1222 -r ./site/. "poof@poof.garbas.si:?duration=1h"` —
  then ask poof for the URL with `ssh -p 1222 poof@poof.garbas.si ls`.
- `-O` is required (OpenSSH 9+ defaults to SFTP; poof speaks the legacy scp protocol).

## Manage your shares over SSH

Every management action is a non-interactive SSH command of the form
`ssh -p 1222 poof@poof.garbas.si <command> [args]` — no upload, just runs and
prints the result. To **list your shares**, run `ls`:

```sh
ssh -p 1222 poof@poof.garbas.si ls
# slug                       12345 bytes      7 views  expires 2026-07-01 …
```

The full set of commands:

| Command | What it does |
| ------- | ------------ |
| `ls` | List your shares: slug, size, **page-view count**, expiry, `[password]`. |
| `url <slug>` | Print a share's public URL. |
| `rm <slug>` | Delete a share now (make it vanish). |
| `extend <slug> <dur>` | Renew the TTL, e.g. `extend my-slug 30d` (max 30d). |
| `passwd <slug>` | Set/clear the password — read from stdin; an empty line clears it. |
| `index <slug> <file>` | Serve `<file>` at the bare URL, e.g. `index my-slug home.html`. |
| `claim <slug?opts>` | Reserve a slug (with optional `?duration=&password=`) before uploading. |
| `archive <slug>` | Stream a gzip-tar of the share to stdout (`> my-slug.tar.gz`). |
| `help` | Print the cheat-sheet (upload + management commands). |

Examples:

```sh
ssh -p 1222 poof@poof.garbas.si rm my-slug
ssh -p 1222 poof@poof.garbas.si extend my-slug 7d
echo 'hunter2' | ssh -p 1222 poof@poof.garbas.si passwd my-slug   # set a password
ssh -p 1222 poof@poof.garbas.si archive my-slug > my-slug.tar.gz
```

`ls`'s **page-view count** tallies visits to the slug root and `*.html` pages
(assets like css/js/images aren't counted).

## Interactive dashboard

Connect with **no command** for a full-screen dashboard to browse and manage
everything visually:

```sh
ssh -p 1222 poof@poof.garbas.si
```

Keys: `↑/↓` move · `n` new share (builds the scp command) · `e` edit (renew TTL,
password, **default page**) · `p` password · `d` delete · `y`/`Y` copy URL /
update command · `/` filter · `S` **stats** (recent visits with town/country +
a per-country chart) · `r` refresh · `T` theme · `?` help · `q` quit.

## Tips for agents

- Build the site first (e.g. `npm run build`), then publish the output dir's
  contents with the `/.` form.
- A named slug needs no round-trip: the URL is
  `https://poof.garbas.si/<slug>/` immediately after a successful `scp`.
- To refresh an existing share, re-run the same `scp` (it renews the TTL).
- Shares are deleted on expiry; `archive` first if a copy is needed.
