feat(clink): add Grok Build and OpenCode CLI clients - #464
Conversation
Enable clink to spawn Grok Build and OpenCode headless agents with JSON parsers, role presets, and tests for prompt delivery and recovery.
Document local and uvx registration for Grok Build, and ship a config.toml example with recommended timeouts.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 34df1f73b4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| command.extend(self.client.config_args) | ||
|
|
||
| if self._pending_prompt_file: | ||
| command.extend(["--prompt-file", self._pending_prompt_file]) |
There was a problem hiding this comment.
Use Grok's supported headless prompt flag
When cli_name='grok', every request is launched as grok ... --prompt-file <tmp> while stdin is empty, but xAI's Grok Build Headless & Scripting docs (https://docs.x.ai/build/cli/headless-scripting) document headless prompts via grok -p "Your prompt here" / -p, --single <PROMPT> and list no --prompt-file flag. In that environment the new Grok integration exits on an unknown flag instead of running the prompt, so clink's advertised Grok support is unusable until the prompt is supplied through the supported headless interface.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Code Review
This pull request introduces support for two new AI CLI agents, Grok Build (grok) and OpenCode (opencode), by updating the documentation, registering the agents, defining their CLI configurations, and adding a JSON parser for Grok. However, several critical issues were identified: the implementation files clink/agents/grok.py and clink/parsers/opencode.py are missing from the PR, which will cause immediate import and test failures. Additionally, type annotations should be added for the client parameter in OpenCodeAgent, and request-specific state variables should be refactored to prevent concurrency issues during asynchronous execution.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| from .claude import ClaudeAgent | ||
| from .codex import CodexAgent | ||
| from .gemini import GeminiAgent | ||
| from .grok import GrokAgent |
| from clink.parsers.base import ParserError | ||
| from clink.parsers.codex import CodexJSONLParser | ||
| from clink.parsers.grok import GrokJSONParser | ||
| from clink.parsers.opencode import OpenCodeJSONLParser |
| from collections.abc import Sequence | ||
| from pathlib import Path | ||
|
|
||
| from clink.models import ResolvedCLIRole |
| def __init__(self, client): | ||
| super().__init__(client) |
| self._pending_message: str | None = None | ||
| self._pending_prompt_file: str | None = None |
There was a problem hiding this comment.
Storing request-specific state (_pending_message and _pending_prompt_file) as instance variables makes the agent stateful and unsafe for concurrent execution. If multiple asynchronous tasks call run concurrently on the same agent instance, they will overwrite each other's state.
Consider using contextvars.ContextVar to store these values safely across asynchronous tasks, or refactoring the base class to allow passing the prompt directly to _build_command.
Summary
grok) and OpenCode (opencode) so PAL can spawn them as external CLI agentsexamples/grok_config_example.tomlClink clients
grokgrok --prompt-file <tmp> --output-format json --always-approvegrok_jsonopencodeopencode run --format json --auto <message>opencode_jsonlGrok headless does not read stdin (uses
--prompt-file). OpenCode takes the message as a positional arg; large prompts are attached via--file.Test plan
pytest tests/test_clink_parsers.py tests/test_clink_grok_agent.py tests/test_clink_opencode_agent.py tests/test_clink_tool.py -qgrok/opencodeCLIs and run a liveclinksmoke call for eachdefault,planner,codereviewer) load fromconf/cli_clients/