feat: Grok Build first-class harness adapter - #123
Conversation
|
Reviewed — same verdict as #124: strong shape, fail-closed classification, and the journal containment is actually stricter than our own adapters (re-running Three changes requested before merge:
Smaller, take or leave: the On our side: Tier-2 means we live-verify the four dialog recipes against a real Grok Build pane before merge. Plan: merge #124 first, then this one after a rebase (six trivial overlaps). |
Flattening every root into one newest-first cap let a populated healthy root starve a broken sibling out of the list — the condition this script exists to catch.
Grok Build panes get the Claude-level treatment: stripped composer chrome with an opaque status strip, native buttons for the probed dialogs, a journal adapter, and a slash-command palette. Registered by exact agent string only (the AltanS#99 bar): adapterFor stays Object.hasOwn over adapter.agent; grok-build catalog folding lives in canonicalAgent. Every keystroke the adapter emits comes from a dated live probe recorded in the notes files, against a byte-faithful fixture corpus, with describeAdapterConformance running grok against the claude and omp cohorts and vice versa. Chrome (Tier 1): the rounded composer box is located by its bottom status border and stripped; the status run is opaque across models and efforts. composerReady gates the reply path. The startup screen's bare [stable] telemetry chip under the box is chrome (matched literally — any other bracket tag is torn transcript and refuses), so a fresh pane accepts its first message. Grok paints background across fully blank rows, which striped the mirror; empty rows lose their paint — no colour inference — while glyph rows keep every background they drew. Permission cards: classified, not layout-pinned. The footer must name the family and count its rows (1/N:select), the last row must be the reject, the row above it the one-shot Yes, and every earlier row must prove itself a persistent mode change — those never become buttons. Unrecognized control rows, or text below the options, refuse the whole card. Both live layouts (3-option rm, 4-option edit) lift to Yes/No. ask_user_question: radio cards lift with digit keys; the z free-text row is modelled as feedback (purpose "free-text" — Collie never types into it) and locks the buttons whenever the keyboard sits on it, which the inner hint row's Enter:edit verb reveals even when the row repaints idle (the hint is matched as a whole anchored row, never as a substring of prose). Esc-parked cards send Tab (the footer's own key) before the digit — a bare digit is swallowed in scrollback. Checkbox cards stay raw: a digit submits rather than toggles. Multi-question wizards step through as consecutive lifted cards. Plan approval: a menu of footer-named keys only (ADR 0009 — no digits), with the composer gated while the review is up. Dialogs replace the screen from their first option row down, so the question stays in the raw mirror above the buttons — the same contract as Claude's prompt-select. The dialog signature spans the whole card; the bridge race guard refuses a stale press (409) after the screen moves. Journal: bridge/journal/grok.ts reads chat_history.jsonl from $GROK_HOME (override: COLLIE_GROK_ROOT) via containedRealpath, refusing non-UUID refs. Neutral-model changes riding along: PromptFeedback.purpose (free-text rows render no feedback composer and submitPromptFeedback refuses them), and PromptOption.keyLabel (the badge shows the digit when a recovery key precedes it). /auto joins the dangerous two-tap set — it changes approval behavior. Claude behavior unchanged, pinned by the existing claude suites. Versions untouched per the fork-PR rule; CHANGELOG line in the PR body.
Replace the sanitized no-ESC chrome fixtures with format:ansi dumps from a sandbox pane, so locateComposer is guarded against the real 3-SGR status border. Darwin temp-dir token is length-preserved. Herdr reports agent "grok" on every Grok Build pane on this host (kind list + pane.agent + agent_session.agent, 2026-08-23).
|
Review follow-up:
|
3a052a5 to
06c2175
Compare
Grok Build first-class harness adapter
|
Merged — thanks. I did the post-#124 rebase on our side: union of the four both-add files, plus one semantic conflict git missed (main renamed the no-adapter test agent codexAgent → opencodeAgent; grokAgent now builds from that — f1a7dbc). Follow-up 7d8ffb4 makes codex and grok treat each other's corpora as foreign. |
…estion One comment-paragraph conflict in conformance.test.ts: the foreign-cohort note now names all three sibling corpora (omp + codex + grok). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
Grok Build panes become first-class like Claude: composer chrome stripped with an opaque status strip re-surfaced natively, probed dialogs lifted into tappable buttons, a journal adapter, and the Grok slash catalog.
web/src/lib/harness/grok/: the rounded composer box is located by its bottom status border and stripped; the status run is opaque across models/efforts (never matchesGrok 4.6/(high)).composerReadygates the reply path; the startup screen's bare[stable]chip is matched literally as chrome so a fresh pane accepts its first message. Grok's full-width background paint on blank rows is dropped (no color inference) so the mirror doesn't stripe; glyph rows keep every background.prompt-select, family permission) — classified, not layout-pinned: the footer must name the family and count its rows (1/N:select+Tab:next option+Ctrl+o:always-approve+Ctrl+c:cancel), the last row must be the reject, the row above it the one-shot Yes, and every earlier row must prove itself a persistent mode change — those never become buttons. Unclassified rows refuse the whole card. Both live layouts (3-option rm, 4-option file-edit) lift; digits probed per layout (PERMISSION_NOTES.md), including the one-shot-doesn't-persist negative control.zfree-text row is modelled as feedback and locks the buttons whenever the keyboard sits on it; the inner hint'sEnter:editverb is the tell even when the row repaints idle (live-probed: a digit there types into the field). Esc-parked cards sendTab— the footer's own key — before the digit, because a bare digit is silently swallowed in scrollback (probed both ways). Checkbox cards stay raw (a digit submits rather than toggles). Multi-question wizards step through as consecutive cards.menu) — footer-named keys only, no digits (ADR 0009); composer gated while the review is up.bridge/journal/grok.tsreadschat_history.jsonlunder$GROK_HOME(overrideCOLLIE_GROK_ROOT) throughcontainedRealpath, refusing non-UUID refs.PromptFeedback.purpose— Grok'szrow is"free-text", so the renderer offers no feedback composer andsubmitPromptFeedbackrefuses it (the Claude plan-feedback choreography is the wrong recipe); andPromptOption.keyLabel— the badge shows the digit when a recovery key precedes it. Claude behavior unchanged, pinned by the existing claude suites.The #99 bar
adapterForstaysObject.hasOwnoveradapter.agent;grok-buildcatalog folding lives incanonicalAgent, never in the registry.grok--*.txt), notes files with the verified recipes (PERMISSION/ASK/PLAN_NOTES.md),describeAdapterConformancerunning grok against the claude+omp cohorts and vice versa./keyspath, files created/removed on disk as the negative controls), plus stale-signature replays refused with 409.Honesty notes
grok--fresh-idle…grok--user-bubble) are sanitized structure fixtures (plain UTF-8, no ESC); the live 3-SGR-run border shape is pinned separately ingrok/markers.test.tsfrom a dated probe. All dialog captures are byte-faithfulformat:ansi.zanswer from the phone, and Grok's cancel-turn panel.Suggested CHANGELOG entry
Grok Build gets a first-class harness adapter — strips the composer chrome, re-surfaces the status strip, lifts permission cards, ask_user_question radios/wizards and plan approval into native buttons, and reads the Grok session journal.
Verification
cd web && bun run typecheckclean; full web suite + conformance green;bun test bridge/green; live pass against real panes as above. Versions untouched at 0.32.0 per the fork-PR rule.🤖 Generated with Claude Code
https://claude.ai/code/session_01PFH7jQVDVhPGC6FqLetNfd