Skip to content

feat: add Grok Build CLI as a built-in agent - #103

Open
Shxiao101 wants to merge 14 commits into
bcurts:mainfrom
Shxiao101:grok-build
Open

feat: add Grok Build CLI as a built-in agent#103
Shxiao101 wants to merge 14 commits into
bcurts:mainfrom
Shxiao101:grok-build

Conversation

@Shxiao101

Copy link
Copy Markdown
Contributor

Summary

Adds Grok Build (xAI's grok CLI) as a built-in agent, following the same pattern as the CodeBuddy / Copilot / Antigravity additions: config.toml entry, built-in wrapper defaults, brand avatar, identity mapping, README coverage, launchers for both platforms, and tests.

Grok is a config-format adapter on the existing settings_file inject path — not a new agent lifecycle. It reads MCP servers from the project's .grok/config.toml (native TOML, not JSON) and authenticates through bearer_token_env_var, so no live token is ever written to the config file.

Why tomlkit (new runtime dependency)

.grok/config.toml is a user-owned file that may already hold their other Grok settings, usually with comments. The adapter must merge an [mcp_servers.agentchattr] block into that file without damaging the rest:

  • stdlib tomllib (3.11+) is read-only — it can parse TOML but cannot serialize it, so it cannot perform the merge-and-write.
  • A hand-rolled writer (string splicing, or re-emitting a tomllib parse) would drop comments, reorder keys, or append a duplicate table when the file already contains an mcp_servers section.

tomlkit round-trips the document (comments, whitespace, and dotted/quoted table headers survive). The write path is defensive: invalid TOML is refused rather than treated as empty, a present-but-non-table mcp_servers is refused rather than replaced, the dump is re-parsed and validated before replacing the original, and the write goes through a unique temp file. It is imported at module scope in wrapper.py on every platform, so it is a global dependency in requirements.txt (documented in the README's dependency section).

What's included

  • config.toml[agents.grok] block with install commands for both platforms
  • wrapper.py_BUILTIN_DEFAULTS["grok"] (mcp_settings_format = "grok_toml"), _write_grok_mcp_toml merge helper, AGENTCHATTR_MCP_TOKEN env-var auth
  • static/chat.js — Grok avatar from the official favicon: self-clipped dark disc + light glyph, inline-sized to the avatar circle (no shared CSS changes; the disc intentionally covers the brand-color container — #e5e5e5 remains the pill/mention/name accent)
  • mcp_bridge.py — identity mapping + Grok color in the chat_set_hat color context
  • Launchers — windows/start_grok.bat / start_grok_yolo.bat (CRLF, PATH hardening for %USERPROFILE%\.grok\bin) and macos-linux/start_grok.sh / start_grok_yolo.sh (LF, 100755, PATH hardening for $GROK_BIN_DIR / ~/.grok/bin in the 5403338 style, pre-flight check with the official install.sh hint)
  • README — agent lists, launcher lists, @grok mentions in both quickstarts, Grok adapter notes, Manual MCP registration entry, dependency note
  • Tests — tests/test_wrapper_mcp_config.py (+331) and tests/test_identity_contract.py (+89) covering merge semantics, invalid-TOML refusal, non-table mcp_servers refusal, and temp-file handling

Testing

  • Full suite: python -m unittest discover -s tests100 tests, all green
  • git diff --check clean; .bat launchers are CRLF, .sh launchers are LF with the executable bit set
  • Verified https://x.ai/cli/install.sh (bash installer, darwin/linux targets, BIN_DIR="${GROK_BIN_DIR:-$HOME/.grok/bin}") and the PowerShell installer for the launcher hints
  • Developed and verified on Windows; the Mac/Linux launchers mirror start_qwen.sh / start_antigravity.sh, and the grok_toml inject lives in the shared wrapper path, but no live macOS/Linux run was performed

Register grok as a first-class CLI agent with native TOML MCP inject (project .grok/config.toml, HTTP + bearer), Windows launchers that find %USERPROFILE%\.grok\bin, identity mapping to base grok, official grok.com favicon avatar, and tests for the launch/inject path.
Stop silently trusting Grok project folders. Keep the instance token in AGENTCHATTR_MCP_TOKEN instead of writing it into project .grok/config.toml. Use an explicit grok_toml inject mode so generic settings_file stays format-neutral. Document that Grok launchers are Windows-only.
Merge mcp_servers.agentchattr via tomlkit so spaced/quoted table headers replace instead of duplicating. Invalid existing files raise instead of being overwritten. Trust coverage is a launch-path behavior check; remove the Unix-launcher absence test.
Avoid a shared config.toml.tmp so concurrent Grok instances cannot FileNotFoundError on replace. Drop the leftover deleted-trust-helper call from the launch behavior test.
Reuse the existing settings_file path for Grok. mcp_settings_format is json by default and grok_toml for Grok; unknown formats error. Instance tokens stay in AGENTCHATTR_MCP_TOKEN. Document Windows-only adapter limits.
Reject explicit empty/false format instead of coercing to JSON. Barrier the concurrent unique-temp test so a shared config.toml.tmp fails reliably.
Drop the extra grok.svg request and .avatar-fill CSS. Keep tomlkit in requirements.txt because grok_toml merge lives in shared wrapper.py.
If mcp_servers is present but not a TOML table, raise ValueError and leave the file unchanged. Only create a table when the field is missing.
Every built-in agent ships both launchers; Grok was Windows-only. The
wrapper's grok_toml inject already works under the Mac/Linux tmux path,
so add start_grok.sh / start_grok_yolo.sh (mirroring start_qwen.sh, with
a grok pre-flight check) and drop the Windows-only wording from
README.md and config.toml. Also document Grok in the Manual MCP
registration section and add its color to the chat_set_hat context.
Mirror 5403338 (start_antigravity.sh) for Grok: the installer puts the
binary in $GROK_BIN_DIR (default ~/.grok/bin) and wires it into PATH via
the shell profile, so a launcher run from a non-login shell — or one
opened before the profile was re-sourced — reports 'grok not found'
even though the CLI is installed. Best-effort prepend the resolved
install dir when grok actually lives there, skipping a dir already on
PATH; the pre-flight check still catches a truly missing CLI.
The Grok avatar filled the whole circle with the favicon's dark field,
which needed overflow: hidden on .avatar and .agent-name-avatar — the
only global-rendering change in the branch. Kilo (#f7f677, the same
light-color problem) needs no container change: a static dark glyph on
the brand-colored circle. Give Grok the same treatment: drop the
favicon's background tile, flip the glyph paths to #050505, remove the
full-bleed inline style so .avatar svg sizing applies, and revert both
overflow: hidden additions. Cache-bust chat.js and style.css.
Follow-up to the kilo-style revert: on the dark UI, grok's #e5e5e5
brand circle reads as a plain white avatar, and the bare glyph rendered
~22% small (it spans 400/512 of the favicon viewBox). Draw the favicon
properly instead: the SVG carries its own #050505 disc (r=256 inscribed
in the viewBox, square corners transparent) sized inline to fill the
avatar circle, so the shared overflow: hidden is still not needed. The
glyph group scales 0.84 to keep the slash tips (283 units from center
untransformed) inside the disc. Cache-bust chat.js.
…olor

style.css is byte-identical to main again after the overflow revert, so
?v=255 was diff noise — back to main's v=251; chat.js 268 -> 273 is the
only legitimate bump left. Also make the Grok avatar comment state that
the dark disc intentionally paints over the agent-color container:
#e5e5e5 remains visible only in the sender name, pill, and @mentions.
# Conflicts:
#	requirements.txt
#	static/index.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant