Skip to content

Repository files navigation

grok-search-cli

Agent-friendly CLI for Grok-powered web and X search.

Important

This is an unofficial, experimental project. It is not affiliated with or endorsed by xAI. It reuses a Grok Build login at the user's risk. xAI has not authorized this integration, and a technically successful request is not authorization. The user is responsible for whether their use complies with applicable xAI terms.

Status

V1 is implemented. Source and GitHub Release binaries are public. Use remains unofficial and at the user's risk. Do not operate the CLI as a shared service. See the V1 specification.

Install

V1 supports macOS and Linux on amd64 and arm64. The installer downloads the matching GitHub Release archive, verifies its SHA-256 sidecar, and writes grok-search to ${INSTALL_DIR:-$HOME/.local/bin}:

curl -fsSL https://github.com/patrick-fu/grok-search-cli/releases/latest/download/install.sh | bash

Pin a release tag with VERSION=<tag>. Put $HOME/.local/bin on PATH if needed. The installer does not edit shell rc files, use sudo, or read credentials.

From source:

go build -o grok-search ./cmd/grok-search

Update

grok-search update

update replaces the current binary with the latest GitHub Release for this platform after the same checksum verification as the installer. It does not refresh credentials or call xAI.

Agent skill

This repository is the only source for the grok-search skill. Installing the skill does not install the CLI:

npx skills add patrick-fu/grok-search-cli -g -s grok-search -a universal claude-code -y --full-depth

Authentication

Users authenticate with the official Grok Build CLI:

grok login

The search CLI treats Grok Build's credential store (${GROK_HOME:-$HOME/.grok}/auth.json) as read-only input. It never logs in, refreshes, rotates, copies, or rewrites credentials, and it never starts a login flow itself.

Missing, unreadable, insecure, malformed, locally expired, or provider-rejected credentials produce typed errors (exit 3). The error message directs the user to run grok login. An agent must request explicit permission before running grok login on a user's behalf; the search CLI only tells the user to do so.

Usage

grok-search web [common flags] [web flags] [query]
grok-search x   [common flags] [x flags]   [query]
grok-search help
grok-search version
grok-search update

help, version, and update

help, --help, and -h print human-readable usage text and exit 0. version and --version print grok-search <version> and exit 0. update writes human-readable status and replaces the current binary; it is not a search command and does not emit search JSON.

Query input: stdin or positional

Prefer piping arbitrary queries through stdin to avoid shell-escaping hazards:

echo "Find the official xAI documentation." | grok-search web

A single positional argument also works:

grok-search web "Find the official xAI documentation."

Rules (verified against the implementation):

  • If stdin is not a terminal, it is read first (up to 64 KiB).
  • Non-empty stdin and a positional query together is usage_error (exit 2).
  • Empty non-terminal stdin is treated as absent; the positional query is then used.
  • With a terminal stdin, exactly one positional query is required.
  • Invalid UTF-8, a query of only whitespace, or exceeding 64 KiB is usage_error.
  • For stdin only, one trailing LF (and an optional preceding CR) is removed; all other bytes are preserved. The preserved query is what is sent upstream.

web and x

web searches current public web information; x searches X posts. Each invocation performs exactly one search and emits exactly one JSON object.

Common options

Option Contract
--auth-file <path> Read credentials from this path instead of ${GROK_HOME:-$HOME/.grok}/auth.json; the same read-only checks apply.
--timeout <duration> Total deadline; default 90s, valid from 1s through 180s.
--max-output-tokens <n> Provider output bound; default 1024, valid from 128 through 4096.
--verbose Write sanitized, non-contractual diagnostics to stderr only.

--model

--model <id> overrides the default grok-4.5. The model ID is treated as opaque: valid UTF-8, 1–256 bytes, no control or whitespace characters. It is sent once and never silently swapped; the CLI never falls back to another model. The returned model is always the requested ID. An explicit empty value is usage_error.

Filters

Web filters (--allow-domain, --exclude-domain) and X filters (--allow-handle, --exclude-handle) are mutually exclusive within each set.

Surface Flag Limit
web repeatable --allow-domain <domain> / --exclude-domain <domain> 5 unique values
x repeatable --allow-handle <handle> / --exclude-handle <handle> 20 unique values
x --from <YYYY-MM-DD>, --to <YYYY-MM-DD> from must not be later than to

Domains are ASCII hostnames (no scheme, port, path, or wildcard), lowercased and deduplicated. Handles omit @ and contain no whitespace. Use filters only when the user's request requires them.

Output

Search commands write exactly one compact JSON object followed by a newline to stdout, on both success and expected failure. Diagnostics go only to stderr.

Success

{
  "schema_version": 1,
  "type": "web",
  "query": "Find the official xAI documentation.",
  "model": "grok-4.5",
  "provider_model": "grok-4.5-build",
  "answer": "The documentation is available at the cited URL.",
  "sources": [
    {"url": "https://docs.x.ai/", "title": "xAI Documentation"}
  ],
  "warnings": []
}
  • schema_version, type, query, model, answer, sources, and warnings are always present.
  • provider_model appears only when the provider reported a completed-response model that differs from the requested model. That is disclosure, not a client-side fallback.
  • sources are provider-supplied URL citations attached to the answer, not ranked search hits. They are deduplicated by exact URL in first-citation order; that order is not relevance rank. title is omitted when absent.
  • Agents should consume answer, sources, and warnings, and treat sources as citations rather than ranked results.

Warnings

warnings is always an array. A warning describes degraded evidence in an otherwise usable response — not an error. V1 uses a closed set:

Code Meaning
invalid_citations_ignored Some provider-supplied citations were in an unsupported shape and were ignored. The remaining answer is still valid.
missing_citations The answer has no supporting citations. The response succeeds with sources: [].

When both apply, they appear in the order shown. A response with no citations left after ignoring invalid ones is a success with sources: [] plus missing_citations.

Errors

Expected failures write a JSON error object and a non-zero exit status:

{
  "schema_version": 1,
  "error": {
    "code": "rate_limited",
    "message": "The provider rate-limited the search request.",
    "retryable": true,
    "http_status": 429,
    "retry_after_seconds": 30,
    "request_id": "safe-request-id"
  }
}

code and message are stable and client-owned. retryable says whether a caller may retry later; it does not mean the CLI already retried. http_status, retry_after_seconds, and request_id appear only when reliably observed and sanitized. The CLI never emits provider bodies or mutable provider messages on stdout.

Exit codes

Exit Meaning
0 Search success, help, version, or successful/no-op update.
2 Local usage or input-validation failure (usage_error for search commands).
3 Credential/authentication failure (missing, unreadable, insecure, invalid, expired, or rejected).
4 Transport, provider, compatibility, response, search, or update failure.
70 Sanitized unexpected internal failure.

Diagnostics (--verbose)

--verbose writes allowlisted, sanitized diagnostics to stderr only. It does not change stdout and does not affect the exit code. The diagnostics are a non-contractual debugging aid: a line carries only a phase name, elapsed time, a stable code, and narrow evidence such as HTTP status.

They never contain the query, answer, citations, request or response bodies, headers, paths containing a username, or any credential material. Do not parse stderr as part of the contract; rely on the stdout JSON and the exit code.

Verifying without network

Everything can be verified offline without calling the live xAI proxy. From a clone:

go test ./...
go build -o grok-search ./cmd/grok-search

You can also exercise the local command surface with no credential and no network. Point --auth-file at a missing path so the command fails closed at the auth step regardless of whether a real grok login exists:

./grok-search help                                              # exit 0
./grok-search version                                           # exit 0
echo "x" | ./grok-search web --auth-file /tmp/no-such-cred      # exit 3 (auth_missing)

Each line is fully offline: help and version never touch auth or network, and the web line fails at credential loading (exit 3) before any request is made. They contain no real credentials. update and the curl installer need GitHub Release HTTPS and are not part of these offline checks. A search that reaches the provider requires a valid grok login and is an explicit, user-risk manual action — not part of these offline checks. See the explicit live smoke procedure.

Security

Never commit or share ~/.grok/auth.json, OAuth tokens, callback URLs, API keys, or captured request headers. The CLI never prints, copies, or exposes credentials. See SECURITY.md.

License

MIT

About

Agent-friendly CLI for Grok web and X search using an existing Grok Build session

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages