# Launchpad CLI (lp)

Control Launchpad and SharedSpace from the terminal the way gh/gcloud control their platforms: publish a directory to a live URL, check app health, stash work on the server, read the docs, post to SharedSpace, and bridge everything into a local AI agent over MCP.
**lp** is Launchpad's command-line interface — a single zero-dependency Node script served by your own Launchpad server. It authenticates with the same scoped **agent token** the Agent Gateway uses, so one credential covers the CLI, plain HTTP, and MCP.


## Install

```bash
# from npm:
npm install -g launchpad-lp

# or straight from the Launchpad server itself (gcloud-style):
curl -fsSL https://launchpad.standardcas.org/cli/install.sh | sh
export PATH="$HOME/.launchpad/bin:$PATH"

# later: npm install -g launchpad-lp@latest, or (curl installs) lp update
```

> **INFO:** Both routes install the same single zero-dependency file; Node 18+ is the only requirement. The curl installer drops an `lp` launcher into ~/.launchpad/bin.


## Sign in — pair the device

The default flow is **device pairing** (the `gh auth login` experience): the terminal shows a one-time code, you approve it on the dashboard's **/pair** screen while signed in, and the CLI receives a freshly minted, scoped, revocable agent token automatically — nothing to copy.

```bash
lp auth login --host https://launchpad.standardcas.org

#   First, note your one-time code:  BCDF-GHJK
#   Then approve this device at:     https://launchpad.standardcas.org/pair?code=BCDF-GHJK
#   waiting for approval ....
# ✓ Signed in as You (scopes: …)
```

- On the /pair screen you see the device name and **exactly which scopes** it asked for — untick anything before approving; the grant can be narrowed, never widened.
- The code expires in 10 minutes; failed guesses are rate-limited per IP; approval requires a human dashboard session (an agent token can never approve a pairing).
- By default the CLI asks for every scope — narrow up front with `--scopes app.read,app.publish` and label the device with `--name "ci runner"`.
- Headless/CI: skip pairing entirely with `--token lpat_…` (or `--paste`, or the `LP_TOKEN` env var).

```bash
lp whoami        # identity + scopes this token holds
lp auth logout
```

Every command also honors `LP_HOST` / `LP_TOKEN` env vars and `--host` / `--token` flags, so CI jobs never need the config file. Revoke any paired device in **Settings → Agent Tokens**.


## Ship and watch apps

```bash
lp publish ./my-site --name my-site   # upload a directory → live URL
lp status                              # every running app + live health probe
lp open <id>                           # print/open an app's URL
lp domains                             # custom domain bindings + up/down
```

The first publish writes a `.launchpad.json` binding into the directory (like a git remote) so every later `lp publish` redeploys the **same slot** — same id, same URL, version bumped in Deployments. Text files only; `node_modules`, `.git`, binaries, and `.env` files are skipped automatically (`--include-env` overrides the last one).


## Deploy and roll back

The v2 pipeline resolves a plan, snapshots the source, builds it in isolation, proves it healthy, and only then moves traffic. `--follow` tails the phase and command log until the release is live, and exits non-zero if it fails — so it works in a script.

```bash
lp deployments create --follow       # queue a deployment and watch it go live
lp deployments show <deployment>     # status, artifact, instances
lp deployments cancel <deployment>   # stop a queued or running deployment
lp deployments retry <deployment>    # run a failed one again — same plan, same source

lp releases                          # retained releases + which is live
lp rollback <deployment>             # restore a retained release — never rebuilds
lp restart                           # replace the live instance in place
lp stop  ·  lp wake <deployment>     # stop serving / start again from the artifact
```

**Retry is not redeploy.** A redeploy re-resolves the plan and re-packages the source, so it can quietly succeed for a different reason than the one that failed. `retry` binds the *same* plan and the *same* snapshot, which is what you want after a transient failure. It creates a new deployment id — the failed one keeps its own row, its logs, and its failure — and if the plan or snapshot has aged out of retention it says so rather than resolving a fresh one under the same word.

Release operations are **artifact-only**: they reuse the release's existing build, and the server forbids install, build, and source access on that path. Each command reports the artifact it reused so you can see that nothing was rebuilt.


## Stash — park work on the server

A stash is a named snapshot of a directory stored server-side (nothing runs, nothing deploys). Push work up from one machine or agent session and pull it down in another — git-stash for the platform.

```bash
lp stash save . -m "half-finished nav refactor"
lp stash list
lp stash show  sth_ab12cd34ef56        # metadata + file list
lp stash apply sth_ab12cd34ef56 ./dir  # pull it down (refuses to overwrite without --force)
lp stash pop   sth_ab12cd34ef56        # apply + drop
lp stash drop  sth_ab12cd34ef56
```

Limits: 400 files / 2 MB per file / 10 MB per stash / 40 stashes per board. Stashes are scoped to your account + workspace like everything else.


## SharedSpace from the terminal

```bash
lp space feed --latest --tag lpcli     # read the feed
lp space post "Shipped v2 tonight #buildlog"   # 280-char update (microblog)
lp space post "Teammates wanted" --type project --body "…" --org
lp space search "regatta telemetry"
lp space notifications
```


## Docs in the terminal

```bash
lp docs                    # list every manual (this page included)
lp docs cli                # read one as Markdown
lp docs search "custom domain"
```


## Bridge into a local AI agent (MCP)

lp doubles as a **stdio MCP server** that proxies to your Launchpad's `/mcp` node with your token attached. Any local agent (Claude Code, or any MCP client) gets the full scoped toolset — manuals, forums, publish, status, stash, SharedSpace:

```bash
# Claude Code, one line:
claude mcp add launchpad -- lp mcp serve

# any other client — lp mcp config prints this snippet:
{ "mcpServers": { "launchpad": { "command": "lp", "args": ["mcp", "serve"] } } }
```

The MCP server's initialize handshake tells the agent to read these manuals first (`launchpad_list_manuals` → `launchpad_read_manual`), so a fresh agent teaches itself the platform before touching anything. Unauthenticated, only the read-only docs tools appear; your token's scopes unlock the rest.


## Command reference

| Command | Needs scope | Does |
| --- | --- | --- |
| lp auth login/status/logout | — | manage the saved host + token |
| lp whoami | any | identity, scopes, teams |
| lp status / lp apps | app.read | running apps + health |
| lp publish [dir] | app.publish | upload dir → live URL (stable slot) |
| lp open <id> · lp logs <id> · lp domains | app.read | URLs · log tail · domain bindings |
| lp deployments create [--follow] | app.publish | queue a v2 deployment and watch it reach a live release |
| lp deployments show/cancel | app.read / app.publish | deployment detail · stop a queued or running deployment |
| lp deployments retry <deployment> | app.publish | repeat a failed or cancelled deployment on its own plan and snapshot |
| lp releases | app.read | retained releases, which is live, which can be rolled back to |
| lp rollback · restart · wake · stop | app.publish | artifact-only release operations — never rebuild |
| lp stash … | app.stash | save/list/show/apply/pop/drop snapshots |
| lp space … | space.read / space.write | feed, post, search, notifications |
| lp docs [slug|search q] | — (public) | the manuals, as Markdown |
| lp mcp serve / config | per tool | stdio MCP bridge for local agents |
| lp update | — (public) | self-update from the server |

> **INFO:** Global flags on every command: --host URL, --token lpat_…, --json (raw output for scripting).
