hermes-grok-acp
Use the logged-in grok CLI (xAI Grok subscription) as a model provider inside Hermes Agent. Grok runs as an ACP subprocess. Hermes keeps its normal provider interface, tool loop, and approvals.
This follows the published hermes-kiro-provider plugin: a ProviderProfile with auth_type="external_process" whose client subclasses Hermes' in-tree CopilotACPClient. Session lifecycle, streaming, permission cancellation, and the fs/read_text_file / fs/write_text_file bridge (including agent/file_safety.py) are inherited.
The original build spec is preserved in docs/original-spec.md. What the live CLI actually did is in docs/phase-1-findings.md.
Prerequisites
- Hermes Agent with the external-process provider seam (
CopilotACPClient) grokonPATH, logged in (grok modelssaysYou are logged in)
Verified against grok 1.0.41 (grok agent --no-leader stdio, ACP protocol version 1).
Install
Drop the repo in as a model-provider plugin:
git clone https://github.com/nicolasdmolina/hermes-grok-acp.git
mkdir -p "${HERMES_HOME:-$HOME/.hermes}/plugins/model-providers"
cp -a hermes-grok-acp "${HERMES_HOME:-$HOME/.hermes}/plugins/model-providers/grok-acp"
The next Hermes process registers the grok-acp provider. Auth is the grok CLI's own login (~/.grok, or GROK_HOME). This plugin does not take an API key. hermes model asks grok models whether that login exists and, on a terminal, runs grok login when it does not. The model list is the same short ACP session/new probe as fetch_models.
model:
provider: grok-acp
default: grok-4.7
Or as a fallback:
fallback_providers:
- provider: grok-acp
model: grok-4.7
hermes -z "Reply with the single word pong." --provider grok-acp -m grok-4.7
Provider name: grok-acp. Aliases: xai-grok-acp, grok-acp-agent.
Configuration
| Env var | Purpose | Default |
|---|---|---|
HERMES_GROK_ACP_COMMAND |
Path to the grok binary | grok |
GROK_CLI_PATH |
Older alias for the same | — |
HERMES_GROK_ACP_ARGS |
Full argv, shlex-split, not a shell | agent --no-leader stdio |
--model and --always-approve belong on grok agent, before stdio. This plugin does not pass either. The model is selected after session/new with session/set_config_option (value is a string). --no-leader keeps the request off a shared Grok leader. --always-approve did not change stdio permission behavior on grok 1.0.41; see the findings note.
HERMES_GROK_ACP_ARGS replaces the whole argv. Do not include --acp (that flag is Copilot's, and grok rejects it). A broken quote raises a Grok error naming HERMES_GROK_ACP_ARGS instead of an uncaught parse error. Do not rebuild this argv just to set reasoning effort.
Reasoning effort
On grok 1.0.41, reasoning effort is a session config option (reasoning_effort: xhigh, high, medium, low), same channel as the model. After session/new, the client sends session/set_config_option with a string value. Spawn-time --reasoning-effort only sets the session's starting value; a Hermes request overrides it without respawning.
Hermes already decides the effort: agent.reasoning_effort globally, and agent.reasoning_overrides per model. This provider maps that onto the session. For example, to run the grok-acp fallback at high while other providers stay on the global level:
agent:
reasoning_effort: medium
reasoning_overrides:
grok-4.7: high
Grok has no none level. An explicit disable leaves the session default alone. ultra and max clamp down to xhigh.
How tool calls work
Hermes tools are sent in the prompt as OpenAI function schemas. The model emits <tool_call>{...}</tool_call> text, and the inherited bridge turns those blocks back into OpenAI tool calls. Hermes then runs the tools.
Grok also has its own tools. File reads and writes that arrive as fs/read_text_file / fs/write_text_file go through Hermes' file-safety gates (cwd jail, credential reads, write denylist, approval-gated paths fail closed). Grok's shell tool runs inside the grok process. On 1.0.41 it did not emit session/request_permission, and --deny / --disallowed-tools on grok agent stdio did not stop it. Those commands are Grok's own, under the account that owns the CLI, not a Hermes terminal approval. The child environment has Hermes provider credentials removed before spawn, so that shell cannot read OPENAI_API_KEY, XAI_API_KEY, and the other names Hermes already treats as provider secrets. Grok's own login file is unchanged.
Development
Unit tests need a Hermes checkout (default ~/.hermes/hermes-agent) and that checkout's virtualenv:
~/.hermes/hermes-agent/venv/bin/python -m pytest tests -q -m "not integration"
~/.hermes/hermes-agent/venv/bin/python -m pytest tests -q
hermes plugins validate .
The integration tests spawn the real CLI. They copy the login file into a scratch GROK_HOME and delete it afterward. Set GROK_ACP_INTEGRATION=0 to skip them.
License
MIT