skip to content
$worker

grok

v0.1.5

xAI Grok CLI as an iii worker; grok::run/start/stop/status/sessions::list spawn the grok CLI for headless turns, mirror raw streaming-json events onto grok::events, and stream AgentEvent frames onto agent::events.

iiiverified
5 installs1 in 7d0 today
install
$iii worker add grok@next
binarylicense: Apache-2.0coding-agentgrokxaicliheadless
  • macOS: arm64 · x64
  • Linux: arm64 · armv7 · x64
  • Windows: arm64 · x64 · x86

exact versions are immutable; binary and bundle artifacts are digest-pinned.

agent-ready brief for v0.1.5
install + config + dependencies + readme + api reference, all in one place. fetch as agent-context.md for an llm to consume.
the same content rendered as discrete blocks below is exposed as a single markdown document at /workers/grok.md?version=next. paste it into an llm prompt or pipe it through curl from a worker.

install

install
$iii worker add grok@0.1.5

configuration

iii-config.yaml
- defaults:
    always_approve: true
    cwd:
    model:
  events_stream: agent::events
  grok_executable:
  iii_context: true
  raw_events_stream: grok::events

dependencies

no dependencies for v0.1.5

readme

README.md

grok

The xAI Grok CLI as an iii worker: the Grok agent exposed as functions and streams on the iii bus, nothing else. The worker spawns the same grok binary the user runs in their terminal, with the same XAI_API_KEY, the same filesystem, and the same working directory. grok::run executes one headless turn (grok --single --output-format streaming-json) and returns the result; the raw Grok events mirror verbatim onto the grok::events stream, and a translated AgentEvent view lands on agent::events, so the iii console and any sibling worker observe a Grok run exactly like a native harness turn.

Install

iii worker add grok

Requires the Grok CLI on the host and XAI_API_KEY in the worker environment. See docs.x.ai for CLI installation and authentication.

Skills

Install the grok agent skill for Claude Code, Cursor, and 30+ other agents:

npx skills add iii-hq/workers --skill grok

Quickstart

From zero to a Grok turn over the bus:

curl -fsSL https://install.iii.dev/iii/main/install.sh | sh
iii worker add grok
iii   # starts the engine + worker

Then talk to it like any other function: from iii trigger grok::run, or from any SDK:

import { registerWorker } from 'iii-sdk';

const iii = registerWorker('ws://127.0.0.1:49134', { workerName: 'demo' });

const res = await iii.trigger({
  function_id: 'grok::run',
  payload: {
    prompt: 'Add a /health endpoint to server.ts and run the tests',
    cwd: '/path/to/repo',
  },
  timeout_ms: 600_000,
});
// { session_id, grok_thread_id, result, stop_reason, num_turns }

Or straight from the terminal with the iii trigger CLI:

# one full turn (raise the timeout; the default 30s is too short for agent turns)
iii trigger grok::run --timeout-ms 600000 \
  --json '{"prompt":"add a /health endpoint and run the tests","cwd":"/path/to/repo"}'

# quick reads use key=value syntax
iii trigger grok::sessions::list
iii trigger grok::status session_id=<session_id>

# background turn + control
iii trigger grok::start --json '{"prompt":"...","cwd":"/path/to/repo"}'
iii trigger grok::stop session_id=<session_id>

# ask the running engine for a function's description and parameter table
iii trigger grok::run --help

A turn from the CLI, and the published request schema served by --help:

iii trigger grok::run returning the result over the bus

iii trigger grok::run --help printing the typed request schema as a parameter table

Call grok::run again with the returned session_id to continue the same conversation: the worker maps iii session ids to Grok session ids in engine state and resumes automatically (sessions persist in ~/.grok/sessions).

Two ids come back from every run. session_id is the iii session id: the key for grok::status, grok::stop, resume, and the stream group. grok_thread_id is Grok's own session id (what the worker passes to --resume on the next turn) — returned for reference, not a lookup key.

Functions

Function Purpose
grok::run Run one turn, wait, return the final result
grok::start Fire-and-forget turn; progress arrives on the streams
grok::stop Interrupt a live run
grok::status Session state, live flag, turn count
grok::sessions::list All sessions this worker has run

grok::run accepts either a bare prompt string or a messages array ([{ role: 'user', content: [{ type: 'text', text }] }]) — the same input contract as the claude-code worker and run::start_and_wait, so the acp worker drives Grok with --brain-fn grok::run — plus model, cwd, always_approve, and iii_context.

Raw events

Every line Grok emits on its --output-format streaming-json stream is mirrored verbatim onto the grok::events stream, group_id = session_id. Consumers that want the exact Grok wire format read grok::events; consumers that want harness-shaped frames read agent::events. Same turn, two views.

The streaming-json stream (captured from Grok CLI 0.2.77) is delta-based: assistant text arrives as {"type":"text","data":""} lines, the turn closes with {"type":"end","stopReason","sessionId","requestId"}, and failures arrive as {"type":"error","message"}. The worker accumulates the text deltas and emits one message_complete frame on agent::events at end.

Note: the Grok CLI streaming-json schema is not formally published, so the typed model in src/grok/events_types.rs is lenient — unrecognized event types pass through verbatim on grok::events and are skipped on the translated stream rather than failing the turn. Headless output carries no token usage and does not break out tool-call events today.

Configuration

engine_url: ws://127.0.0.1:49134

defaults:
  model: ""             # empty = Grok CLI default (e.g. grok-build-0.1)
  cwd: ""               # default working directory for runs
  always_approve: true  # auto-approve tool/command execution on headless turns

events_stream: agent::events     # translated AgentEvent frames
raw_events_stream: grok::events  # verbatim Grok streaming-json events
grok_executable: ""              # path to the grok CLI; empty = PATH resolution

Auth is the Grok CLI's own: the worker inherits XAI_API_KEY from its environment. always_approve keeps headless turns from blocking on an interactive approval prompt; set it to false to let the CLI's approval policy gate tool execution.

The agent on the bus

By default every turn carries the iii runtime context, prepended to the prompt on the first turn of a session: the same engine-grounded rules as the harness identity prompts, retargeted to the iii CLI the agent reaches through its shell. The agent discovers capabilities from the live engine instead of memory — iii trigger engine::functions::list to find function ids, iii trigger --help as the contract before every first call, the registry flow (directory::registry::workers::list/info, worker::add) when nothing registered fits — plus the calling rules and error-handling discipline that go with them. Local file edits stay on Grok's native tools; backend actions go through registered functions.

# the agent answers this by querying the live engine itself
iii trigger grok::run --timeout-ms 300000 \
  --json '{"prompt":"List every worker connected to this engine and what each one does.","cwd":"/tmp"}'

With the context on, Grok reaches for iii trigger engine::workers::list itself and reports the live mesh — every worker and what it does — instead of guessing from ps and config files:

Grok answering a live-system question by querying the engine through the iii CLI

The context is injected once at the start of a session; resumed turns rely on the existing session history. Turn it off per call with "iii_context": false or globally in config.yaml.

Observability

Every grok::run is an ordinary traced invocation on the engine: the trace carries the full input payload and the output (result, stop reason) as span events, with per-function p50/p95/p99 in the console's trace explorer — no extra instrumentation in the worker. Headless Grok output carries no token usage today, so the worker does not report it.

How it maps

Grok iii
one headless grok --single turn grok::run invocation
every streaming-json line, verbatim grok::events stream frame
accumulated text deltas at end message_complete frame on agent::events
turn end turn_end + agent_end frames, function return value
end.sessionId--resume next turn engine state scope grok_sessions, keyed by iii session_id
extra capability another iii worker on the bus (shell, database, storage, ...)

api reference (json)

agent-api-reference.json
{
  "functions": [
    {
      "description": "Internal: reload grok configuration when it changes.",
      "metadata": {},
      "name": "grok::on-config-change",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Run one Grok turn and wait for the result. Accepts `prompt` or a `messages` array; streams raw Grok events onto grok::events, AgentEvent frames onto agent::events, and returns {session_id, result, stop_reason}.",
      "metadata": {},
      "name": "grok::run",
      "request_schema": {
        "definitions": {
          "Message": {
            "properties": {
              "content": {
                "description": "Either a plain string or an array of content blocks."
              },
              "role": {
                "type": "string"
              }
            },
            "required": [
              "content",
              "role"
            ],
            "type": "object"
          }
        },
        "properties": {
          "always_approve": {
            "default": null,
            "description": "Auto-approve tool/command execution for this headless turn (--always-approve).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "cwd": {
            "default": null,
            "description": "Working directory the turn runs in (--cwd).",
            "type": [
              "string",
              "null"
            ]
          },
          "iii_context": {
            "default": null,
            "description": "Inject the iii runtime discovery prompt as the leading instructions (default true via config).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "messages": {
            "description": "Alternative to prompt: role/content messages; the last user entry becomes the prompt.",
            "items": {
              "$ref": "#/definitions/Message"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "model": {
            "default": null,
            "description": "Model id; empty = Grok default (e.g. grok-build-0.1).",
            "type": [
              "string",
              "null"
            ]
          },
          "prompt": {
            "default": null,
            "description": "The user prompt for this turn.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "default": null,
            "description": "iii session id; reuse to resume the same Grok thread.",
            "type": [
              "string",
              "null"
            ]
          },
          "timeout_ms": {
            "default": null,
            "description": "Reserved for callers; not forwarded.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "title": "RunRequest",
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "busy": {
            "type": "boolean"
          },
          "grok_thread_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_error": {
            "type": "boolean"
          },
          "num_turns": {
            "type": "integer"
          },
          "reason": {
            "type": "string"
          },
          "result": {
            "type": "string"
          },
          "session_id": {
            "type": "string"
          },
          "stop_reason": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "List every Grok session this worker has run.",
      "metadata": {},
      "name": "grok::sessions::list",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "sessions": {
            "items": {
              "type": "object"
            },
            "type": "array"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Start a Grok turn and return immediately; watch grok::events / agent::events (group_id = session_id) for progress and turn_end.",
      "metadata": {},
      "name": "grok::start",
      "request_schema": {
        "definitions": {
          "Message": {
            "properties": {
              "content": {
                "description": "Either a plain string or an array of content blocks."
              },
              "role": {
                "type": "string"
              }
            },
            "required": [
              "content",
              "role"
            ],
            "type": "object"
          }
        },
        "properties": {
          "always_approve": {
            "default": null,
            "description": "Auto-approve tool/command execution for this headless turn (--always-approve).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "cwd": {
            "default": null,
            "description": "Working directory the turn runs in (--cwd).",
            "type": [
              "string",
              "null"
            ]
          },
          "iii_context": {
            "default": null,
            "description": "Inject the iii runtime discovery prompt as the leading instructions (default true via config).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "messages": {
            "description": "Alternative to prompt: role/content messages; the last user entry becomes the prompt.",
            "items": {
              "$ref": "#/definitions/Message"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "model": {
            "default": null,
            "description": "Model id; empty = Grok default (e.g. grok-build-0.1).",
            "type": [
              "string",
              "null"
            ]
          },
          "prompt": {
            "default": null,
            "description": "The user prompt for this turn.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "default": null,
            "description": "iii session id; reuse to resume the same Grok thread.",
            "type": [
              "string",
              "null"
            ]
          },
          "timeout_ms": {
            "default": null,
            "description": "Reserved for callers; not forwarded.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "title": "RunRequest",
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "session_id": {
            "type": "string"
          },
          "started": {
            "type": "boolean"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Point-in-time status of a Grok session.",
      "metadata": {},
      "name": "grok::status",
      "request_schema": {
        "properties": {
          "session_id": {
            "description": "iii session id returned by grok::run / grok::start.",
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "SessionIdRequest",
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "live": {
            "type": "boolean"
          },
          "record": {
            "type": [
              "object",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Interrupt a live Grok run for a session.",
      "metadata": {},
      "name": "grok::stop",
      "request_schema": {
        "properties": {
          "session_id": {
            "description": "iii session id returned by grok::run / grok::start.",
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "SessionIdRequest",
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "stopped": {
            "type": "boolean"
          }
        },
        "type": "object"
      }
    }
  ],
  "triggers": []
}