# Ren CLI

import { Tabs, TabItem, Steps, Aside } from "@astrojs/starlight/components"

The Ren CLI (`ren`) is an agent-friendly client for the Ren API. Pair once, then drive
agents, skills, MCPs, pods, and projects from your terminal, or from inside another
agent's tool call.

## Install

<Tabs syncKey="pkg">
  <TabItem label="npm">

```bash
npm install -g @renai-labs/cli
```

  </TabItem>
  <TabItem label="npx (no install)">

```bash
npx @renai-labs/cli whoami
```

  </TabItem>
</Tabs>

Once installed, `ren upgrade` pulls the latest published version (`ren upgrade --check`
only reports), and `ren --version` prints the installed version.

## Authenticate

<Steps>

1. **Pair with your account.** For a human at a terminal, run the interactive flow:

   ```bash
   ren init
   ```

   For agents or CI, use the non-blocking device-code flow:

   ```bash
   ren init --device-start --output json
   ren init --device-poll --wait 25 --output json   # poll until status: signed-in
   ```

2. **Confirm you're signed in:**

   ```bash
   ren whoami
   ```

</Steps>

For non-interactive, long-lived auth (servers, CI), use a [personal access token](#personal-access-tokens-pats)
via `ren pats …`.

## Configuration

### Server URLs

| Setting         | Default                   | Environment variable |
| --------------- | ------------------------- | -------------------- |
| API server      | `https://api.renai.build` | `REN_SERVER_URL`     |
| App (dashboard) | `https://renai.build/app` | `REN_APP_URL`        |

Both values have trailing slashes stripped at runtime. Override them when pointing at a self-hosted or staging instance.

### Config directory

The CLI stores credentials and device-flow state under a config directory:

| Path                        | Purpose                                      |
| --------------------------- | -------------------------------------------- |
| `~/.config/ren/auth.json`   | Profiles, active profile name, bearer tokens |
| `~/.config/ren/device.json` | Pending device-code flow state (ephemeral)   |

If `XDG_CONFIG_HOME` is set, the directory becomes `$XDG_CONFIG_HOME/ren/` instead of `~/.config/ren/`.

`auth.json` is written with mode `0600` (owner read/write only). The directory is `0700`.

## Profiles

A **profile** is a named set of credentials stored in `auth.json`. The default profile is called `default`.

| Selector                      | Priority     | Example                          |
| ----------------------------- | ------------ | -------------------------------- |
| `--profile <name>` flag       | 1 (highest)  | `ren whoami --profile work`      |
| `REN_PROFILE` env             | 2            | `REN_PROFILE=work ren whoami`    |
| Active profile in `auth.json` | 3 (fallback) | Set via `ren auth switch <name>` |

When `--profile` or `REN_PROFILE` names a profile that does not exist in `auth.json`, the CLI exits with an error.

```bash
ren auth list          # show all profiles and which is active
ren auth switch <name> # set a different profile as active
ren auth logout        # remove the active profile (or --profile <name>)
ren auth status        # alias: ren whoami
```

## Authentication methods

### Device-code flow (interactive)

Used by `ren init` for human operators at a terminal. The CLI requests a device code from the server, opens the browser to the verification URL, and polls until the user approves. The resulting bearer token is stored in `auth.json` under the resolved profile name.

| Flag               | Description                                                       |
| ------------------ | ----------------------------------------------------------------- |
| `--profile <name>` | Store under a named profile (default: `default` or `REN_PROFILE`) |
| `--no-browser`     | Print the verification URL instead of opening the browser         |

### Device-code flow (agent / CI)

Two-step, non-blocking variant for automation:

```bash
# Step 1: start the flow, capture the verification URL
ren init --device-start --output json

# Step 2: poll until the user approves (or timeout)
ren init --device-poll --wait 25 --output json
```

`--device-start` writes a `device.json` and exits immediately with a `verificationUrl` and `userCode`. `--device-poll` reads that file and polls the server. `--wait <seconds>` controls how long to keep polling (default `0` = single check). On success, the profile is finalized and `device.json` is removed.

### Personal access tokens (PATs)

PATs (format `ren_pat_*`) are long-lived bearer tokens for non-interactive use: servers, CI, scripts, the [TypeScript SDK](/docs/developers/typescript-client/). They are **not** used to log the CLI in; the CLI authenticates via `ren init`.

PATs are sent as `Authorization: Bearer ren_pat_…` headers, and the API resolves them first.

| Subcommand                                                                   | Description                                                                |
| ---------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `ren pats create --name <string> --scopes <scope>… [--expires-at <iso8601>]` | Create a PAT. `--scopes` is repeatable. The plaintext token is shown once. |
| `ren pats list`                                                              | List active (non-revoked) PATs for the current profile.                    |
| `ren pats revoke <id>`                                                       | Revoke a PAT by its ID. Revocation is immediate and permanent.             |

Create a PAT scoped to what you need, then use it with the [TypeScript SDK](/docs/developers/typescript-client/) or any HTTP client:

```bash
ren pats create --name "ci-deploy" --scopes sessions:write --scopes projects:read
```

## Auth resolution priority

When the CLI or API receives a request, credentials are resolved in this order:

| Priority | Source                        | Token type      | Mechanism                      |
| -------- | ----------------------------- | --------------- | ------------------------------ |
| 1        | `--profile <name>` flag       | Bearer (stored) | Named profile from `auth.json` |
| 2        | `REN_PROFILE` env             | Bearer (stored) | Named profile from `auth.json` |
| 3        | Active profile in `auth.json` | Bearer (stored) | Fallback                       |

On the API side, the resolver checks the `Authorization` header for a PAT first, then the bearer token from `ren init`. The first match wins.

If no credential is found, the CLI exits with: `not authenticated — run 'ren init' to pair this CLI`.

## Scopes

Scopes define what a token or actor can access. They are attached to PATs at creation and to sessions/PATs via org role. They use the pattern `<resource>:<action>`:

| Resource          | Read scope           | Write scope           |
| ----------------- | -------------------- | --------------------- |
| Agents            | `agents:read`        | `agents:write`        |
| Skills            | `skills:read`        | `skills:write`        |
| MCPs              | `mcps:read`          | `mcps:write`          |
| Pods              | `pods:read`          | `pods:write`          |
| Sandboxes (owner) | `sandboxes:read`     | `sandboxes:write`     |
| Projects          | `projects:read`      | `projects:write`      |
| Triggers          | `triggers:read`      | `triggers:write`      |
| Sessions          | `sessions:read`      | `sessions:write`      |
| Vaults            | `vaults:read`        | `vaults:write`        |
| Environments      | `environments:read`  | `environments:write`  |
| Memory stores     | `memory-stores:read` | `memory-stores:write` |
| File stores       | `file-stores:read`   | `file-stores:write`   |
| Replays           | `replays:read`       | `replays:write`       |
| Blueprints        | `blueprints:read`    | `blueprints:write`    |
| Publishers        | `publishers:read`    | `publishers:write`    |
| PATs              | `pats:read`          | `pats:write`          |
| Billing           | `billing:read`       | `billing:write`       |
| Admin             | `admin`              | None                  |

When creating a PAT or assigning roles, you can reference groups that expand to multiple scopes:

| Group      | Expands to                                    |
| ---------- | --------------------------------------------- |
| `all`      | Every scope, including `admin`                |
| `member`   | All scopes except `admin` and `billing:write` |
| `readonly` | All `:read` scopes                            |

Org roles map to scope groups: `owner` and `admin` → `all`, `member` → `member`. A PAT's scopes cannot exceed the creator's scopes. If you request scopes you don't hold, creation fails and the denied scopes are listed.

For a conceptual explanation of scopes and visibility, see [Scopes](/docs/deep-dives/concepts/sharing/scopes/) and [Permissions](/docs/deep-dives/concepts/sharing/permissions/).

## Global flags

These flags are available on every `ren` command:

| Flag / Env var          | Type   | Description                                                       |
| ----------------------- | ------ | ----------------------------------------------------------------- |
| `--output json\|pretty` | string | Output format. Defaults to `pretty` in a TTY, `json` otherwise.   |
| `--profile <name>`      | string | Use a named profile. Overrides `REN_PROFILE`.                     |
| `--help`                | flag   | Print command help and exit.                                      |
| `REN_SERVER_URL`        | string | Override the API server URL (default: `https://api.renai.build`). |
| `REN_APP_URL`           | string | Override the dashboard URL (default: `https://renai.build/app`).  |
| `REN_PROFILE`           | string | Select a profile by name. Lower priority than `--profile`.        |

## Common commands

A few representative commands to get started. Run `ren <command> --help` for the full
flag listing on any command.

```bash
# Discover agents, skills, and MCPs across your account, org, and the registry
ren agents search --query "support triage" --sources user org registry
ren skills search --query "pdf" --sources user org registry

# Create an agent and ship a version
ren agents create --name "Release Notes" --icon "🤖"
ren agents versions create <agentId> --prompt "You are a release-notes writer." --model <model-id>

# List the available model ids
ren models list

# Pods & projects
ren pods list
ren projects create --pod-id <podId> --name "Onboarding"

# Schedule the project's primary agent on a cron
ren triggers create \
  --project-id <projectId> \
  --project-agent-id <projectAgentId> \
  --input-message "Summarize this week's activity" \
  --schedule "0 9 * * MON"
```

<Aside type="tip">
  The CLI covers the full API surface: pods, projects, agents, skills, MCPs, triggers, replays, vaults, file/memory
  stores, and models. Use `ren --help` to browse the command tree, and `--output json` whenever you parse the result.
</Aside>

## Issues

Bug reports and feature requests: [github.com/renai-labs/cli/issues](https://github.com/renai-labs/cli/issues).