# NiceTryBot CLI

- [Introduction](#introduction)
- [Installing the Command](#installing-the-command)
    - [On Your Server](#on-your-server)
    - [On Your Laptop](#on-your-laptop)
    - [Updating the Command](#updating-the-command)
- [Managing Your Server](#managing-your-server)
- [Working With the Control Panel](#working-with-the-control-panel)
    - [Domains](#domains)
    - [Rules and Gyms](#rules-and-gyms)
    - [Calling Any Tool](#calling-any-tool)
- [Where Commands Run](#where-commands-run)
- [Options](#options)
- [Scripting](#scripting)
- [Using the Command With AI](#using-the-command-with-ai)

## Introduction

NiceTryBot ships with a `nicetrybot` command that looks after your installation and works with your control panel, on your server or from your laptop. It does two jobs:

<div class="content-list" markdown="1">

- **On your server**, it looks after the installation itself: updating, rolling back, installing add-ons, checking health, and reading logs.
- **On your server or your laptop**, it works with the control panel: adding and removing domains, changing protection modes, listing rules and gyms, and anything else an AI agent can do through the [MCP server](https://docs.nicetrybot.com/docs/0.x/mcp.md).

</div>

The control panel commands are calls to the same tools the MCP server gives agents, so the command, the control panel, and your agent all follow the same rules. A domain the command adds is checked exactly like one added in the control panel.

## Installing the Command

### On Your Server

The [installer](https://docs.nicetrybot.com/docs/0.x/installation.md) puts `nicetrybot` in `/usr/local/bin`, and every `nicetrybot update` replaces it with the copy that ships with the new release. There's nothing else to install.

> [!NOTE]
> The control panel commands and [remotes](https://docs.nicetrybot.com/docs/0.x/remotes.md) came after release `0.5.0`. If `nicetrybot domains` says it's an unknown command, run `nicetrybot update`.

### On Your Laptop

The same command runs on macOS and Linux, where it works with your control panel over HTTPS. It needs `curl` and `jq`. macOS 15 and newer ship with both; on older versions, install `jq` using `brew install jq`.

Download the command from the newest release and make it executable:

```shell
mkdir -p ~/.local/bin

curl -fsSL https://github.com/NiceTryBot/nicetrybot/releases/latest/download/nicetrybot \
  -o ~/.local/bin/nicetrybot

chmod +x ~/.local/bin/nicetrybot
```

Make sure `~/.local/bin` is on your `PATH`, then connect the command to your control panel by [adding a remote](https://docs.nicetrybot.com/docs/0.x/remotes.md#adding-a-remote):

```shell
nicetrybot remote add panel.example.com
```

### Updating the Command

To update the command on your laptop to the newest release:

```shell
nicetrybot cli update
```

It downloads the release's copy, checks that it's a complete, working script, and only then swaps it in place of the old one. If you installed the command somewhere only `root` may write, run it with `sudo`. To go to a specific release, pass `--version=vX.Y.Z`. `nicetrybot self-update` does the same thing.

To see which release your copy came from, and whether a newer one is out:

```shell
nicetrybot cli version
```

On your server, there's no need: `nicetrybot update` updates NiceTryBot and the command together, so they always come from the same release.

## Managing Your Server

These commands only ever work on the server they run on. Run them as `root`, or with `sudo`:

| Command | Description |
| --- | --- |
| `nicetrybot update` | Update to the newest release, backing up the database first. See [Upgrading Versions](https://docs.nicetrybot.com/docs/0.x/upgrade.md). |
| `nicetrybot update --version=vX.Y.Z` | Update to, or go back to, a specific release. |
| `nicetrybot rollback` | Put back the release and database from before the last update. |
| `nicetrybot addons` | List the marketplace add-ons built into the app. See [Installing Add-ons](https://docs.nicetrybot.com/docs/0.x/addons.md). |
| `nicetrybot addons add NAME…` | Build add-ons in. `NAME=KEY` also enters an add-on's licence key. |
| `nicetrybot addons remove NAME…` | Take add-ons out. |
| `nicetrybot addons keys` | Enter the licence keys your paid add-ons still need. |
| `nicetrybot apply` | Start the stack again with what you changed in `.env`. |
| `nicetrybot doctor` | Check the server, the containers, the control panel, and the app, with advice. |
| `nicetrybot status` | The release, the containers, and the add-ons. |
| `nicetrybot version` | The release running, and the newest one. |
| `nicetrybot cli update` | Update just this command, to the newest release. |
| `nicetrybot logs [SERVICE]` | Follow the logs of `app`, `worker`, `scheduler`, `edge`, `vector`, `postgres`, or `valkey`. |
| `nicetrybot artisan COMMAND…` | Run an Artisan command in the app, such as `admin:grant you@example.com`. |

The stack lives in `/opt/nicetrybot`, unless the installer was told to put it somewhere else, in which case `/etc/default/nicetrybot` says where.

## Working With the Control Panel

The following commands work on your server or, from your laptop, on a [remote](https://docs.nicetrybot.com/docs/0.x/remotes.md). To check who the commands act as, run `whoami`:

```shell
nicetrybot whoami
```

It prints the team, the user, what the commands are allowed to do, and when the token expires.

With a token for all of your teams, `nicetrybot teams` lists them and `nicetrybot team use SLUG` picks the one the commands work on. See [Working With Several Teams](https://docs.nicetrybot.com/docs/0.x/remotes.md#working-with-several-teams).

### Domains

To list your team's domains:

```shell
nicetrybot domains
```

```text
HOSTNAME           MODE     STATUS                DNS   ORIGIN
docs.example.com   observe  pending_verification  -     https://docs-origin.example.com
shop.example.com   enforce  active                edge  https://shop-origin.example.com
```

To [add a domain](https://docs.nicetrybot.com/docs/0.x/domains.md), give the hostname visitors type and the origin it should forward to. An origin without a scheme is assumed to use `https://`:

```shell
nicetrybot domains add docs.example.com docs-origin.example.com
```

Adding a domain prints the three steps that finish setup, in order: the ownership TXT record to add, the `X-NiceTry-Origin-Secret` header to [lock your origin](https://docs.nicetrybot.com/docs/0.x/origins.md) to so nobody can reach your site around the edge, and the DNS records that point at the edge. As in the control panel, nothing changes for your visitors until the domain is verified and its DNS points at the edge.

As you work through them, `nicetrybot domains check` shows where the domain stands. It looks up the TXT record, and verifies the domain as soon as the record appears. It then asks the origin whether it refuses requests without the header, and checks where public DNS points:

```text
✓ Ownership: Found the TXT record: the domain is verified.
✗ Origin locked to the edge: The origin served a request without the secret header (200), so anyone can go around the edge.
     The header, and how to lock the origin: nicetrybot domains secret docs.example.com
✗ DNS at the edge: No records found for docs.example.com yet.
     CNAME  docs.example.com  edge.example.net

Next: lock the origin (nicetrybot domains secret docs.example.com), then check again.
```

You may pass the same settings as the **Add domain** modal:

| Option | Description |
| --- | --- |
| `--www` | Serve `www.` in front of the domain as the same site. |
| `--host-header=rewrite` | Send the origin its own `Host` header rather than the visitor's. Use this for Laravel Vapor, Vercel, Netlify, Heroku, Render, and CloudFront. See [Host Headers](https://docs.nicetrybot.com/docs/0.x/domains.md#host-headers). |
| `--origin-host-header=HOST` | With `rewrite`, send this `Host` header instead of the origin's own. |
| `--forwarded-host-header=NAME` | A header that carries the visitor's hostname to the origin, such as `X-Forwarded-Host`. Separate several with commas. |

For example, to put a site hosted on a platform that routes by `Host` header behind NiceTryBot:

```shell
nicetrybot domains add docs.example.com docs-edge.example.com \
  --host-header=rewrite \
  --forwarded-host-header=X-Forwarded-Host
```

[Hosting Platforms](https://docs.nicetrybot.com/docs/0.x/domains.md#hosting-platforms) has the exact command for Laravel Vapor, CloudFront, Vercel, and more. `nicetrybot add domain` and `nicetrybot domain add` work too, as do `--rewrite-to-origin-host` and `--fwd-host-header` in place of the longer options.

The rest of a domain's life happens one command at a time:

```shell
nicetrybot domains check docs.example.com            # Ownership, the origin lock and DNS, and the next step
nicetrybot domains verify docs.example.com           # Check only the ownership TXT record
nicetrybot domains secret docs.example.com           # The origin secret header, and how to lock the origin to it
nicetrybot domains mode docs.example.com enforce     # off, observe or enforce
nicetrybot domains remove docs.example.com           # Take the domain out of NiceTryBot
```

> [!WARNING]
> Removing a domain deletes its request history, and the edge stops serving it straight away. Point the domain's DNS back at your origin first. The command asks before it removes anything; pass `--yes` to skip the question.

### Rules and Gyms

To list your team's [rules](https://docs.nicetrybot.com/docs/0.x/concepts.md#rules) and [gyms](https://docs.nicetrybot.com/docs/0.x/concepts.md#the-bot-gym), or to delete one by its ID:

```shell
nicetrybot rules
nicetrybot rules 12          # Just rule 12
nicetrybot rules remove 12

nicetrybot gyms
nicetrybot gyms remove 4
```

Deleting asks for confirmation first, unless you pass `--yes`. To create or change rules and gyms, use the control panel, an agent, or [any tool](#calling-any-tool).

### Calling Any Tool

Every tool the [MCP server](https://docs.nicetrybot.com/docs/0.x/mcp.md#available-tools) offers is available from the command line, including those your add-ons add. To list the tools your token may use:

```shell
nicetrybot tools
```

Then call one with `call`, passing its arguments as `key=value` pairs:

```shell
nicetrybot call query-traffic group_by=country period=7d
nicetrybot call backtest-rule source="TAG ip, ja4 AS 'dutch' FOR 1 DAY WHERE country = 'NL'" days=3
```

A value that reads as JSON, such as a number, `true`, or a list, is sent as that; anything else is sent as a string. You may also pass the arguments as a single JSON object:

```shell
nicetrybot call backtest-rule '{"id": 12, "days": 3}'
```

Add `--json` to see a tool's whole answer exactly as it sent it.

## Where Commands Run

The control panel commands run in the first of these places that applies:

<div class="content-list" markdown="1">

1. On this server's stack, when you pass `--local`.
2. On the remote named by `--remote=NAME`, or by the `NICETRYBOT_REMOTE` environment variable.
3. On your [current remote](https://docs.nicetrybot.com/docs/0.x/remotes.md#switching-remotes).
4. On this server's stack, when NiceTryBot is installed here.

</div>

On a terminal, the command prints where it's working before it does anything, such as `→ prod (https://panel.example.com), team Acme`, so a change never lands somewhere you didn't expect.

On your server, the command acts as the owner of the first administrator's current team, with every ability. Being able to run commands as `root` on the server is all the permission it needs. To work on another team, pass its slug:

```shell
nicetrybot domains --team=acme
```

## Options

| Option | Description |
| --- | --- |
| `--yes` | Don't ask before a rollback, or before removing a domain, rule, or gym. |
| `--json` | Print the control panel's answer as JSON. |
| `--remote=NAME` | Run a control panel command on that remote, rather than the current one. |
| `--local` | Run a control panel command on this server's stack, even when you have a current remote. |
| `--team=SLUG` | The team to work on. On a remote whose token works on all of your teams, for this command only. On your server, the first administrator's current team when left out. |
| `--token=TOKEN` | With `remote add` or `remote auth`: the API token. With `addons add`: your Composer token. When you leave it out, the command asks for the token without showing it, which also keeps it out of your shell's history. |
| `--no-backup` | Update without backing up the database first. `rollback` can't restore the database afterwards. |
| `--version=vX.Y.Z` | With `update`: the release to update to. |

To see every command, run `nicetrybot help`.

## Scripting

Every control panel command accepts `--json`, which prints the tool's answer as JSON for `jq` or your own scripts:

```shell
nicetrybot domains --json | jq -r '.domains[] | select(.protection_mode == "observe") | .hostname'
```

The command exits with a non-zero status when anything goes wrong, such as a validation error, a domain that doesn't exist, or a token that no longer works, and prints the reason to standard error.

## Using the Command With AI

The command is a good fit for agents working in a terminal, since every answer explains itself and `--json` is there when they want structure. You may give your agent a prompt like the following:

```text
Read https://docs.nicetrybot.com/docs/0.x/cli.md. Use the nicetrybot command to list my domains and tell me which ones are still in observe mode. Don't add, change, or remove anything until I say so.
```

If your agent supports MCP, you may connect it to the [MCP server](https://docs.nicetrybot.com/docs/0.x/mcp.md) directly instead. It offers the same tools.
