---
name: folslate-cli
description: Use the Folslate CLI to publish files and manage documents from a terminal. Use when the folslate binary is installed or installable, when signing in, or when listing, inspecting, deleting, or reporting documents.
---

# Folslate CLI

The CLI publishes a file to Folslate with one command and prints its public
`fol.ink` link with the exact expiry. Anonymous uploads need no account and
expire one day after the last upload or replace. Signing in makes uploads
permanent and unlocks the account commands.

For the raw HTTP behind these commands, load the `folslate-api` skill. For
publishing a report or plan as a link, load `create-artifact`.

## Install

Check for the binary first, then install with the installer when it is
missing. The installer resolves the newest release at run time and installs
user-local into `~/.local/bin` (`INSTALL_DIR` overrides the directory).
Prefer it over npm so every agent lands on the same binary:

```bash
folslate --version
t=$(mktemp /tmp/folslate-install.XXXXXX) && curl -fsSL https://folslate.com/install.sh -o "$t" && sh "$t"
```

Alternatives when the installer does not fit: `npm install -g @folslate/cli`
for a Node-managed install, `npx @folslate/cli upload report.md` for a
one-shot run with nothing saved, or a standalone binary from
`https://dl.folslate.com/latest.json`, which names the newest version and both
platform files. The binaries need no runtime; the npm distribution needs Node
22 or later.

## Sign in

Anonymous uploads work with no account. `folslate auth login` sends a 6-digit
code to an email address and saves the minted key; `folslate auth setup`
saves an existing key, prompting without echo so the secret never lands in
shell history (`--key` feeds the value non-interactively instead, which
exposes it in the process arguments, so prefer the prompt).
`folslate auth status` shows the signed-in account and
`folslate auth logout` forgets the stored credentials:

```bash
folslate auth login
folslate auth setup
folslate auth status
folslate auth logout
```

Credentials live in `~/.config/folslate/credentials.json`
(`XDG_CONFIG_HOME` respected) with mode `0600`. `FOLSLATE_API_KEY` wins over
the file, and `--api-key` wins for one run only. Pass secrets through the
environment, never on the command line, so they stay out of shell history.

Anonymous ownership secrets travel through `FOLSLATE_CAPABILITY` or
`--capability` on `folslate replace` and `folslate revoke`. A stored key and
`FOLSLATE_CAPABILITY` together are a conflict: `folslate replace` refuses and
tells you to pass `--capability` or unset the variable.

## Publish

```bash
folslate upload report.md
folslate upload page.html --title "Release notes"
cat report.md | folslate upload - --type markdown
```

`-` reads stdin (`./-` names a file that is really called `-`), and stdin
needs an explicit `--type markdown` or `--type html` because there is no file
name to read it from. `--title` overrides the derived title. Human output
prints the resolved title, the public URL, and the exact expiry
(`Expires: never` for a permanent document, `--json` carries
`expires: null`).

A signed-in upload is permanent. An anonymous upload expires in one day and
hands back an ownership secret beside the link: it authorizes
`folslate replace` until expiry and is shown once, so save it when the document
may need revising.

```bash
folslate replace doc_01k3n8w5q2r7v0xyz4a6bcdefg report-revised.md
folslate revoke doc_01k3n8w5q2r7v0xyz4a6bcdefg --capability "$FOLSLATE_CAPABILITY"
```

A replace swaps the document at the same link and restarts the 1-day
window. A revoke makes the document unmanageable for its remaining life, to
its holder too and irreversibly; the document keeps serving until expiry
because revocation is not a takedown.

## Commands

| Command | What it does |
| ------- | ------------ |
| `folslate auth` | `login`, `setup`, `logout`, `status` for credentials |
| `folslate upload <file>` | Publish Markdown or HTML; `-` reads stdin, `./-` a file named `-` |
| `folslate replace <id> <file>` | Replace the document at the same link |
| `folslate upgrade` | Update this CLI to the newest release (`update` is an alias) |
| `folslate get <id>` | Inspect an owned document |
| `folslate list` | List owned documents, newest first (`--limit`, `--cursor`, `--all`) |
| `folslate delete <id>` | Remove an owned document |
| `folslate revoke <id>` | Revoke an anonymous document ownership secret |
| `folslate report <id>` | File an abuse report (`--reason`) |
| `folslate me` | Show the signed-in account |
| `folslate keys` | List active API keys |
| `folslate usage` | Show quota usage |

`folslate get`, `folslate list`, `folslate delete`, `folslate me`,
`folslate keys`, and `folslate usage` need a signed-in account. `folslate get`
prints the stored metadata with its view count; `folslate list` pages newest
first at 50 a page up to 100 (`--all` walks every page). `folslate report`
needs no account.

## Agent-friendly usage

Every command accepts `--json` and `--quiet` alongside the human default.
`--json` prints the raw response payload when the API answers, and
`{ code, message, guidance }` when the API reports a failure. Local usage
errors (a malformed id, a missing capability, no saved key) print prose to
stderr, except `folslate auth status`, which prints `{ loggedIn: false }` in
`--json` mode. `--quiet` prints only the primary value, such as the URL. All
failures exit nonzero, so branch on the exit code and on `error.code`, never
on prose:

```bash
folslate upload report.md --json
folslate upload report.md --quiet
```

A stale binary copy refreshes itself at most once a day after other
commands, reporting on stderr so `--json` and `--quiet` output stays
stable. `FOLSLATE_NO_UPDATE_CHECK` or one run with `--no-update-check`
opts out entirely, which pinned automation should always set.

The shared envelope behind the API modes is documented at
`https://folslate.com/api`. The same three checks as a raw upload apply to
every publish: the link is public and cannot be unpublished, it expires in
one day unless the upload was authenticated, and the hosted page runs no
JavaScript and loads nothing external.
