---
title: CLI reference
description: garage command groups, flags, and environment variables.
---

The `garage` CLI is the canonical shell client for the API. Every command also
accepts `--json` for machine-readable output; JSON is the default when
stdout is not a TTY.

## Global flags

Recognised anywhere in argv (before or after the subcommand):

| Flag            | Description                                                 |
| --------------- | ----------------------------------------------------------- |
| `--repo <name>` | Override the active repo for this invocation                |
| `--json`        | Machine-readable JSON on stdout, events as NDJSON on stderr |

| Env var             | Description                                           |
| ------------------- | ----------------------------------------------------- |
| `GARAGE_API_KEY`    | Overrides the stored auth.json key (takes precedence) |
| `GARAGE_SERVER_URL` | API base URL (default: `https://api.thegarage.sh`)    |
| `GARAGE_REPO`       | Default repo if no `--repo` is passed                 |
| `GARAGE_ANON_ID`    | Overrides the stored anonymous repo identifier        |

Repo names are bare — the server resolves them against your active org.
There is no per-command org override; switch the active org with
`garage org switch <slug>`.

## `garage init`

Authenticate the CLI, set up your active org, and optionally link the current
directory to a garage repo. An organization is auto-created at signup.
Idempotent — re-running surfaces current state without destructive changes.

```sh
garage init
garage init --no-link
```

Behavior:

- no auth → device-flow login
- active org set → report it
- no active org yet → activate the account's oldest org
- inside a git repo → offer to write `.garage/config.json` (`--no-link` skips)

## `garage whoami`

Print the active authentication, organization, and resolved repo context.
Exits 0 even when unauthenticated so agents can use it as a probe.

```sh
garage whoami
```

## `garage auth`

| Subcommand           | Purpose                                                        |
| -------------------- | -------------------------------------------------------------- |
| `garage auth login`  | Start the device-authorization flow and store a `grg_` API key |
| `garage auth logout` | Delete the stored credential and revoke the key                |
| `garage auth token`  | Print the active API key (or `--header` for `curl`)            |
| `garage auth status` | Show which credential is active (`env` vs `file`)              |

Bare `garage auth` is a back-compat alias for `garage auth login`.

```sh
# Print the active key for scripting
export GARAGE_API_KEY=$(garage auth token)

# Or use it directly with curl against the oRPC endpoint
curl -X POST -H "$(garage auth token --header)" \
  https://api.thegarage.sh/api/rpc/health/ping
```

**Note:**   `GARAGE_API_KEY` overrides the stored key for CI, agents, and scripts.

## `garage org`

An organization is auto-created when you sign up — its name is derived from
your display name or email (renamable later). Org slugs are opaque,
server-minted handles (`org-…`): copy them from `garage org list`, don't
invent them.

| Subcommand                   | Purpose                                           |
| ---------------------------- | ------------------------------------------------- |
| `garage org list`            | List organizations you belong to                  |
| `garage org current`         | Print the active organization                     |
| `garage org switch <slug>`   | Switch the active organization (slug from `list`) |
| `garage org create [--name]` | Create an organization (slug is server-minted)    |
| `garage org delete <slug>`   | Delete an organization you own                    |

## `garage repos`

| Subcommand            | Purpose                       |
| --------------------- | ----------------------------- |
| `garage repos create` | Create a new repo             |
| `garage repos import` | Import a repo from GitHub     |
| `garage repos get`    | Show a repo                   |
| `garage repos list`   | List repos in the current org |
| `garage repos delete` | Delete a repo                 |

```sh
garage repos list
garage repos create hello-world --description "..." --default-branch main
garage repos import site --from https://github.com/acme/site.git
garage repos delete hello-world --yes
```

For ephemeral, no-auth repos, see [`garage anon`](#garage-anon).

## `garage anon`

Manage anonymous, ephemeral repos that don't require authentication.
Identity is a local `anonId` stored in `~/.config/garage/anon.json` (or set
via `GARAGE_ANON_ID`). Anon repos are owned by that `anonId` and expire
after the TTL chosen at creation time.

| Subcommand           | Purpose                                                         |
| -------------------- | --------------------------------------------------------------- |
| `garage anon create` | Create an ephemeral anonymous repo                              |
| `garage anon list`   | List anon repos owned by this `anonId`                          |
| `garage anon get`    | Show details of an anon repo                                    |
| `garage anon clone`  | Clone an anon repo (mints a read token + wires git credentials) |
| `garage anon share`  | Share an anon repo with a human or an agent                     |
| `garage anon delete` | Delete an anon repo                                             |
| `garage anon whoami` | Print the local `anonId` and its source (`env` vs store)        |

```sh
garage anon create --ttl 6h
garage anon list
garage anon clone <name> /tmp/scratch
garage anon share <name> --role write --expires 2h
garage anon delete <name> --yes
```

`garage anon share` mirrors [`garage share`](#garage-share) for anonymous
repos: it mints an owner-scoped `share` token and prints a clone URL that
works with bare `git` — no account, no garage CLI on the recipient side. A
share can never outlive the repo (the TTL is clamped to the repo's remaining
lifetime), and `garage anon delete <name>` is the kill switch for every
share. `--link` creates a secure invite instead (see
[`garage invites`](#garage-invites)), clamped to the repo's expiry; manage
those with `garage anon invites list` / `garage anon invites revoke <id>`
(anon invites belong to your local `anonId`, not a logged-in session).

**Note:**   After `garage anon clone`, the git credential helper falls back to an anon-scoped mint when no
  auth is present, so `git fetch` / `git pull` keep working without re-running `garage auth`.

## `garage git`

Read and clone git content via the API — no shell-out needed for `log`,
`show`, `ls`, `branch`, `tag`, `compare`, or `diff`.

| Subcommand           | Purpose                                                    |
| -------------------- | ---------------------------------------------------------- |
| `garage git clone`   | Clone a repo (mints a token + wires the credential helper) |
| `garage git log`     | List commits                                               |
| `garage git show`    | Show a blob by oid or `ref:path`                           |
| `garage git ls`      | List tree entries                                          |
| `garage git branch`  | List, create, or delete branches                           |
| `garage git tag`     | List, create, or delete tags                               |
| `garage git compare` | Compare two refs                                           |
| `garage git diff`    | Diff two refs                                              |

```sh
garage git clone hello-world
garage git log hello-world --oneline -n 20
garage git ls hello-world src/ -r
```

`garage git clone` and `garage anon clone` read the repo's API-returned
storage remote, mint a short-lived token, and install local credentials for
the clone.

## `garage link` / `garage unlink`

Write or remove `.garage/config.json` in the current directory so
subsequent commands resolve the repo automatically.

```sh
# Auto-detect from `origin` when inside a clone, or pass an explicit name
garage link
garage link --repo hello-world
garage unlink
```

The link file records the bare repo name. That name resolves against your
active org, so switching orgs re-points the link; if the repo does not exist
in the new active org, repo and git commands surface `REPO_NOT_FOUND`.

## `garage tokens`

| Subcommand             | Purpose                                              |
| ---------------------- | ---------------------------------------------------- |
| `garage tokens mint`   | Mint a scoped repo token (`--scope read` or `write`) |
| `garage tokens list`   | List repo tokens (shares included)                   |
| `garage tokens revoke` | Revoke a repo token by id                            |

```sh
garage tokens mint hello-world --scope write --op agent
garage tokens list hello-world
garage tokens revoke hello-world <id>
```

You can always revoke tokens you minted yourself (so the revoke command
printed by `garage share` works for every sharer); revoking anyone else's
tokens requires repo admin.

`--op` selects the TTL cap and must be one of `refs`, `object`, `merge`,
`seed`, `clone`, `agent`, or `share`. Use `agent` for general write tokens;
`share` is the long-lived tier behind [`garage share`](#garage-share). Git
credential-helper requests derive push/fetch scope through the API's
`tokens.mintForGitRemote` path.

Repo tokens are for git remote operations. Use API keys from `garage keys`
when calling the RPC API or SDK.

## `garage share`

One command to onboard a single human or agent to **one specific repo** —
without org membership, accounts, or short-lived git-wire tokens. A share is
a long-lived, repo-scoped, revocable token embedded in a clone URL: whoever
holds the link has the granted access (bearer semantics).

```sh
garage share my-api --role write --expires 7d
```

Every share prints:

- a clone URL that works with **bare `git clone`** (the credential is
  percent-encoded into the URL — treat the whole URL as a secret),
- the `.garage/config.json` link snippet for the recipient's clone,
- a paste-ready onboarding block that reads the same for a human or an agent
  (`--out FILE` writes it to a file), and
- the exact `garage tokens revoke …` command that kills the share.

| Flag                   | Purpose                                                  |
| ---------------------- | -------------------------------------------------------- |
| `--role read\|write`   | Access level → token scope (default `read`)              |
| `--expires <duration>` | Share lifetime, e.g. `24h`, `7d` (default `7d`, clamped) |
| `--link`               | Mint a secure invite link instead (see below)            |
| `--out <file>`         | Write the onboarding instructions to a file              |
| `--print`              | Dry run — show the plan without minting anything         |

Inside a linked directory `garage share` needs no name; manage shares with
`garage tokens list` / `garage tokens revoke`.

**Caution:**   The default output embeds a live credential in the clone URL. Pasting it into chat, an issue, or a
  transcript shares the access with everyone who can read that channel. For untrusted channels use
  `--link`.

### Secure invite links (`--link`)

`garage share --link` prints an unguessable `https://thegarage.sh/invites/<id>`
capability URL instead of a credential-bearing clone URL — safe to paste in
chat, because the invite id is the only secret in the link:

```sh
garage share my-api --role read --link
```

Opening the invite renders the onboarding instructions; a fresh,
short-lived git credential is minted only on an explicit **Reveal** action
(never on a bare GET, so link previews can't consume it). Agents can fetch
the same invite as raw markdown at `/invites/<id>.md?reveal=1`. Invites are
revocable (`garage invites revoke <id>`), expiring, and policy-bounded
(`maxReveals`); garage stores only a hash of the invite id and never stores
a live credential.

## `garage invites`

Manage the secure invite links created by `garage share --link`.

| Subcommand              | Purpose                                 |
| ----------------------- | --------------------------------------- |
| `garage invites list`   | List share invite links you created     |
| `garage invites revoke` | Revoke an invite (stops future reveals) |

```sh
garage invites list
garage invites revoke <id>
```

Invites created by `garage anon share --link` belong to your local `anonId`
rather than a logged-in session — manage those with
`garage anon invites list` / `garage anon invites revoke <id>`.

Revoking an invite stops future reveals immediately; credentials already
revealed stay valid until their short TTL expires (revoke those with
`garage tokens revoke`). Treat every invite URL like a password.

## `garage keys`

Create, list, and delete additional API keys for CI, API, and SDK consumers.
Scopes are repeatable.

| Subcommand           | Purpose              |
| -------------------- | -------------------- |
| `garage keys create` | Create a new API key |
| `garage keys list`   | List API keys        |
| `garage keys delete` | Delete an API key    |

```sh
garage keys create ci --scope repos:read --scope tokens:mint
garage keys list
garage keys delete <id> --yes
```

Available scopes: `repos:read`, `repos:write`, `tokens:read`,
`tokens:mint`, `tokens:revoke`, `orgs:read`, `orgs:write`, `members:read`,
`members:write`, `keys:read`, `keys:write`, `agents:invoke`.

## `garage members`

Members commands administer the active org. Switch the administered org with
`garage org switch <slug>`.

| Subcommand                   | Purpose                  |
| ---------------------------- | ------------------------ |
| `garage members list`        | List members             |
| `garage members invitations` | List pending invitations |
| `garage members invite`      | Invite a member          |
| `garage members remove`      | Remove a member          |
| `garage members set-role`    | Change a member role     |
| `garage members accept`      | Accept an invitation     |
| `garage members cancel`      | Cancel an invitation     |

## `garage doctor`

Check the CLI's local configuration: auth store, file permissions, server
reachability, and the git credential helper.

```sh
garage doctor
```

## `garage git config-credential-helper`

Install or remove the git credential helper for garage remotes. `garage git
clone` wires credentials for the clone automatically; this command is useful
when you manage remotes yourself.

```sh
garage git config-credential-helper --global
garage git config-credential-helper --global --uninstall
```

## Agent discovery endpoints

The docs site exposes canonical bytes for coding agents alongside the rendered
pages:

| Endpoint                              | Content                                          |
| ------------------------------------- | ------------------------------------------------ |
| [`/skill.md`](/skill.md)              | Canonical garage SKILL.md for agent skill stores |
| [`/llms.txt`](/llms.txt)              | Plain-text index of every docs page              |
| `https://thegarage.sh/docs/<slug>.md` | Raw markdown for any docs page (append `.md`)    |

See [/docs/agents](/docs/agents) for the install-the-skill walkthrough.