Command-Line Tool (CLI)#

The project ships with a cli/ directory — a ready-to-use command-line program. Once your users log in with their own API key, they can call your platform API as themselves, right from the terminal.

By default it's called stackflare, but the whole command name is configurable — change one environment variable and it becomes your own brand (e.g. acme, mytool), then package it as a single file to ship to users. This page covers how to use it and how to rebrand it as your own.

1. Run it#

The CLI is written with Bun. During development you just run the source with Bun — no build needed.

bashcd cli
bun install        # first time
bun run start help # show help

Common commands:

bashbun run start login    # log in (paste an API key)
bun run start whoami   # show the current identity
bun run start logout   # log out

In development it automatically reads the config from the project root .env, so changes to .env take effect immediately — no rebuild required.

2. Rebrand it as your own ⭐#

The command name and service URL both come from the project root .envno code changes needed.

Open .env and set these two variables:

bash# Your platform URL (where the CLI calls the API)
PUBLIC_APP_URL=https://your-app.com

# Your command / brand name (defaults to stackflare)
PUBLIC_CLI_NAME=acme

After that:

  • Running bun run start help shows acme as the command name
  • The built binary filename is also acme
  • Users type acme login, acme whoami, etc.

PUBLIC_CLI_NAME keeps only letters, digits and ._-; other characters are stripped so it's safe as a command and filename.

How it resolves#

You don't need to know this to use it, but the priority order (high to low) is:

  1. The value baked into the binary at build time (no .env needed after distribution)
  2. The live value of PUBLIC_CLI_NAME / PUBLIC_APP_URL in .env when run from source
  3. Otherwise → command name defaults to stackflare; an empty URL makes login error out

So: editing .env takes effect instantly in dev; a built binary uses whatever was baked in. Remember to rebuild after rebranding, then distribute.

3. Build & distribute#

The build output is a single-file executable — users download and run it, with no Bun or Node required.

bashcd cli

bun run build       # current platform only, output in dist/<your-name>
bun run build:all   # build all 5 platforms at once

build:all output (assuming PUBLIC_CLI_NAME=acme):

PlatformFilename
macOS (Apple Silicon M1/M2…)dist/acme-darwin-arm64
macOS (Intel)dist/acme-darwin-x64
Linux (x64)dist/acme-linux-x64
Linux (ARM)dist/acme-linux-arm64
Windowsdist/acme-windows-x64.exe

Upload the right file to your download page / GitHub Release and share it with users.

Build a different brand on the fly#

If you don't want to edit .env, override via environment variables for a single build:

bashPUBLIC_CLI_NAME=acme PUBLIC_APP_URL=https://acme.com bun run build

4. How users use it (share this with them)#

  1. In your dashboard, go to Developer → API Keys and create a key starting with sk_live_
  2. Download the CLI for their system, make it executable and put it on PATH:
    bashchmod +x acme-darwin-arm64
    sudo mv acme-darwin-arm64 /usr/local/bin/acme
    
  3. Log in:
    bashacme login              # paste the key
    acme login --key sk_live_xxx   # or pass inline in a script
    
  4. The key is saved to ~/.acme/config.json (permission 600, owner-only)

For the full end-user install & usage guide, see API Keys & CLI.

5. Want to add a command?#

The CLI code is short — just 4 files under cli/src/:

FileRole
index.tsCommand entry & dispatch (add a case here)
config.tsLocal key storage, API URL resolution
constants.tsCommand name / URL resolution
api.tsBackend request wrapper

Add a case in the switch in index.ts and implement the function:

tsasync function cmdPing() {
  const config = await loadConfig()
  if (!config.key) {
    console.error(c.red(`Not logged in. Run: ${CLI_NAME} login`))
    process.exit(1)
  }
  const apiUrl = resolveApiUrl(config)
  const res = await request(apiUrl, "/v1/your-endpoint", { key: config.key })
  console.log(res)
}

// Register the command
case "ping":
  return cmdPing()

Create the matching backend endpoint under src/routes/v1/, validating the key with requireUserApiKey (see api-keys/verify.ts).