The Flowershow CLI allows you to publish your Markdown files and folders to Flowershow directly from your terminal.

Installation

The CLI is a single binary called fl (the install script also adds a flowershow alias).

macOS / Linux — run the install script:

curl -fsSL https://raw.githubusercontent.com/flowershow/flowershow/main/apps/cli/install.sh | sh

This detects your OS and architecture, downloads the latest binary, and installs it to /usr/local/bin/ (using sudo if needed). To install without sudo, for example from an AI agent or in CI, choose another directory:

curl -fsSL https://raw.githubusercontent.com/flowershow/flowershow/main/apps/cli/install.sh | FL_INSTALL_DIR="$HOME/.local/bin" sh

Windows — download fl_windows_amd64.zip (or fl_windows_arm64.zip for ARM) from the latest release and add the extracted fl.exe to your PATH.

Check it worked:

fl --version

Using an AI agent? Install the Flowershow skill and your agent can install and run fl for you. See Supported agents.

Manual installation

Download the archive for your platform from the latest release and put the fl binary on your PATH.

macOS (Apple Silicon)

curl -L https://github.com/flowershow/flowershow/releases/latest/download/fl_darwin_arm64.tar.gz | tar xz
sudo mv fl /usr/local/bin/

macOS (Intel)

curl -L https://github.com/flowershow/flowershow/releases/latest/download/fl_darwin_amd64.tar.gz | tar xz
sudo mv fl /usr/local/bin/

Linux (amd64)

curl -L https://github.com/flowershow/flowershow/releases/latest/download/fl_linux_amd64.tar.gz | tar xz
sudo mv fl /usr/local/bin/

Linux (arm64)

curl -L https://github.com/flowershow/flowershow/releases/latest/download/fl_linux_arm64.tar.gz | tar xz
sudo mv fl /usr/local/bin/

Upgrade

macOS / Linux — re-run the install script:

curl -fsSL https://raw.githubusercontent.com/flowershow/flowershow/main/apps/cli/install.sh | sh

Windows — download the latest fl_windows_amd64.zip (or fl_windows_arm64.zip) from the latest release and replace your existing binary.

Authentication

Before you can publish, you need to authenticate with your Flowershow account.

fl login

This prints a URL with a one-time code. Open it in your browser and approve, and the CLI finishes logging in (the code expires after 15 minutes). Your token is stored in ~/.flowershow/token.json.

To check who you're logged in as:

fl whoami

fl whoami exits with status 1 when you are not logged in (or your token has expired), so scripts can use it as an auth check.

To log out:

fl logout

Publishing a Site

The core command is fl. You can publish a single file or an entire folder, of Markdown, HTML, or both. .html files are served as-is, with the CSS, JavaScript and other files they reference (see Publishing HTML).

Publish a Folder

To publish a folder of notes:

fl ./my-notes

This will create a new site (named after the folder) and upload all supported files within it. The site URL (https://<site-name>-<username>.flowershow.me) is printed at the end.

Note

If you already have a site with the same name, fl asks whether to overwrite it or choose a new name (with --yes it refuses). See Name collisions.

Publish a Single File

To publish a single Markdown or HTML file:

fl ./my-note.md
fl ./report.html

To publish an HTML page together with its CSS, JavaScript or images, put them in a folder and publish the folder, so relative paths keep working.

Options

  • --name <siteName>: Specify a custom name for your site. For folder mode, the name is saved to a .flowershow file in the folder and remembered automatically on future runs.
  • --yes: Skip the new-site name confirmation prompt (useful for scripts and CI). It never allows overwriting an existing site.
  • --anon: Publish without an account, to a temporary site. See Publish without an account.
  • --overwrite: Publish a path that isn't linked to a site (no .flowershow file) into an existing site with the same name, replacing its content. See Name collisions.
  • --json: Print the result as JSON on stdout, for scripts and agents (requires fl 2.9.0 or later). See JSON output.

Example with options:

fl --name my-awesome-site ./my-notes

Publish without an account

Use --anon to publish with no account and no login (requires fl 2.5.0 or later):

fl --anon ./my-report

fl creates a site at a random https://<name>-anon.flowershow.me URL. It prints the claim link as soon as the site is created, and again at the end:

✓ Published (no account): https://k3x9q2mf-anon.flowershow.me
Claim it to keep it (expires 7 Oct 2026): https://flowershow.app/claim?siteId=…#token=fs_claim_…
  • It expires in 7 days unless you claim it. Updating the site doesn't extend the expiry. Once it expires, its pages, sitemap and feed stop being served straight away; images and other files linked directly from storage (r2.flowershow.app/…) can stay reachable for up to a day, until the nightly cleanup deletes them.
  • Claim it to keep it. Open the claim link, sign in or sign up, check the site's address and the account it's going to, and confirm with Add to my account to move the site into your account. It keeps its …-anon.flowershow.me address.
  • Or publish it while logged in. Run fl login, then publish the folder without --anon (fl ./my-report). On the computer that published it, fl adds the site to your account and updates it (requires fl 2.9.0 or later). Elsewhere, fl can't claim it and creates a new site in your account; use the claim link instead.
  • Re-running on the same folder updates the same URL. The folder's .flowershow file keeps the site ID; the claim token is kept in your user config folder (claims.json), not in the project, so it isn't committed with your files. The claim token and claim link are secrets: anyone with them can overwrite the site or take it until it's claimed, so don't share them publicly.
  • Single files and multiple paths aren't linked, so each run creates a new site.
  • Limits: 200 files and 50 MB in total. HTML-only content is fine.
  • Anonymous sites' pages, sitemap and feed tell search engines not to index them (noindex). Images and other files served directly from storage don't carry that header.
  • --anon never uses your login, even if you're logged in.
  • If the saved anonymous site has expired or been deleted, fl says so, removes the link from .flowershow and exits with status 1. Re-run the command to create a new anonymous site.
  • If the site has been claimed, fl --anon exits with status 1 and keeps the link: run fl login with the account that claimed it, then publish the folder without --anon (fl ./my-report) to update the claimed site.
  • --anon in a folder linked to a site in your account warns first: it creates a separate temporary site that the folder can't update later.
  • fl sync doesn't support anonymously published folders. Use fl --anon <folder> to update them.

fl never publishes anonymously unless you pass --anon. Without a login and without --anon it exits with status 1 and suggests both fl login and fl --anon <path>.

JSON output

Add --json to get the result as one JSON object on stdout; progress and messages go to stderr. It implies --yes, so it never waits for input.

fl --anon --json ./my-report
{
  "ok": true,
  "url": "https://k3x9q2mf-anon.flowershow.me",
  "siteId": "cm…",
  "siteName": "k3x9q2mf",
  "anon": true,
  "claimUrl": "https://flowershow.app/claim?siteId=…#token=fs_claim_…",
  "expiresAt": "2026-10-29T12:00:00.000Z"
}

claimUrl and expiresAt are only set for anonymous sites. claimed is true when the run added the folder's anonymous site to your account. On failure, ok is false, error holds the message and fl exits with status 1; fields already known (such as a new site's claimUrl) are still included.

Environment token

Set FLOWERSHOW_TOKEN to authenticate without fl login, for CI and cloud or headless agents. Create a personal access token (fs_pat_…) at cloud.flowershow.app/tokens, then:

FLOWERSHOW_TOKEN=fs_pat_... fl ./my-notes

The variable takes precedence over the token saved by fl login. fl whoami notes when it is in use. While it's set, fl login refuses to run, because a saved login would be ignored. fl logout removes only the saved login and tells you you're still authenticated through the variable; unset it to log out completely. Keep the token out of your repository: use your CI's secret store.

Updating a Site

fl is idempotent for linked folders — once a folder has been published, it syncs changes automatically instead of creating a new site. Just run the same command every time:

fl ./my-notes

For folder mode, the site name is stored in a .flowershow file inside your folder after the first publish, so you don't need --name on subsequent runs.

Name collisions

If a path is not linked (no .flowershow file — for example a folder you're publishing for the first time, or a single file) and its name matches a site you already have, fl will not sync into that site implicitly, because syncing replaces the site's content and deletes its files that aren't in your path. Instead:

  • Interactively, fl warns you with the existing site's name and URL and asks whether to overwrite it or choose a new name.
  • With --yes, fl refuses and exits with a non-zero status, suggesting fl --name <new-name> <path> (publish as a new site) or fl --overwrite <path> (replace the existing site).
# Publish as a new site instead
fl --yes --name my-notes-2 ./my-notes

# Deliberately replace the existing site's content
fl --yes --overwrite ./my-notes

Single files are never linked, so re-publishing fl ./my-note.md into its existing site needs --overwrite (or confirming the prompt).

Exit codes

Every fl command exits with status 0 on success and a non-zero status on failure (not authenticated, path not found, site not found, refused overwrite, API or upload errors), so you can rely on it in scripts, CI and AI agents.

fl sync (deprecated)

fl sync still works but is deprecated. The plain fl command now handles both creating and syncing automatically.

If you need --dry-run or --verbose, fl sync is currently the only way to access those options:

# Preview changes without making them
fl sync --dry-run ./my-notes

# See all files including unchanged ones
fl sync --verbose ./my-notes

Managing Sites

List Sites

To see all your published sites:

fl list

Delete a Site

To delete a site and all its content:

fl delete <site-name>
fl delete --yes <site-name>   # skip the confirmation prompt

Site settings

To see a site's plan, privacy, comments, search, GitHub connection and custom domain:

fl settings                  # uses the .flowershow file in the current folder
fl settings --name <site-name>

Annotations

With Annotations on, anyone with the link can select text on a page and leave a note.

fl --annotations ./my-draft         # publish and turn annotations on for the site
fl --annotations=false ./my-draft   # publish and turn them off
fl annotations pull                 # open notes, as Markdown for an AI agent
fl annotations pull --name my-drafts --path notes/draft.md
fl annotations pull --all --format json   # include resolved notes
fl annotations resolve <id> [<id>...]
fl annotations resolve --all --path notes/draft.md
fl annotations delete <id> [<id>...]
fl annotations delete --all --yes   # --yes is required without a terminal

--site works as an alias for --name. fl and fl settings print Annotations: ON — anyone with this link can annotate while they're on, and how many open annotations are waiting. A folder literally named annotations must be published as fl ./annotations.

Troubleshooting

  • "You must be authenticated…": Run fl login, set FLOWERSHOW_TOKEN, or publish without an account with fl --anon <path>.
  • "A site named … already exists": the path isn't linked to that site. Use --name <new-name> to publish a new site, or --overwrite to replace the existing one. See Name collisions.
  • "Site not found" (during fl sync): Make sure you're using the correct site name (check with fl list), or just use fl <path> which handles this automatically.
Built with LogoFlowershow