# Reference

###### Full listing of every `localcan` command, flag, and what it returns.

Every command supports `-h`/`--help` to print a short synopsis and `--json` (or `--output json`) to emit machine-readable output instead of formatted text.

#### Quick tunnels

##### `localcan http <port> [--host <hostname>] [-H "Name: value"] [--domain <custom-domain>]`

Open an ephemeral HTTP tunnel to `http://localhost:<port>`, or to `http://<hostname>:<port>` with `--host`. `-H "Name: value"` sets a request header before forwarding and can be repeated, values take the templates from [Headers](/docs/configuration/headers). Auto-starts the daemon if it isn't running. Generates a random LocalCan.dev URL unless `--domain` is set to a [custom domain](/docs/public-urls/custom-domains) you've verified for your account.

##### `localcan https <port> [--host <hostname>] [-H "Name: value"] [--domain <custom-domain>]`

Same as `http` but for local servers that already terminate TLS. LocalCan trusts your server's certificate even if it's self-signed.

##### `localcan tcp <port> [--host <hostname>]`

Open a raw TCP tunnel. `--domain` and `-H` are not supported. Requires a license. Without a license the command exits with an error (there's no `.local` fallback for raw TCP).

Without a license, `localcan http` and `localcan https` still work but publish only a `.local` URL and print the Free plan signup link. `--domain` is rejected without a license.

See [Quick tunnels](/docs/cli/quick-tunnels) for more.

#### Daemon

##### `localcan start [-d|--detach] [-v|--verbose]`

Start the daemon. Foreground by default. `--detach` backgrounds the process. `--verbose` enables debug logging.

##### `localcan stop`

Stop the running daemon.

##### `localcan restart [-d|--detach] [-v|--verbose]`

Stop the running daemon (if any) and start a fresh one. Same flags as `start`.

##### `localcan reload`

Tell the running daemon to re-read every project file in `~/.localcan/projects/`. The right command after editing YAML by hand.

##### `localcan status`

Print daemon status: version, RPC protocol, project count, listening address. JSON shape:

```json
{
  "status":   "running",
  "version":  "1.0.0",
  "protocol": 1,
  "projects": 2,
  "address":  "/Users/you/.localcan/daemon.sock"
}
```

#### Resources

##### `localcan projects ls`

List loaded projects. Columns: `ID`, `NAME`, `SERVICES`. JSON shape:

```json
{
  "my-app": {
    "id": "my-app",
    "file_path": "/Users/you/.localcan/projects/my-app.yml",
    "ephemeral": false,
    "project": {
      "name": "My App",
      "icon": "🚀",
      "services": { "web": { "target": "http://localhost:3000", "endpoints": [/* … */] } }
    }
  }
}
```

##### `localcan services ls`

List services across all projects. Columns: `PROJECT`, `SERVICE`, `TARGET`, `ENDPOINTS`. JSON shape:

```json
[
  {
    "project_id": "my-app",
    "service_id": "web",
    "name": "Storefront",
    "target": "http://localhost:3000",
    "endpoints": 2
  }
]
```

##### `localcan tunnel ls`

List active tunnels (Public URLs). Columns: `TUNNEL URL`, `TARGET`, `PROTOCOL`, `PROJECT`, `EDGE`. JSON shape:

```json
[
  {
    "key":          "my-app/web/0",
    "project_id":   "my-app",
    "service_id":   "web",
    "tunnel_url":   "https://swift-falcon-12.localcan.dev",
    "local_target": "http://localhost:3000",
    "protocol":     "http",
    "edge_host":    "edge-eu1.localcan.dev"
  }
]
```

##### `localcan tunnel rm <url>`

Release a Public URL entirely. Removes the endpoint, plus the now-empty service and project when it was the last one. Pass a full URL or a bare host. With `--json` it returns `{ "url", "removed", "service_removed", "project_removed" }`.

##### `localcan config show`

Pretty-print the daemon configuration and loaded projects. Falls back to reading `config.yml` from disk if the daemon isn't running. JSON shape:

```json
{
  "daemon": { "license_key": "localcan_…", "device_id": "…", "proxy_https": { "enabled": true } },
  "projects": { "my-app": { "/* same as projects ls */": "" } }
}
```

##### `localcan config path`

Print the data directory (`~/.localcan/`).

#### Snapshots

Publish a static copy of a folder that LocalCan serves at a Public URL while your machine is offline. These commands need a running daemon. See [Snapshots](/docs/public-urls/snapshots) for the full feature.

##### `localcan snapshot publish <path> [--name <name>]`

Publish a folder to a new Public URL. LocalCan builds the folder when it is a buildable project, or packs it as is when it already holds an `index.html`. Streams build and upload progress, then prints the URL and what was published (`5 files · 6 KB`). `--name` shapes the address, so `--name my-app` gives `my-app-12.localcan.dev`. With `--json` the result is one object on stdout.

##### `localcan snapshot add <url> <path>`

Attach a Snapshot to a Public URL that does not have one yet, so an existing link keeps serving after your machine goes offline. It stops and points you at `update` when the URL already has a Snapshot.

##### `localcan snapshot update <url> [--path <path>]`

Rebuild and re-publish the Snapshot on a Public URL. Pass `--path` to publish a different folder. It stops and points you at `add` when the URL has no Snapshot yet.

##### `localcan snapshot ls`

List your Snapshots. Columns: `URL`, `SERVING` (`live` while your tunnel is up, `snapshot` while it is down), `MODE`, `FRESH` (`stale` when a source file is newer than the Snapshot), `PUBLISHED`, `SOURCE`. With `--json` each row is one object.

##### `localcan snapshot rm <url>`

Remove the Snapshot from a Public URL. The URL stays reserved and keeps serving live while your tunnel is up. Release the URL itself with `localcan tunnel rm`.

#### Access control

Password-protect a Public URL so only people who have the password can open it. Protection is enforced on LocalCan's servers, so it covers the URL's [Snapshot](/docs/public-urls/snapshots) too and keeps working while your machine is offline. These commands need a running daemon and a subscription plan. See [Access control](/docs/public-urls/access-control) for the full feature.

##### `localcan access password <url> [--set <pw>]`

Password-protect a Public URL. LocalCan generates a strong password and prints it, unless `--set` supplies your own. The password is stored with the project, so `access show` can read it back later. With `--json` the result is `{ "url", "mode", "password" }`.

##### `localcan access clear <url>`

Remove protection, making the URL public again. Leaves the URL and its Snapshot in place.

##### `localcan access show <url>`

Print one Public URL's protection: the mode (`public` or `password`) and, when it is password-protected, the password.

##### `localcan access ls`

List every Public URL with its protection. Columns: `URL`, `PROTECTION`. Passwords are shown by `access show`, not here.

#### Comments

Read and answer the review comments reviewers leave on a Snapshot. These commands need a running daemon. A thread is referenced by the number `ls` shows (`#14` or `14`) or by its comment id. See [Comments](/docs/public-urls/comments) for the full feature.

##### `localcan comments ls <url> [--resolved|--all] [--page <path>] [--version N]`

List the comment threads on a Snapshot, open ones by default. Columns: `#`, `STATUS`, `AUTHOR`, `AGE`, `PAGE`, `REPLIES`, `BODY`. With `--json` the daemon's payload is printed as is, replies included.

##### `localcan comments show <url> <#n|id>`

Show one thread in full: the page, the CSS selector the pin sits on, the reviewer's viewport, the Snapshot version, the body, and every reply.

##### `localcan comments reply <url> <#n|id> <body>`

Reply to a thread. The reply is posted under your account name, and reviewers on the thread get it by email unless reply notifications are off for the team or they unsubscribed. Replies only, new threads start on the page.

##### `localcan comments resolve <url> <#n|id>`

Resolve a thread, replies included.

##### `localcan comments reopen <url> <#n|id>`

Reopen a resolved thread.

##### `localcan snapshot comments <url> [on|pause|off]`

Show a Snapshot's comment state and counts, or switch comments on, pause them (existing threads stay readable, no new ones), or turn them off. Turning comments on needs a protected URL (`localcan access password` first) and a subscription plan.

#### Traffic inspector

##### `localcan traffic status | enable | disable | clear`

Show capture state, turn capture on or off, or drop all captured traffic.

##### `localcan traffic ls [--last N] [--host H] [--project P] [--method M] [--status S]`

List recent captured exchanges (newest first), then exit. `--status` accepts `200`, `2xx`, `4xx`, or `5xx`. With `--json` each row is one NDJSON object.

##### `localcan traffic get <id> [--format markdown|curl|http|har|json] [--redact]`

Export one captured exchange. Raw by default, `--redact` strips secrets. Output is written verbatim for redirecting or piping.

##### `localcan traffic watch [filters]`

Stream new exchanges live until Ctrl-C. Same filters as `ls`.

See [Traffic](/docs/cli/traffic) for filters and output shapes.

#### AI agents (MCP)

##### `localcan mcp`

Run a Model Context Protocol server over stdio so AI agents can read captured traffic and manage your Public URLs. Launched by an MCP host, not by hand.

##### `localcan mcp status | enable | disable | redact <on|off> | access <read_only|read_write>`

Manage MCP access from the terminal (the same controls as the desktop Settings). `status` shows agent access, redaction, and write access. `enable` and `disable` allow or block agent access. `redact on|off` toggles secret redaction in agent responses. `access read_only|read_write` allows or blocks the write tools (default `read_only`). Changes apply immediately.

See [AI agents](/docs/ai-agents/mcp) for setup and tools.

#### License

##### `localcan license activate <key> [flags]`

Activate a license key. Flags:

| Flag | Effect |
| --- | --- |
| `--accept-terms` | Skip the Terms-of-Service prompt. Required when `--json` is set and the Terms are not yet accepted. |
| `--usage-data` / `--no-usage-data` | Set the usage-data preference without prompting. |
| `--reassign` | Move a key already activated on another machine. |

##### `localcan license deactivate`

Free the seat. Daemon keeps running and drops to unlicensed (`.local` + proxy keep serving). Public URLs and `localcan tcp` pause until a new key is activated.

##### `localcan license set-usage-data <yes|no>`

Enable or disable anonymous usage data. Telemetry is opt-in and off by default. Works with or without a license.

##### `localcan license status`

Print the current mode, license key (masked), device, platform, CLI and desktop version, and update window. JSON shape:

```json
{
  "mode":            "licensed",
  "licensed":        true,
  "device_id":       "c5b1…",
  "device_name":     "my-laptop",
  "license_key":     "localcan_xxxxxxxxxxxx****",
  "platform":        "darwin",
  "arch":            "arm64",
  "cli_version":     "1.0.0",
  "desktop_version": "3.0.0",
  "terms_version":   "2026-05-20",
  "subscription": {
    "status": "trialing"
  },
  "updates": {
    "expired":             false,
    "allowed_until":       "2027-01-01T00:00:00Z",
    "releases_behind":     [],
    "cli_releases_behind": []
  },
  "cli_update": null
}
```

Without a key, `mode` is `"unlicensed"`, `licensed` is `false`, and `subscription`, `updates`, and `custom_domains` are absent. `terms_version` is always present and is the empty string until the Terms are accepted.

`subscription` is present when the activated key belongs to a subscription plan.

`cli_update` is non-null only on standalone builds when a newer CLI is available, and carries `{ "name": "1.0.1", "pub_date": "2026-05-01T12:00:00Z" }`.

#### Other

##### `localcan accept-terms`

Record acceptance of the [Terms of Service](https://www.localcan.com/terms) non-interactively, then exit. Useful for CI and scripted installs where the first-run prompt cannot run. Engine commands (`start`, `http`, `https`, `tcp`, `restart`) refuse to run until the Terms are accepted, either here or at the interactive prompt.

##### `localcan version`

Print the client and daemon versions:

```plaintext
localcan 1.0.0 (client)
daemon   1.0.0 (running)
```

JSON shape:

```json
{
  "client":        "1.0.0",
  "daemon":        "1.0.0",
  "daemon_status": "running"
}
```

`daemon_status` is `"running"`, `"not running"`, or `"unknown"`. When the daemon is not running, `daemon` is an empty string.

##### `localcan update [--check]`

Download and replace the binary in place. `--check` only reports whether an update is available. No-op on bundled installs (the desktop app's auto-updater handles this).

##### `localcan install-cli [--check|--uninstall]`

*Unix only.* Symlinks the running binary into `~/.localcan/bin/localcan` and adds that directory to your shell's `PATH` by appending a guarded block to your zsh, bash, or fish rc files. Normally invoked automatically (by the desktop app on macOS, by `install.sh` on Linux), so you rarely run it by hand. Cases where you might: re-running after switching shells, uninstalling PATH wiring (`--uninstall`), or inspecting the current state (`--check`, prints JSON).

#### Global flags

These can appear anywhere in the argument list:

| Flag | Effect |
| --- | --- |
| `--json`, `--output json` | Emit JSON instead of formatted text. Suppresses interactive prompts. |
| `-d`, `--detach` | Background the daemon. Applies to `start` and `restart`. |
| `-v`, `--verbose` | Enable debug logging. Applies to `start` and `restart`. |
| `--accept-terms` | Accept the Terms of Service non-interactively. Lets engine commands run on a headless host. |
| `-h`, `--help` | Print usage. |

