Skip to content

Add Grok CLI agent support (Beta) - #1190

Merged
pedramamini merged 13 commits into
RunMaestro:rcfrom
ksylvan:support-grok
Jul 15, 2026
Merged

Add Grok CLI agent support (Beta)#1190
pedramamini merged 13 commits into
RunMaestro:rcfrom
ksylvan:support-grok

Conversation

@ksylvan

@ksylvan ksylvan commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Add Grok CLI agent support (Beta)

Summary

Adds full Grok CLI (grok) support as a Beta agent in Maestro. Integration covers agent definition and capabilities, streaming-json output parsing, session storage (local + SSH), model discovery, error classification, CLI/desktop spawn composition, tab naming, and UI (picker, icon, display names). Behavior is verified against grok v0.2.93 fixtures.

Files Changed

Documentation

  • AGENT_SUPPORT.md — Full Grok CLI section (binary, flags, events, limitations, command patterns).
  • CLAUDE-AGENTS.md / CLAUDE.md — Grok listed as Beta with capability notes.
  • docs/agent-guides/AGENT-INFRA.mdgrok added to agent ID examples.

Shared / agent registry

  • src/shared/agentIds.tsgrok in AGENT_IDS.
  • src/shared/agentMetadata.ts — Display name Grok CLI; added to BETA_AGENTS.
  • src/shared/agentConstants.ts — Default context window 500000 (grok-4.5).

Agent definition & detection

  • src/main/agents/definitions.ts — Full definition: batch (-p), YOLO (--always-approve), read-only (--permission-mode plan), resume, cwd, model (-m), reasoning effort, config options.
  • src/main/agents/capabilities.ts — Capabilities (resume, read-only, session storage, streaming, thinking, batch; no usage/cost/image/tools on stream).
  • src/main/agents/detector.ts — Model discovery from ~/.grok/models_cache.json, fallback to grok models.

Parsers & errors

  • src/main/parsers/grok-output-parser.ts (new) — Parses thought / text / end / error JSONL events.
  • src/main/parsers/error-patterns.ts — Grok patterns (auth, rate limit, context, network, bad model, session not found).
  • src/main/parsers/index.ts, parser-factory.ts — Register GrokOutputParser.

Session storage

  • src/main/storage/grok-session-storage.ts (new) — Reads ~/.grok/sessions/<percent-encoded-cwd>/<uuid>/ (summary.json + chat_history.jsonl); local + SSH; project filtering; tool_result merge; no message-pair delete.
  • src/main/storage/index.ts — Register storage.

Spawn / response handling

  • src/cli/services/agent-spawner.ts — Accumulate non-reasoning partial text deltas when the terminal result has no text (Grok’s end event).
  • src/main/ipc/handlers/tabNaming.ts — Ignore isReasoning text when extracting tab names so thought deltas don’t pollute names.

UI

  • src/renderer/components/NewInstanceModal/types.tsgrok in SUPPORTED_AGENTS.
  • src/renderer/constants/agentIcons.ts — Icon ✖️.
  • src/renderer/components/UsageDashboard/autoRunTableUtils.ts — Display name Grok CLI.

Tests (new/updated)

  • Parser, session storage, error patterns, definitions, detector, agent-args, agent-spawner, tab naming, AgentPickerGrid, agentIcons, parsers index.

Code Changes

Agent definition (spawn flags)

Batch/YOLO use the same boolean flag so clap never sees a repeated --permission-mode:

batchModeArgs: ['--always-approve'],
yoloModeArgs: ['--always-approve'],
readOnlyArgs: ['--permission-mode', 'plan'],
jsonOutputArgs: ['--output-format', 'streaming-json'],
promptArgs: (prompt) => ['-p', prompt],
resumeArgs: (sessionId) => ['--resume', sessionId],

Typical invocation:

grok --cwd /path --always-approve --output-format streaming-json -p "prompt"
# resume
grok ... --resume <session-id> -p "continue"
# read-only
grok ... --permission-mode plan -p "prompt"   # no --always-approve

Output parser

Maps Grok’s four stream events:

Grok event Maestro event
thought + data text partial, isReasoning: true
text + data text partial
end + sessionId result (session ID only; no usage/cost)
error + message error

No tool events on stdout; no init event; session ID only on end.

Session storage

  • Layout: ~/.grok/sessions/<encodeURIComponent(cwd)>/<session-uuid>/
  • Filters by cwd folder before opening files
  • Strips <user_query> wrappers; skips synthetic/<user_info> records
  • Merges tool_result into prior assistant tool_calls by id
  • Token counts reported as 0 (not present in transcripts)
  • macOS /private/var/var path normalization for project match

CLI response accumulation

if (event.type === 'text' && event.isPartial && !event.isReasoning && event.text) {
  streamedText += event.text;
}
// on success:
response: result || streamedText || undefined

Tab naming

} else if (event.type === 'text' && !event.isReasoning) {
  assistantText += event.text;
}

Reason for Changes

Enable Maestro users to run xAI Grok CLI alongside existing agents with the same product surface: batch runs, resume, read-only/plan mode, model + reasoning-effort config, thinking panel, session history (local/SSH), and structured error recovery. Implementation follows established patterns (Copilot-style session dirs, Codex-like batch-only posture) while handling Grok-specific stream and clap constraints.

Impact of Changes

  • New Beta agent selectable in the UI when grok is installed.
  • No usage/cost widgets for Grok until the stream exposes them.
  • No live tool display from stdout (tools only in on-disk session files; history view can show tools after the fact).
  • Batch-only (no interactive PTY), same as Codex.
  • No image input.
  • Shared JSONL spawn path now correctly returns answers built only from text deltas.
  • Tab naming no longer mixes reasoning into generated names for Grok (and other reasoning streams).
  • Parser registry count: 8 → 9.

Test Plan

  • Unit: GrokOutputParser (deltas, end/sessionId, errors, exit/stderr resume failures).
  • Unit: GrokSessionStorage (list/filter, metadata, pagination, SSH, oversized/malformed, never-prompted).
  • Unit: error patterns (session_not_found vs informational restore line; bad model).
  • Unit: definitions (batch/yolo/readOnly args; model + reasoning options).
  • Unit: detector (cache + grok models fallback + empty).
  • Unit: buildAgentArgs desktop composition (unique flags; read-only strips approve; yolo dedupe).
  • Unit: CLI spawnAgent (text accumulation, read-only, resume, stream error).
  • Unit: tab naming ignores thought deltas.
  • Unit: AgentPickerGrid treats grok as supported; dedicated icon.
  • Manual: install grok v0.2.93+, run batch turn, resume, plan mode, model switch, bad model / bad resume errors.
  • Manual: open session history for a project with existing ~/.grok/sessions data (local and SSH if available).

Additional Notes

  • Marked Beta via BETA_AGENTS.
  • batchModeArgs === yoloModeArgs === ['--always-approve'] is intentional: clap rejects repeated --permission-mode, and boolean flags dedupe cleanly when yolo + batch both apply.
  • noToolsArgs intentionally omitted: no reliable all-tools-off flag on v0.2.93.
  • Auth/rate-limit patterns are multi-token only (no bare 401/429) until real unauthenticated/rate-limit log strings are captured; bad-model and bad-resume patterns are fixture-verified.
  • StdoutHandler thinking-chunk gate (intentional): agents that split thought vs answer (Grok, Codex, Claude, OpenCode) only emit thinking-chunk for isReasoning partials so Grok answer text does not flood the thinking panel. Factory Droid keeps the pre-Grok behavior of forwarding all non-reasoning partials to the thinking panel (no live regression). Copilot still never uses thinking-chunk.
  • Wizard discovery intentionally uses --always-approve + --max-turns 8 + --no-subagents (not plan mode), shared via GROK_WIZARD_DISCOVERY_ARGS. Residual write risk under the turn budget is documented in AGENT_SUPPORT.md.
  • History/transcripts are not a scrubbed vault (same OS-user model as Claude/Codex).
  • Potential follow-ups: live tool UI if Grok emits tool events; usage/cost if added to stream; interactive PTY; image input if CLI gains it; tool allowlist for wizard if CLI adds one.

Summary by CodeRabbit

  • New Features
    • Added beta Grok CLI agent support, including streaming JSON output, session resume, read-only/plan mode, and auto-approval behaviors.
    • Enabled Grok model discovery/configuration and Grok session browsing with local and remote transcript history.
    • Added Grok to UI metadata (display name, beta status, icon) and set its default context window.
  • Bug Fixes
    • Improved streamed text assembly and ensured reasoning fragments don’t affect tab naming.
    • Refined SSH auth-expired guidance for Grok.
  • Documentation
    • Updated Grok CLI docs and agent support tables with flags, behaviors, and known limitations.
  • Tests
    • Added extensive Grok coverage for parsing, session storage, model discovery, and error matching.

…orage

- Add Grok CLI as a beta-supported agent
- Implement streaming-json output parser for thought/text/end/error events
- Add session storage for local and SSH-remote Grok transcripts
- Register Grok capabilities, definitions, and model discovery
- Discover models from models_cache.json with CLI fallback
- Add Grok-specific error patterns for auth, resume, and model failures
- Support batch, resume, read-only, and reasoning-effort flags
- Accumulate text deltas when end events carry no response text
- Exclude reasoning deltas from tab-name extraction
- Document Grok CLI integration and known limitations
@coderabbitai

This comment was marked as resolved.

@greptile-apps

This comment was marked as resolved.

Comment thread src/main/agents/definitions.ts
Comment thread src/main/storage/grok-session-storage.ts Outdated
Comment thread src/main/storage/grok-session-storage.ts Outdated
coderabbitai[bot]

This comment was marked as low quality.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@ksylvan ksylvan changed the title Support grok Add Grok CLI agent support (Beta) Jul 9, 2026
- Warn in the reasoning-effort description that 'none' is rejected by
  the default model (grok-4.5) while grok-composer-2.5-fast accepts it
- Make getSessionPath() expand macOS /var|/tmp|/etc to the /private
  realpath form Grok records, so the returned transcript path agrees
  with what listSessions()/readSessionMessages() resolve
- Bound local session-listing fan-out with LOCAL_SESSION_READ_CONCURRENCY
  so large ~/.grok/sessions folders don't open hundreds of files at once

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
coderabbitai[bot]

This comment was marked as resolved.

@ksylvan ksylvan self-assigned this Jul 9, 2026
- Keep the parser's agent-specific login guidance when auth expires on
  an SSH remote: StdoutHandler now prefixes the remote-host context
  instead of replacing the message with a hardcoded "claude login"
  instruction that misdirects Grok/Codex/Copilot users
- Replace em-dashes with spaced hyphens in Grok storage comments and
  test describe blocks per coding guidelines

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pedramamini

Copy link
Copy Markdown
Collaborator

@ksylvan First off, thank you for this contribution - this is an unusually thorough agent integration. The empirically-verified flag reasoning in definitions.ts (especially the --always-approve vs repeated --permission-mode clap analysis and how it interacts with buildAgentArgs' flag dedup) is exactly the kind of thing that normally gets discovered the hard way in production. Test coverage is solid, both CI matrix legs are green, there are no merge conflicts, and you turned around every Greptile/CodeRabbit/Codex thread. Nice work.

I have one blocking item and a couple of nits before I'm happy to approve.

Blocking: the SSH auth fix regresses Claude

src/main/process-manager/handlers/StdoutHandler.ts:386-390 replaces the hardcoded message with a prefix, on the premise stated in the comment:

each agent's error patterns name that agent's own login command

That premise does not hold. I audited every auth_expired block in src/main/parsers/error-patterns.ts, and most messages carry no login command at all: all 4 Codex patterns, all 5 Factory Droid patterns, both OpenCode patterns, and Pi/Qwen/OMP. More importantly, matchErrorPattern() is first-match-wins within a type's ordered array, and for Claude the generic pattern is ordered ahead of the specific one:

  • error-patterns.ts:58 - /authentication failed/i -> "Authentication failed. Please log in again." (no command)
  • error-patterns.ts:63 - /authentication_failed/i -> "Authentication failed. Please run \"claude login\" to re-authenticate."

Pattern 58 shadows 63 for any real-world message containing "authentication failed". Same story for :53 (/invalid api key/i) and :106 (/not authenticated/i).

Net effect on rc, for the flagship agent on an SSH remote:

  • Before: Authentication failed on remote host "build-box". SSH into the remote and run "claude login" to re-authenticate.
  • After: Authentication failed on remote host "build-box". SSH into the remote to re-authenticate. Authentication failed. Please log in again.

So the Grok misdirection is genuinely fixed (good catch by Codex), but Claude SSH users trade a correct, actionable command for a generic one. Since StdoutHandler is shared by every agent, I'd rather not land that.

The Codex reviewer offered two branches; you took "keep the agent-specific message." I think the other branch is the safer one here: choose the login command by agentId. A small AGENT_LOGIN_COMMANDS: Partial<Record<ToolType, string>> map consulted in StdoutHandler gives every agent correct guidance without depending on the pattern bank's message text or its ordering. If you'd rather keep the prefix approach, that also works, but then the generic Claude messages at :53, :58, :106 should be updated to name claude login.

Either way, please extend the new StdoutHandler test - it currently only asserts the Grok path. A companion case with a claude-code parser returning the pattern-58 message, asserting claude login survives, would lock this down.

Nits (non-blocking, but I'd like the first one addressed)

1. References to a Working/ folder that isn't in the repo. CodeRabbit flagged this once in AGENT_SUPPORT.md:972; that one is still there, and there are 27 more across 11 files (grok-output-parser.ts, definitions.ts, capabilities.ts, error-patterns.ts, grok-session-storage.ts, and the test files), plus several "Phase 01 / Phase 02 Auto Run folder" mentions. Working/ does not exist on rc or on this branch, so these point future maintainers at nothing. Please strip them or reword to just "verified against grok v0.2.93." The evidence is valuable; the unreachable path is not.

2. grok: '✖️' in agentIcons.ts. U+2716 plus VS16 forces emoji presentation, which renders as a red X in most fonts. Maestro already uses red as a state color meaning "no connection / error" for agents, so a permanently-red agent icon is going to read as a broken agent in the Left Bar. Consider 𝕏 (U+1D54F) or the monochrome (U+2715, no variation selector), which sits better next to the other geometric glyphs (, ).

Observation (no action needed, just flagging)

The streamedText fallback in src/cli/services/agent-spawner.ts is guarded correctly - result only accumulates on result events with text, so there's no double-count. One side effect worth knowing about: factory-droid also routes through spawnJsonLineAgent, its result event is text: data.finalText || '', and its parser emits raw non-JSON stdout lines as isPartial: true text. When finalText is empty, the response will now be the streamed text, which can include stray stdout noise where it previously returned undefined. That's arguably an improvement over an empty response, so I'm not asking you to change it - just noting it so it isn't a surprise later.

The Grok parser, session storage (the tool_result merge indexing and the /private realpath folding both look right to me), detector, and error patterns all look good. Once the StdoutHandler item is resolved I'll approve.

ksylvan added 2 commits July 9, 2026 21:04
Choose the SSH auth re-login command by agentId via
AGENT_LOGIN_COMMANDS so Claude keeps "claude login" and Grok gets
"grok login", without depending on error-pattern message text or
first-match ordering. Strip unreachable Working/ fixture paths from
comments/docs, and switch the Grok icon to monochrome ✕ so it does
not read as the red error state in the Left Bar.
@ksylvan

ksylvan commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@pedramamini Thanks for the careful review - especially catching the Claude SSH regression. Addressed in ec87e1ff6.

Blocking: SSH auth by agentId

Agreed the prefix-and-keep-parser-message approach was the wrong branch. Pattern messages are often generic, and first-match-wins shadows the Claude patterns that do name claude login.

Took your preferred fix:

  • Added AGENT_LOGIN_COMMANDS / getAgentLoginCommand() in src/shared/agentMetadata.ts (partial map: claude-code, codex, copilot-cli, grok)
  • StdoutHandler now builds the remote auth message from that map, not from pattern text
    • known command → ... SSH into the remote and run "<cmd>" to re-authenticate.
    • no command (OpenCode, Factory, etc.) → generic re-auth without a wrong CLI name
  • Extended the StdoutHandler tests:
    • grokgrok login
    • claude-code with the generic pattern-58 message → still gets claude login
    • opencode (no map entry) → no fabricated login command
  • Also covered getAgentLoginCommand in agentMetadata.test.ts

Net Claude SSH message is back to the actionable form:

Authentication failed on remote host "build-box". SSH into the remote and run "claude login" to re-authenticate.

Nits

  1. Working/ paths - stripped the unreachable fixture references across AGENT_SUPPORT.md, definitions/capabilities/parser/error-patterns, and the related tests. Left only the legitimate Auto Run Working/ scratch-folder docs in the wizard prompt (unrelated).
  2. Icon - switched grok from ✖️ (red emoji presentation) to monochrome (U+2715) so it does not read as the Left Bar error/no-connection state.

Observation

Noted on the factory-droid streamedText fallback - no change, as you suggested.

Happy to tweak the login map (e.g. if Factory/OpenCode later grow a known CLI login) in a follow-up.

@ksylvan

ksylvan commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@pedramamini Hold on this - Fixing the inline Wizard issue

image

Grok had supportsWizard=false and no stream extractors, so /wizard failed
with "not supported". Enable the capability, join text deltas (skip
thought) for conversation and doc-gen parsing, apply --permission-mode
plan during discovery, and cover plan-mode spawn + structured reply
parsing in tests.
@ksylvan

ksylvan commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@pedramamini Hold on this - Fixing the inline Wizard issue

Fixed with the latest commit

ksylvan added 2 commits July 10, 2026 15:05
Grok emits no tool events on streaming-json, so after the first thought
the wizard looked frozen while tools (web fetch for GitHub URLs, etc.)
ran for minutes. Cap discovery turns, disable web search, ban subagents,
keep plan mode + always-approve, and only route isReasoning deltas to
thinking-chunk so assistant JSON is not mistaken for finished work.
Also accept parseable structured replies on non-zero exits (max-turns).
Plan mode and --disable-web-search blocked the reads and URL fetches
discovery needs (e.g. GitHub issue links, package.json). Keep
always-approve, max-turns, and no-subagents so silent tool loops cannot
freeze the wizard UI forever, and soften the JSON suffix to allow
scoped inspect/fetch without implementing.
@ksylvan
ksylvan requested a review from pedramamini July 13, 2026 14:56
ksylvan and others added 3 commits July 13, 2026 08:36
# Conflicts:
#	src/__tests__/shared/agentMetadata.test.ts
#	src/main/process-manager/handlers/StdoutHandler.ts
The rc branch added supportsAdditionalDirectories as a required
AgentCapabilities field; the grok entry added on this branch needs it.
Conservative default of false since no directory-grant flag is
confirmed for the Grok CLI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ksylvan

ksylvan commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

@pedramamini Grok 4.5 self-review using the Code Review Playbook.

PR_COMMENT.md
REVIEW_SCOPE.md
REVIEW_SUMMARY.md
SECURITY_ISSUES.md
TEST_GAPS.md

ksylvan and others added 2 commits July 14, 2026 15:12
Harden Grok CLI Beta support after code/security review. No critical
blockers; these changes close Major/Minor findings and follow-ups.

Stream and thinking UX
- StdoutHandler: only isReasoning partials emit thinking-chunk for Grok,
  Codex, Claude, and OpenCode so answer text does not flood the panel.
  Factory Droid keeps pre-Grok behavior (all partials); Copilot unchanged.
- Soft-succeed CLI JSONL spawns when text streamed and exit is non-zero
  without a structured error (e.g. max-turns), matching wizard recovery.

Parser and errors
- Type-guard sessionId and error messages; empty errors no longer invent
  "Unknown error".
- Mid-run non-JSON stderr runs the pattern bank (earlier auth/rate/model
  feedback). Truncate long unmatched bodies for UI; keep detail on raw.
- Drop bare 401/429 auth and rate patterns; multi-token phrases only.
- DRY thought/text deltas and AgentError construction.

Wizard
- Share extractGrokTextFromJsonl and GROK_WIZARD_DISCOVERY_ARGS across
  inline wizard, onboarding conversationManager, and document generation.
- Fix supportsWizard comment (always-approve discovery, not plan mode).
- Align modelArgs trim with configOptions.model.argBuilder.

Session storage and paths
- Validate sessionId before getSessionPath (no path traversal).
- Honor GROK_HOME for sessions and models_cache (parity with CODEX_HOME).
- Join all <user_query> wrappers; report unexpected SSH stats to Sentry.
- Extract shared isExpectedRemoteError for Grok and Copilot storage.
- Document raw tool-args JSON string shape for History consumers.

Docs and tests
- AGENT_SUPPORT: wizard always-approve residual, no noToolsArgs, History
  is not a scrubbed vault, multi-token auth/rate patterns, GROK_HOME paths.
- Tests for parser, storage, error patterns, StdoutHandler, CLI soft-success,
  grokWizard helpers, remote-error-utils, and onboarding Grok path.
# Conflicts:
#	src/main/storage/index.ts
@pedramamini
pedramamini merged commit c993434 into RunMaestro:rc Jul 15, 2026
4 checks passed
@ksylvan
ksylvan deleted the support-grok branch July 15, 2026 13:36
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.

2 participants