# gujoctl

> The buyer CLI that signs in from a terminal and installs products you bought.

gujoctl is a single executable for macOS and Linux. It signs you in with browser approval, lists your library, and downloads, verifies and installs products you bought.

## Install

```bash
curl -fsSL "https://gujo.ai/download/gujo-install.sh?channel=dev" | sh
```

The install script fetches the latest release of that channel for your platform (`darwin-arm64`, `darwin-amd64`, `linux-amd64` or `linux-arm64`), checks its sha256 and puts it in `~/.local/bin`. Set `GUJOCTL_BIN_DIR` to use another folder.

The `dev` channel is the one open today. The address without a channel (stable) is still closed.

## Sign in

```bash
gujoctl login
```

1. gujoctl shows a user code and opens the approval page on the account host in your browser.
2. Signed in to your Gujo account in the browser, check the code and approve it.
3. gujoctl waits for the approval, then receives and stores an account API key.

On a server that cannot open a browser, use `gujoctl login --no-browser`. It prints the page and the code, and you approve from a browser on another device.

The key you get is a device sign-in key with six abilities: `products.read`, `device.entitlements`, `device.activate`, `device.install`, `device.usage` and `support.report`. It has no `mcp.read`. To connect an agent over MCP, create a separate key as described in [Getting started](getting-started.md).

The key is kept in the device's standard secret store: Keychain on macOS, secret-service on Linux (when a session bus is available), and otherwise a file with mode 600.

## Commands

| Command | What it does |
|---|---|
| `gujoctl login [--no-browser]` | Device sign-in. Shows a code and waits for browser approval |
| `gujoctl logout` | Revokes this device's key on the server and deletes it from the device |
| `gujoctl library list` | Lists the products you can use (numeric ids) |
| `gujoctl install <id> [--channel <c>] [--dir <path>]` | Gets an install plan, downloads, checks the sha256 and unpacks |
| `gujoctl version` | Version, commit, OS and architecture |
| `gujoctl help` | Usage |

Global flags:

- `--json`: writes only JSON to stdout. Progress messages go to stderr.
- `--api-url <url>`: changes the API address. The default is `https://api.gujo.ai`, and `GUJO_API_URL` sets it too.

## Installing a product

```bash
gujoctl library list
gujoctl install 42
```

`install` gets the server's install plan (`GET /api/products/{id}/install`), downloads the file from the signed download URL, and refuses to unpack it if the sha256 differs. Pick a channel with `--channel stable|beta|alpha|dev`. Without it you get stable. Where the product goes depends on the target the server reports.

| Target | Where it goes |
|---|---|
| `agent-skill` (agent skill, tar.gz) | `--dir` or `INSTALL_DIR`. Otherwise `skills/<name>` in the first of `~/.claude`, `~/.codex` and `~/.gemini/antigravity-cli` that exists, `./.agents/skills/<name>` inside a repository, and `~/.local/share/gujo/assets/<name>` as the last resort |
| `macos-app` (app, zip) | Moves the single `.app` to `/Applications` (or `~/Applications` if that is not writable), or to `--dir` |

An existing install is removed only after the new one is in place. Absolute paths, `..` and symbolic links pointing outside the archive are rejected. The key goes to the API host only, never to the download URL.

## Settings and environment variables

| Variable | Meaning |
|---|---|
| `GUJO_API_URL` | API address (same as `--api-url`) |
| `GUJOCTL_SECRET_STORE` | Secret store choice: `keychain`, `secret-service` or `file` |
| `GUJOCTL_CONFIG_DIR` | Config folder. The default is `~/.config/gujoctl` |

`config.json` in the config folder holds only non-secret sign-in details. With the file store, the key goes in `credentials.json` in the same folder.

## Exit codes

| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error |
| 2 | Usage |
| 3 | Sign-in required (401) |
| 4 | Forbidden (403) |

In scripts, exit code 3 means the user should run `gujoctl login` again.
