#### CLI

# Headless & Scripting

## Headless mode

Use headless mode for scripts, bots, or other machine-friendly tasks.

```bash customLanguage="bash"
grok -p "Your prompt here"
```

Common flags:

| Flag                    | What it does                                              |
| ----------------------- | --------------------------------------------------------- |
| `-p, --single <PROMPT>` | Send one prompt                                           |
| `-m, --model <MODEL>`   | Choose a model                                            |
| `-s, --session-id <ID>` | Create or resume a named headless session                 |
| `-r, --resume <ID>`     | Resume an existing session                                |
| `-c, --continue`        | Continue the most recent session in the current directory |
| `--cwd <PATH>`          | Set the working directory                                 |
| `--output-format <FMT>` | Choose `plain`, `json`, or `streaming-json`               |
| `--always-approve`      | Auto-approve tool executions                              |

## Output formats

* `plain`: human-readable text
* `json`: one JSON object at the end
* `streaming-json`: newline-delimited JSON events

```bash customLanguage="bash"
grok -p "List TODO comments" --output-format json
grok -p "Explain the architecture" --output-format streaming-json
```

Streaming JSON emits incremental events as they arrive.

## ACP

Use ACP when you want IDE or tool integration rather than a terminal session.

```bash customLanguage="bash"
grok agent stdio
```

This runs Grok as an ACP agent over JSON-RPC on stdin/stdout. The example below assumes `grok` is already authenticated locally, or `GROK_CODE_XAI_API_KEY` is set. `session/prompt` returns completion metadata; the assistant text itself arrives as `session/update` chunks.

```javascript customLanguage="javascriptWithoutSDK"
import { spawn } from "node:child_process";
import readline from "node:readline";
import process from "node:process";

const proc = spawn("grok", ["agent", "stdio"], { stdio: ["pipe", "pipe", "pipe"] });
const rl = readline.createInterface({ input: proc.stdout });
const pending = new Map();
let nextId = 1;
let text = "";

proc.stderr.on("data", chunk => process.stderr.write(chunk));

rl.on("line", line => {
  const message = JSON.parse(line);

  if (message.method === "session/update") {
    const update = message.params?.update;
    if (update?.sessionUpdate === "agent_message_chunk" && update.content?.text) {
      text += update.content.text;
    }
    return;
  }

  const pendingRequest = pending.get(message.id);
  if (!pendingRequest) return;

  pending.delete(message.id);
  if (message.error) {
    pendingRequest.reject(new Error(message.error.message ?? JSON.stringify(message.error)));
  } else {
    pendingRequest.resolve(message.result ?? {});
  }
});

function request(method, params, timeoutMs = 30000) {
  const id = nextId++;

  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      pending.delete(id);
      reject(new Error(`${method} timed out`));
    }, timeoutMs);

    pending.set(id, {
      resolve(result) {
        clearTimeout(timer);
        resolve(result);
      },
      reject(error) {
        clearTimeout(timer);
        reject(error);
      },
    });

    proc.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
  });
}

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

try {
  const init = await request("initialize", {
    protocolVersion: "1",
    clientCapabilities: {
      fs: { readTextFile: true, writeTextFile: true },
      terminal: true,
    },
  });

  const authMethods = new Set((init.authMethods ?? []).map(method => method.id));
  const methodId =
    process.env.GROK_CODE_XAI_API_KEY && authMethods.has("xai.api_key")
      ? "xai.api_key"
      : authMethods.has("cached_token")
        ? "cached_token"
        : null;

  if (!methodId) {
    throw new Error("Run `grok login` first, or set GROK_CODE_XAI_API_KEY.");
  }

  await request("authenticate", { methodId, meta: { headless: true } });

  const { sessionId } = await request("session/new", {
    cwd: process.cwd(),
    mcpServers: [],
  });

  const prompt = await request("session/prompt", {
    sessionId,
    prompt: [{ type: "text", text: "Say hello in one short sentence." }],
  });

  let lastLength = -1;
  let stableChecks = 0;
  while (stableChecks < 2) {
    await sleep(150);
    if (text.length === lastLength) {
      stableChecks += 1;
    } else {
      lastLength = text.length;
      stableChecks = 0;
    }
  }

  console.log(text.trim() || `No text returned (stopReason=${prompt.stopReason})`);
} finally {
  rl.close();
  proc.kill();
}
```
