docs: document the grok provider + ~/.grok session reuse (add-grok phase 7)
ober
100cb6341dfcbaf03c4ffca02f44753b53305e83
--- a/docs/cli.md +++ b/docs/cli.md @@ -51,9 +51,14 @@ jcode keys remove <provider> jcode keys list # provider names only, never values jcode keys unlock # unlock for this session jcode keys change-passphrase -jcode keys import [opencode|claude-code|aider|env|prompt|all] +jcode keys import [opencode|claude-code|aider|env|grok|prompt|all] ``` +`keys import grok` copies the current `~/.grok/auth.json` bearer token into the +encrypted store under `grok`. Grok tokens **expire** (~6 h) and the Grok CLI +hot-reloads `auth.json` on every `grok login`, so for most users the runtime +lookup is enough — see [Grok CLI session](providers.md#grok-cli-session). + Keys live in `~/.jcode/keys.enc` (AES-256-GCM, PBKDF2). See [providers.md](providers.md#secrets) for the storage details. --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -146,6 +146,7 @@ plaintext config**. - **Environment:** `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`, `OPENROUTER_API_KEY`, `DEEPSEEK_API_KEY`, `XAI_API_KEY`, `GROQ_API_KEY`, `MISTRAL_API_KEY`, `TOGETHER_API_KEY`, `CEREBRAS_API_KEY`, `PERPLEXITY_API_KEY`. + The `grok` provider also accepts `GROK_CODE_XAI_API_KEY` as a fallback. - **Encrypted store** (recommended) — AES-256-GCM at `~/.jcode/keys.enc`, unlocked with a passphrase (or `JCODE_PASSPHRASE` for non-interactive use): @@ -153,9 +154,22 @@ plaintext config**. jcode keys init # create the store jcode keys add anthropic # prompt for and store a key jcode keys import all # import from opencode / aider / env + jcode keys import grok # import the current ~/.grok session token jcode keys list ``` +- **Grok CLI session reuse** — if you have already run `grok login`, the + `grok` provider reads `~/.grok/auth.json` at runtime as the lowest-priority + fallback. You do not have to copy the bearer token into `jcode`: + + ```bash + jcode --provider grok --model grok-build -p "hello" + ``` + + Tokens expire (~6 h); re-run `grok login` when 401s appear. See + [Grok CLI session](providers.md#grok-cli-session) for the full resolution + order. + Local providers (**Ollama**, **MLX**) need no key. See [providers.md](providers.md) for endpoints and model setup. --- a/docs/providers.md +++ b/docs/providers.md @@ -1,9 +1,10 @@ # Providers & models -`jcode` speaks to 13 LLM providers behind one interface. The active provider and +`jcode` speaks to 14 LLM providers behind one interface. The active provider and model come from config (`provider` / `model`), the `--provider` / `--model` flags, or the `/provider` and `/model` slash commands. If none is set, the -provider is auto-detected from whichever API key is present. +provider is auto-detected from whichever API key is present (or, for `grok`, +an existing `~/.grok/auth.json` session token). ## Supported providers @@ -15,6 +16,7 @@ provider is auto-detected from whichever API key is present. | `openrouter` | OpenAI-compatible | `https://openrouter.ai/api/v1` | Bearer | | `deepseek` | OpenAI-compatible | `https://api.deepseek.com/v1` | Bearer | | `xai` | OpenAI-compatible | `https://api.x.ai/v1` | Bearer | +| `grok` | OpenAI Responses | `https://cli-chat-proxy.grok.com/v1` | Bearer (`~/.grok` session) | | `groq` | OpenAI-compatible | `https://api.groq.com/openai/v1` | Bearer | | `mistral` | OpenAI-compatible | `https://api.mistral.ai/v1` | Bearer | | `together` | OpenAI-compatible | `https://api.together.xyz/v1` | Bearer | @@ -23,8 +25,10 @@ provider is auto-detected from whichever API key is present. | `ollama` | OpenAI-compatible (local) | `http://localhost:11434/v1` | none | | `mlx` | OpenAI-compatible (local) | `http://127.0.0.1:8080/v1` | none | -The non-Anthropic, non-Google providers all share the OpenAI chat-completions -code path, so adding a new OpenAI-compatible endpoint is mostly a table entry. +The non-Anthropic, non-Google, non-Grok providers all share the OpenAI +chat-completions code path, so adding a new OpenAI-compatible endpoint is mostly +a table entry. `grok` speaks the **OpenAI Responses API** to the Grok CLI proxy +and is dispatched separately — see [Grok CLI session](#grok-cli-session) below. ## Models @@ -42,6 +46,7 @@ windows, and a default. A few highlights: | openrouter | `anthropic/claude-sonnet-4` | 30+ models across vendors | | ollama | `llama3.2` | `qwen2.5-coder`, `deepseek-r1`, `codellama`, … | | mlx | *(your local model directory)* | any MLX model you serve | +| grok | `grok-build` | whatever `~/.grok/models_cache.json` lists | The registry isn't a whitelist — set `model` to **any id the provider accepts** and it's used as-is. Live model and pricing metadata is cached under @@ -74,6 +79,39 @@ Serve a model with `mlx_lm.server` (default `http://127.0.0.1:8080/v1`), then: MLX gets sane sampling defaults automatically (see below) — without them, small quantized models loop on greetings or truncate XML mid-stream. +### Grok CLI session + +`grok` is a separate provider from `xai` even though both surface Grok models. +`xai` is a conventional API-key provider against `api.x.ai`. `grok` reuses an +existing **Grok CLI** login: it reads `~/.grok/auth.json` at runtime and sends +the session token as `Authorization: Bearer …` to the +`cli-chat-proxy.grok.com/v1/responses` endpoint (the OpenAI **Responses** API, +not chat-completions). + +```json +{ "provider": "grok", "model": "grok-build" } +``` + +You do **not** need to copy a key into `jcode`. As long as `grok login` has been +run, `jcode` finds the token automatically. Key resolution order for `grok` is: + +``` +XAI_API_KEY → GROK_CODE_XAI_API_KEY → encrypted store → jcode.json → ~/.grok/auth.json +``` + +Tokens expire (default ~6 h) and the Grok CLI hot-reloads `auth.json` on every +login, so the runtime lookup keeps `jcode` aligned with `grok login` without +re-importing. On a 401 `jcode` raises **"Run `grok login` to refresh +~/.grok/auth.json"** instead of a raw API error. `jcode keys import grok` is +also available if you prefer to copy the current token into the encrypted store +(remember it will expire — re-import after each `grok login`). + +Default model and metadata come from `~/.grok/models_cache.json` +(`info.base_url`, `info.api_backend`, `info.context_window`, `info.name`) with +fallbacks to `grok-build` / `https://cli-chat-proxy.grok.com/v1` / `responses` / +512000 / "Grok Build". Tool calling via Responses is not yet wired in — `grok` +runs as text-only chat for now (see `docs/add-grok.md` for the deferred work). + ## Sampling Sampling is **policy-driven** (`/forge sampling off|on|strict`): @@ -118,6 +156,8 @@ API keys are stored encrypted at `~/.jcode/keys.enc`: - **Permissions** — the file is `chmod 0600` after every write. Manage it with `jcode keys …` ([CLI reference](cli.md#keys)). `jcode keys import` -pulls existing keys from opencode (`auth.json`), aider (`~/.aider.conf.yml`), or -the environment. Resolution order at runtime is **env var → encrypted store → -plaintext config**. +pulls existing keys from opencode (`auth.json`), aider (`~/.aider.conf.yml`), the +environment, or `~/.grok/auth.json` (`jcode keys import grok`). Resolution order +at runtime is **env var → encrypted store → plaintext config**; the `grok` +provider additionally falls back to **`~/.grok/auth.json`** when none of those +match, so an existing `grok login` is enough. --- a/docs/tools.md +++ b/docs/tools.md @@ -82,9 +82,12 @@ model instead of executing; `prompt` surfaces an interactive **Landlock** on Linux, **Seatbelt** on macOS, **Capsicum** on FreeBSD, **pledge+unveil** on OpenBSD. The external-LLM sandbox is tight by design: it can read system roots, write only `cwd` / `/tmp` / the chosen provider's auth -dir, and exec only from standard bin paths — every other provider's credentials -plus `~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.netrc`, `~/.config/gh`, `~/.docker` are -denied. +dir (`~/.claude`, `~/.gemini`, `~/.codex`, `~/.config/opencode`, **`~/.grok`**), +and exec only from standard bin paths — every other provider's credentials plus +`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.netrc`, `~/.config/gh`, `~/.docker` are +denied. The deny list is symmetric: when the chosen CLI is `claude`, `~/.grok` +is denied; when the chosen CLI is `grok`, `~/.claude` is denied; no CLI can +read another's bearer token. ### 4. Generated-artifact protection