Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
eec75b7
feat: support multiple Grok accounts
kenryu42 Jul 15, 2026
1730450
feat(accounts): add cached quota management
kenryu42 Jul 15, 2026
1d3cfbf
fix: isolate Grok credentials and preserve reasoning
kenryu42 Jul 16, 2026
a64de96
fix: preserve Grok Build reasoning
kenryu42 Jul 16, 2026
9698501
feat(accounts): improve exhaustion rotation
kenryu42 Jul 16, 2026
503789c
fix(accounts): preserve active model during removal
kenryu42 Jul 16, 2026
cbc9e03
feat(accounts): add local account management dashboard
kenryu42 Jul 17, 2026
c200f54
feat(accounts): wire dashboard into /grok-cli-accounts gui
kenryu42 Jul 17, 2026
4516d41
fix(accounts): harden dashboard offline handling and card states
kenryu42 Jul 17, 2026
d836d6e
fix(accounts): clarify dashboard copy and error messages
kenryu42 Jul 17, 2026
1f7554f
fix(accounts): rename dashboard title to Pi Grok CLI
kenryu42 Jul 17, 2026
a944b15
feat(accounts): add cursor spotlight border to dashboard cards
kenryu42 Jul 17, 2026
9854154
chore: update .gitignore
kenryu42 Jul 17, 2026
2a633ab
feat(accounts): rebuild dashboard as a state-driven WebGL experience
kenryu42 Jul 17, 2026
2797eb1
feat(accounts): clarify dashboard quota and plan presentation
kenryu42 Jul 17, 2026
27aecad
chore: update .gitignore
kenryu42 Jul 17, 2026
116d59c
feat(vision): collapse on/off into a single toggle command
kenryu42 Jul 17, 2026
18e3bc4
refactor(accounts): dispatch manage-account menu actions with switch
kenryu42 Jul 17, 2026
b59cc42
docs(accounts): describe gui subcommand as browser UI
kenryu42 Jul 17, 2026
5a247a2
fix(dashboard): raise ghost button border contrast in appbar
kenryu42 Jul 18, 2026
3944b16
fix(dashboard): polish account console styling and a11y
kenryu42 Jul 18, 2026
294180c
fix(dashboard): close audit gaps in a11y, layout, and field rendering
kenryu42 Jul 18, 2026
5c3ff28
fix: harden payload and account state handling
kenryu42 Jul 18, 2026
c7b2b59
fix(docs): align security and configuration guidance
kenryu42 Jul 18, 2026
54cc847
docs: refresh README presentation
kenryu42 Jul 18, 2026
dd1c1b2
fix: resolve multiple-account review findings
kenryu42 Jul 18, 2026
f75ed4b
fix: resolve follow-up review findings
kenryu42 Jul 18, 2026
e8426ab
fix(dashboard): show free quota as unavailable
kenryu42 Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/assets/pi-grok-cli.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ dist/
docs/
*.tgz
.DS_Store
.agents
.impeccable
DESIGN.md
PRODUCT.md
.playwright-cli
.codex
2 changes: 2 additions & 0 deletions CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ Most users do not need these overrides. Only point base URL overrides at endpoin
| `PI_GROK_CLI_TOKEN_TIMEOUT_MS` | `30000` | Timeout for OAuth token requests. |
| `PI_GROK_CLI_IMAGINE_BASE_URL` | `https://api.x.ai/v1` | Override the Imagine API base URL. |
| `PI_GROK_CLI_IMAGINE_MODEL` | `grok-imagine-image-quality` | Override the Imagine image model. |

OAuth logins store the effective main API base URL in each account's credentials. Changing or removing `PI_GROK_CLI_BASE_URL` or `GROK_CLI_BASE_URL` does not immediately redirect an already authenticated account; its stored URL remains active until token refresh or re-login. Log in again to apply the change immediately.
80 changes: 66 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@
[![npm version](https://img.shields.io/npm/v/pi-grok-cli?label=npm&color=blue)](https://www.npmjs.com/package/pi-grok-cli)
[![License: MIT](https://img.shields.io/badge/License-MIT-red.svg)](./LICENSE)

<div align="center">

[![Pi Grok CLI](./.github/assets/pi-grok-cli.png)](./.github/assets/pi-grok-cli.png)

</div>

Use your X Premium or SuperGrok subscription in [pi](https://pi.dev/) with a clean, focused toolset.

- **Vision for text-only models** — automatically describe images with a vision-capable Grok model and cache descriptions locally.
- **Subscription OAuth** — sign in through a browser or device code; tokens refresh automatically.
- **Multiple accounts** — keep independent Pi logins, switch from a TUI or browser UI, and rotate automatically on exhausted-balance error.
- **Usage tracking** — check account limits, remaining credits, and reset times from pi.
- **Grok Imagine** — generate JPEGs from the TUI or let Grok call the `image_gen` tool, with inline previews.
- **Subscription OAuth** — sign in through a browser or device code or reuse an official Grok Build login; tokens refresh automatically.
- **Vision for text-only models** — automatically describe images with a vision-capable Grok model and cache descriptions locally.
- **Model-scoped compatibility** — Cursor-style tool names only for Grok Build and Composer 2.5. All other models keep Pi's native tools.
- **Usage tracking** — check account limits, remaining credits, and reset times from pi.

> Requires pi 0.80.0 or newer and an xAI/Grok account with access to the selected model. Model availability varies by account, plan, region, and xAI rollout. The Grok Build executable is not required.
> Requires pi 0.80.9 or newer and an xAI/Grok account with access to the selected model. Model availability varies by account, plan, region, and xAI rollout. The Grok Build executable is not required.
>
> pi-grok-cli is an unofficial community integration. It does not bypass xAI access controls, quotas, or billing.

Expand All @@ -39,7 +46,8 @@ Choose **Grok CLI**, then select one of these methods:

- **Browser login (default)** — opens xAI authorization and completes a PKCE exchange through a local loopback callback. If xAI shows a one-time code instead of redirecting to pi, paste that code into pi to complete the active PKCE exchange.
- **Device code login (headless)** — displays a URL and short code for SSH, containers, and other headless environments.
- **Use existing Grok Build login** — appears when a valid official `~/.grok/auth.json` entry is available. The file is read-only to this extension.

To add another login, run `/grok-cli-accounts`, choose **+ Add account**, and optionally label it. The extension adds a stable provider alias and pre-fills `/login <provider-id>`; press Enter to complete Pi's native login flow. For a browser UI with an account and quota overview, run `/grok-cli-accounts gui`; adding an account there starts browser login immediately. Use only accounts you own or are authorized to access.

### 3. Select a model

Expand Down Expand Up @@ -71,7 +79,7 @@ The table describes metadata bundled with this extension, not live model discove
| Model ID | Registered context | Reasoning | Input | Coding tools |
| --- | ---: | --- | --- | --- |
| `grok-composer-2.5-fast` | 200K | no | text; images can be described through vision routing | Cursor-compatible names |
| `grok-build` | 512K | yes | text + image | Cursor-compatible names |
| `grok-build` | 500K | yes | text + image | Cursor-compatible names |
| `grok-4.3` | 1M | yes | text + image | native pi names |
| `grok-4.5` | 500K | yes | text + image | native pi names |
| `grok-4.20-0309-reasoning` | 2M | yes | text + image | native pi names |
Expand All @@ -82,7 +90,27 @@ The table describes metadata bundled with this extension, not live model discove

### OAuth authentication

Use `/login` to authenticate through a browser or device code, or reuse an official Grok Build login. Pi stores and refreshes OAuth credentials automatically. For automation, `GROK_CLI_OAUTH_TOKEN` supplies a direct token without automatic refresh.
Use `/login` to authenticate through a browser or device code. Pi stores and refreshes OAuth credentials automatically. For automation, `GROK_CLI_OAUTH_TOKEN` supplies a direct token without automatic refresh.

Run `/grok-cli-accounts` to add, switch, rename, relogin, log out, or remove accounts. Each account is registered as an independent Pi provider (`grok-cli`, `grok-cli-2`, and so on), so Pi keeps its OAuth credential separately in `auth.json`. The base `grok-cli` slot is permanent; aliases can be removed. Existing aliases keep their provider IDs, and a removed alias number is reused by the next account when it is the lowest available slot.

Run `/grok-cli-accounts gui` to open the same account controls in a local browser UI with monthly and weekly quota meters. The browser UI binds to a random `127.0.0.1` port for the current Pi session, completes browser login without exposing credentials to the page, and closes on Pi session shutdown or after 15 minutes without requests. Its private local URL grants access to account controls while the server is running; do not share it. Browser login and manual one-time-code entry are supported in the browser UI, while device-code login remains available through the TUI for headless environments.

The account selectors show the last cached quota for every logged-in account as consumed monthly and weekly usage. Press `r` to refresh all logged-in accounts without switching models or changing the selected account. Refreshes run three accounts at a time; a failed account keeps its previous cached value and is marked as failed for the current dialog. Values older than 30 minutes are labeled stale. Opening the selector does not refresh automatically.

`GROK_CLI_OAUTH_TOKEN` applies only to the permanent base account. When it is set, the accounts UI identifies the environment token and tells you to unset it instead of presenting a logout action that cannot remove it.

#### Automatic exhaustion rotation

When at least two configured accounts are logged in, pi-grok-cli rotates after a final Grok assistant error whose trimmed message is exactly:

```text
OpenAI API error (402): 402 "Grok Build usage balance exhausted"
```

Rotation waits until Pi has finished retries, compaction, and tool activity. It preserves the current model when available and automatically continues the interrupted request once. Accounts that returned the exact error are skipped for five minutes within the current Pi session, including across new requests and successful continuations. A successful relogin makes that account immediately eligible again. If every logged-in account is exhausted or still cooling down, the extension stops without wrapping and reports that all accounts are exhausted.

Within the eligible circular fallback order, quota values cached less than 30 minutes ago rank candidates by their tightest remaining monthly or weekly percentage. Candidates with stale, missing, or invalid quota keep their circular slots, and equal scores keep circular order. Failover reads the cache only—it never fetches billing data—and quota ranking never rotates a healthy account or chooses the initial account. Similar 402 messages, 401s, 429s, non-Grok errors, and non-final errors do not trigger rotation. A manual model change before failover cancels the pending rotation.

### Model-scoped Cursor compatibility

Expand All @@ -91,6 +119,8 @@ Pi's native tool vocabulary remains the default. Cursor-compatible tool names ar
- `grok-cli/grok-build`
- `grok-cli/grok-composer-2.5-fast`

Managed account aliases expose the same two model IDs with the same compatibility behavior.

Only these two models get Cursor-compatible tool names. Grok 4.5, future Grok models, and other providers continue to use Pi's native tools. No extra shims.

| Compatibility tools | Implementation |
Expand All @@ -117,28 +147,50 @@ When `read` or `Read` returns an image to a text-only model, pi-grok-cli describ

### Grok Imagine image generation

Run `/grok-cli-imagine <prompt>` to generate and preview a JPEG, or let any active model call the `image_gen` tool. Both use the current Grok CLI OAuth token and save the result under the current session or a requested output path. The command supports `--aspect`, `--out`, and `--resolution 1k`.
Run `/grok-cli-imagine <prompt>` to generate and preview a JPEG, or let any active model call the `image_gen` tool. Both use the current or last successfully selected Grok account and save the result under the current session or a requested output path. The command supports `--aspect`, `--out`, and `--resolution 1k`.

`image_gen` is enabled by default across providers and is independent of Cursor compatibility. Use `/grok-cli-imagine:tool [on|off|status]` to manage its persisted availability without disabling the direct command.

## Commands

| Command | Description |
| --- | --- |
| `/grok-cli-usage` | Fetch current quota, remaining credits, and reset times. |
| `/grok-cli-accounts [gui]` | Manage Grok accounts in the TUI, or add `gui` for the local browser UI with account and quota controls. |
| `/grok-cli-usage` | Fetch current quota, update its cache, and show cached data if refresh fails. |
| `/grok-cli-imagine <prompt>` | Generate and preview an image. Supports `--aspect`, `--out`, and `--resolution 1k`. |
| `/grok-cli-imagine:tool [on\|off\|status]` | Toggle, set, or report persistent model-callable `image_gen` availability. |
| `/grok-cli-vision` | Toggle vision routing on or off. |
| `/grok-cli-vision:status` | Show vision state, describer model, configuration path, and cache statistics. |
| `/grok-cli-vision:on` / `/grok-cli-vision:off` | Enable or disable vision routing. |
| `/grok-cli-vision:cache-clear` | Remove all cached image descriptions. |

## Configuration

All extension settings are read from `~/.pi/grok-cli.json`. The file is created after the first setting change and defaults to:
Extension-owned data is grouped under `~/.pi/grok-cli/`:

```text
~/.pi/grok-cli/
├── config.json
├── vision-cache.json
└── quota-cache.json
```

`config.json` contains settings and account labels. The two cache files contain derived vision descriptions and quota responses; neither contains OAuth tokens. Pi owns OAuth credentials in its `auth.json`; this extension does not read Grok Build credentials.

The configuration file is created after the first setting change and defaults to:

```json
{
"version": 1,
"version": 2,
"accounts": {
"nextAccountNumber": 2,
"selectedProvider": "grok-cli",
"items": [
{
"provider": "grok-cli",
"label": "Account 1"
}
]
},
"imagine": {
"enabled": true
},
Expand All @@ -152,7 +204,7 @@ All extension settings are read from `~/.pi/grok-cli.json`. The file is created
}
```

Legacy Imagine and vision settings are migrated automatically. The vision cache remains separate at `~/.pi/grok-cli-vision-cache.json`.
Existing `~/.pi/grok-cli.json`, `~/.pi/grok-cli-vision-cache.json`, version 1 configuration, and legacy Imagine and vision settings are migrated atomically while preserving feature settings and cache data. A conflicting file at the new location remains authoritative and the legacy file is preserved with a warning instead of being overwritten.

`model` must identify an image-capable model. Invalid values are reported and replaced with safe defaults. Manual changes apply on the next image read.

Expand All @@ -170,7 +222,7 @@ See [Advanced configuration](./CONFIGURATION.md) for OAuth, callback, endpoint,
| Problem | What to do |
| --- | --- |
| grok-cli is missing from `/model` | Confirm the package appears in `pi list`, run `/login`, choose **Grok CLI**, then restart pi or run `/reload`. |
| Browser login cannot bind or complete | Paste the complete callback URL into pi when prompted. If xAI displays a one-time code instead, paste it into the same prompt. Otherwise, use device-code login or adjust `PI_GROK_CLI_CALLBACK_HOST` and `PI_GROK_CLI_CALLBACK_PORT`. Never post the callback URL or authorization code publicly. |
| Browser login cannot bind or complete | If the callback listener started but the browser redirect does not complete, paste the complete callback URL into pi when prompted. If xAI displays a one-time code instead, paste it into the same prompt. If pi reports that the listener could not bind, use device-code login or adjust `PI_GROK_CLI_CALLBACK_HOST` and `PI_GROK_CLI_CALLBACK_PORT`. Never post the callback URL or authorization code publicly. |
| Authentication returns HTTP 401 or 403 | Run `/login` again and confirm the account can access the selected model. Replace an expired `GROK_CLI_OAUTH_TOKEN` if using the bypass. |
| A listed model is unavailable | Availability can differ by account or region, and the catalog is bundled rather than discovered live. Try another model or update the extension. |
| Images are not being described | Run `/grok-cli-vision:status`, confirm routing is on, and verify Grok authentication. Native image-capable models bypass routing by design. |
Expand Down
12 changes: 8 additions & 4 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ The maintainer aims to acknowledge a complete report within 7 calendar days and

## Security boundaries

- pi-grok-cli and its tools run with the user's operating-system permissions. File and shell tools can read or modify the workspace and execute commands when the model invokes them.
- OAuth credentials returned by this extension are stored and refreshed by pi. pi-grok-cli may read the verified official Grok CLI entry in `~/.grok/auth.json`, but never writes to that file.
- Prompts, conversation context, tool definitions, and tool results are sent to the configured Grok CLI proxy.
- pi-grok-cli and its tools run with the user's operating-system permissions. File and shell tools can access any path those permissions allow, including paths outside the workspace, and can execute commands when the model invokes them.
- OAuth credentials returned by this extension are stored and refreshed by pi. pi-grok-cli does not read or modify Grok Build credentials.
- Browser OAuth starts a temporary callback server on `127.0.0.1:56122` by default and falls back to an ephemeral port. `PI_GROK_CLI_CALLBACK_HOST` can bind it to another interface. The server validates the callback path and OAuth state and closes after login. Treat complete callback URLs and authorization codes as sensitive.
- `/grok-cli-accounts gui` starts a temporary account-management server bound only to an OS-assigned `127.0.0.1` port. A random capability URL bootstraps a session cookie; subsequent mutations require same-origin and CSRF validation. The page receives account labels, status, and quota data. It never receives stored OAuth credentials, callback URLs, or environment-token values; a manually entered one-time authorization code is handled transiently during login and is never returned by `/api/state`. Treat the private dashboard URL as sensitive and do not share it while the server is running.
- Prompts, conversation context, tool definitions, tool results, and native image inputs are sent to the configured Grok CLI proxy.
- Images handled by vision routing are sent to the configured describer model. The local vision cache stores descriptions and hashes, not raw images.
- Grok Imagine sends the selected account's bearer token, generation prompt, and options to `https://api.x.ai/v1` or `PI_GROK_CLI_IMAGINE_BASE_URL`. Generated JPEGs and PNG previews are saved under session storage, a requested output path, or temporary storage.
- Monthly and weekly quota totals and reset timestamps are cached per account in `~/.pi/grok-cli/quota-cache.json` with file mode `0600`. The cache does not contain OAuth tokens.
- Optional web search is delegated to `pi-web-access` and the providers configured there.
- A configured base URL override is trusted with bearer tokens, prompts, conversation data, and tool results.
- A configured main API base URL override is trusted with bearer tokens, prompts, conversation data, tool results, images, and billing queries. An Imagine base URL override is trusted with the bearer token and generation request described above.

Expected provider behavior, account-specific model availability, subscription quotas, model-generated content, a model choosing an enabled local tool, and changes made after a user deliberately configures an untrusted endpoint are generally out of scope unless pi-grok-cli violates a documented boundary or exposes data beyond that configuration.
Loading
Loading