# CLI

> The `permahost` command uploads files from disk to a permanent public folder and prints their URLs. Its `file` commands mirror the [MCP tool](https://permahost.io/docs/mcp/); its `domain` commands add [custom domains](https://permahost.io/docs/domains/).

HTML version: https://permahost.io/docs/cli/ · All docs: https://permahost.io/docs.md

Why agents should prefer the CLI

The CLI reads and writes files on disk, so file content never enters the model's context: uploading a 5 MB PDF or a whole `dist/` folder costs a command and a few lines of output. Through MCP the same bytes would be written out as a tool argument, as text or as base64. Whenever the agent can run shell commands, use the CLI.

## Local paths

The CLI works with paths on disk in both directions: `upload` takes any number of local files and directories, from anywhere on disk, and `download` writes to the local path given with `-o`. The bytes go straight between the disk and permahost.io, never through the model.

### Upload: where local files land in the folder

| Command | Paths in the folder |
| --- | --- |
| permahost file upload build/out/report.pdf | `report.pdf` (the base name) |
| permahost file upload ~/notes/a.md ./b.txt | `a.md`, `b.txt` |
| permahost file upload site | `site/index.html`, `site/css/app.css` |
| permahost file upload site/ | `index.html`, `css/app.css` |
| permahost file upload site/ --path v2 | `v2/index.html`, `v2/css/app.css` |
| permahost file upload out.txt --path logs --name today.txt | `logs/today.txt` |

Like rsync, a directory keeps its name as a prefix, while `site/` or `.` uploads only its contents. Symlinks to files are followed; other non-regular files are skipped. Paths follow the server's rules (at most 5 directories deep, no `.` or `..` segments, no backslashes) and are checked before anything is sent.

### Download: to any local path

Shell:

```
$ permahost file download --id k7q2m9xa3bd --path css style.css -o build/cache/style.css
Downloaded css/style.css (3.0 KiB) to build/cache/style.css
$ permahost file download --id k7q2m9xa3bd index.html -o -
```

`--path` is the file's directory inside the folder; `-o` is where it goes on disk (`-` for stdout). An existing file is kept unless `--force` is given.

## Install

macOS and Linux (amd64, arm64):

```
$ curl -fsSL https://raw.githubusercontent.com/tmphost/permahost/main/install.sh | sh
```

Windows (PowerShell):

```
> irm https://raw.githubusercontent.com/tmphost/permahost/main/install.ps1 | iex
```

Both download the latest release, check it against `checksums.txt` and install `permahost` to `/usr/local/bin` when writable, or `~/.local/bin` (Windows: `%LOCALAPPDATA%\permahost\bin`, added to the user PATH). Set `PERMAHOSTIO_VERSION=v1.2.3` for a specific release or `PERMAHOSTIO_INSTALL_DIR` for another directory.

## Sign in

Shell:

```
$ permahost login
Logged in to https://app.permahost.io as agent@example.com (2000/2000 credits)
```

`login` opens the browser to sign in with Google or GitHub and approve the CLI (OAuth 2.1 with PKCE; the URL is printed too, in case the browser does not open) and waits up to 5 minutes. The tokens are saved to `$PERMAHOSTIO_CONFIG`, or `permahost/config.json` in the user config directory, readable only by the user, and refreshed automatically. `permahost logout` forgets them.

The server defaults to `https://app.permahost.io`; `--server` or `PERMAHOSTIO_SERVER` picks a self-hosted one. Tokens are only ever sent to the server that issued them.

Shell:

```
$ permahost whoami
Email:         agent@example.com
Name:          Agent
Credits:       1000/2000
Renews at:     2026-12-02 00:00 UTC
Hosting:       1 folders, 2.4 MiB in 1 storage blocks, 0 domains
Monthly cost:  1000 credits
Prices:        500 credits a month per folder, 500 per started 25.0 MiB stored, 500 per domain (+500 to set it up)
```

The numbers above are an example; `whoami` shows your own.

## Upload

### A directory, in a new folder

Shell:

```
$ permahost file upload site/
Uploading 3 files (2.4 MiB, at most 1000 credits; you have 2000)
https://k7q2m9xa3bd.file.permahost.io/index.html
https://k7q2m9xa3bd.file.permahost.io/css/app.css
https://k7q2m9xa3bd.file.permahost.io/img/chart.png

id:      k7q2m9xa3bd
url:     https://k7q2m9xa3bd.file.permahost.io/
credits: 1000 spent
```

Before it starts, `upload` prints the most it can cost: a new folder (500) plus any storage blocks the files start (500 per 25 MB). The server may charge less, for example when files replace others. The last lines give the folder id to keep and the credits actually spent.

### More files, or updates, in the same folder

Shell:

```
$ permahost file upload site/index.html --id k7q2m9xa3bd
Uploading 1 files (4.1 KiB, at most 0 credits; you have 1000)
https://k7q2m9xa3bd.file.permahost.io/index.html

id:      k7q2m9xa3bd
url:     https://k7q2m9xa3bd.file.permahost.io/
credits: 0 spent
```

With `--id`, files go into that folder and never cost folder credits again. A file at a path that already exists is replaced in place: same URL, and only the size difference counts toward storage. Don't know the id? `permahost file ls` lists your folders.

## Read and list

Shell:

```
$ permahost file ls
ID           TITLE       SIZE     URL
k7q2m9xa3bd  Q3 report   2.4 MiB  https://k7q2m9xa3bd.file.permahost.io/
$ permahost file get --id k7q2m9xa3bd
FILE NAME   PATH  SIZE     URL
index.html        4.1 KiB  https://k7q2m9xa3bd.file.permahost.io/index.html
app.css     css   3.0 KiB  https://k7q2m9xa3bd.file.permahost.io/css/app.css
chart.png   img   2.4 MiB  https://k7q2m9xa3bd.file.permahost.io/img/chart.png

id:      k7q2m9xa3bd
url:     https://k7q2m9xa3bd.file.permahost.io/
size:    2.4 MiB
$ permahost file url --id k7q2m9xa3bd --path css app.css
https://k7q2m9xa3bd.file.permahost.io/css/app.css
```

## Delete

Shell:

```
$ permahost file rm --id k7q2m9xa3bd css/app.css
Deleted css/app.css from folder k7q2m9xa3bd.
$ permahost file rm --id k7q2m9xa3bd
Deleted folder k7q2m9xa3bd.
```

Deleting a folder deletes its files and stops its monthly charge from the next renewal.

## Domains

Shell:

```
$ permahost domain add --id k7q2m9xa3bd www.example.com
Added www.example.com to folder k7q2m9xa3bd. Create this DNS record:

  www.example.com  CNAME  k7q2m9xa3bd.file.permahost.io

then run "permahost domain verify --id k7q2m9xa3bd www.example.com".
$ permahost domain verify --id k7q2m9xa3bd www.example.com
www.example.com is active and serves folder k7q2m9xa3bd.
```

See [custom domains](https://permahost.io/docs/domains/) for the DNS record, verification and HTTPS.

## Commands

| Command | Description |
| --- | --- |
| permahost login [--server URL] | Sign in with the browser |
| permahost logout | Forget the saved tokens |
| permahost whoami | Show the user, credits, renewal time, usage and prices |
| permahost file upload <local path>... [--id ID] [--path DIR] [--name NAME] | Upload files and print their URLs, the folder id and the credits spent |
| permahost file download --id ID [--path DIR] <fileName> [-o OUT] [--force] [--format FORMAT] | Download a file (`-o -` for stdout) |
| permahost file get --id ID | List a folder's files |
| permahost file url --id ID [--path DIR] [fileName] | Print a folder, directory or file URL |
| permahost file ls | List your folders |
| permahost file rm --id ID [path] | Delete a folder, or one file |
| permahost domain add --id ID <hostname> | Add a custom domain to a folder and print its CNAME record |
| permahost domain ls --id ID | List a folder's domains, their status and CNAME target |
| permahost domain verify --id ID <domain> | Check the CNAME record and activate the domain |
| permahost domain rm --id ID <domain> | Remove a custom domain |

## JSON output

The global `--json` flag prints JSON with the same fields as the MCP tool's results (`id`, `url`, `fileName`, `path`, `size`, `creditsSpent`, `files`), so an agent can parse it. `download -o - --json` puts the file in `base64Content`, or as UTF-8 text in `textContent` with `--format textContent`. `--version` prints the version.

Shell:

```
$ permahost --json file upload report.pdf --id k7q2m9xa3bd
{
  "id": "k7q2m9xa3bd",
  "url": "https://k7q2m9xa3bd.file.permahost.io/report.pdf",
  "fileName": "report.pdf",
  "size": 512000,
  "files": [ ... ]
}
```
