Summary
Add Grok CLI as a fourth harness in burn with maximum feature parity to Claude Code, Codex, and OpenCode. Grok sessions live under ~/.grok/sessions/<url-encoded-cwd>/<session-id>/ but do not currently emit per-turn billing tokens in on-disk logs, so usage will be estimated until native usage fields appear in session files.
Motivation
Grok CLI persists rich session data locally (chat_history.jsonl, updates.jsonl, summary.json, prompt_context.json, signals.json) but burn does not ingest it today. Users running Grok alongside other harnesses cannot get unified burn summary, hotspots, compare, or overhead views.
Feature parity matrix
| Capability | Claude | Codex | Grok target | Notes |
|---|
burn ingest / --watch | Yes | Yes | Yes | Scan ~/.grok/sessions/ |
burn summary | Yes | Yes | Yes | Estimated tokens + priced cost |
burn hotspots | Yes | Yes | Yes | Tool/file/bash attribution from chat_history |
burn compare | Yes | Yes | Yes | Activity classification |
burn overhead | CLAUDE.md | AGENTS.md | Yes | prompt_context.json + Agents.md |
| Pending stamps | Yes | Yes | Yes | writePendingStamp({ harness: "grok" }) |
| Harness adapter | Yes | Yes | Yes | pending_stamp + watch loop |
| Subagent tree | Yes | Yes | Partial → Yes | Task tool + subagents/ child sessions |
| Compaction events | Yes | Yes | Partial | compaction_checkpoints/, signals.compactionCount |
| Per-turn billing fidelity | Full | Full | Partial | Estimate; mark FidelityClass::Partial |
| Cache attribution | Yes | Partial | No | Not in Grok logs |
| Provider grouping | Yes | Yes | Yes | xai |
Grok session layout
~/.grok/sessions/<url-encoded-cwd>/<session-id>/
chat_history.jsonl ← primary: turns, tools, content (API message transcript)
updates.jsonl ← secondary: turnStartMs, totalTokens, timestamps (ACP/UI stream)
summary.json ← session id, cwd, model, git metadata
prompt_context.json ← AGENTS.md snapshot for overhead
signals.json ← session aggregates (sanity check)
subagents/ ← child session metadata
compaction_checkpoints/
Design choice: parse chat_history.jsonl for semantic content; join updates.jsonl for turn boundaries and context-size proxies.
chat_history.jsonl record types: system, user, reasoning, assistant, tool_result.
Unlike Claude/Codex (single authoritative JSONL with billing usage blocks), Grok splits model transcript from UI stream and does not log input_tokens / output_tokens / cache breakdown per turn.
Pricing
Known Grok rates (to ship as xAI model overrides):
| Metric | Cost |
|---|
| Input tokens | $1.00 / 1M |
| Output tokens | $2.00 / 1M |
Model IDs observed in sessions:
grok-composer-2.5-fastgrok-build
Add to vendored models.dev.json and support $RELAYBURN_HOME/models.dev.json overrides. No cache pricing (not exposed in logs).
Usage estimation strategy
For each turn (bounded by turnStartMs changes in updates.jsonl, aligned with <user_query> → assistant completion in chat_history):
- Output tokens —
HeuristicCounter (bytes/4) over reasoning.summary, assistant.content, and serialized tool_calls[].arguments. - Input tokens — prefer context proxy when available:
input ≈ max(0, totalTokens_end − totalTokens_start) for that turnStartMs, subtract estimated output, floor at user-prompt heuristic size. Fallback: full heuristic on messages since prior turn. - Reasoning tokens — count reasoning summary text separately.
- Fidelity —
FidelityClass::Partial, UsageGranularity::PerTurn; coverage: input/output true, cache false. - Validation — cross-check against
signals.json (contextTokensUsed, turnCount); warn if drift >15%.
burn summary should surface a fidelity note when Grok turns are present (similar to missing-pricing warnings).
Future: if Grok adds usage blocks to session logs, feature-detect and parse natively (Claude-style) behind the estimator.
Implementation plan (PR stack)
PR 1 — Types & enums (relayburn-sdk)
SourceKind::Grok ("grok")RelationshipSourceKind::Grok, NativeGrokPendingStampHarness::GrokIngestRoots.grok_sessions_dir (default ~/.grok/sessions)AdapterName::Grok, FileCursor::Grok(GrokCursor)- Node SDK +
index.d.ts updates
Files:reader/types.rs, ingest/cursors.rs, ingest/gap.rs, ingest/ingest.rs, pending_stamps.rs, relayburn-sdk-node, packages/sdk-node
PR 2 — Grok reader (reader/grok.rs)
parse_grok_session_incremental(session_dir, opts) -> ParseGrokIncrementalResult
- Walk
chat_history.jsonl; start turn on user with <user_query> - Accumulate
reasoning, assistant, tool_result until next user query - Metadata from
summary.json - Map
tool_calls / tool_result to burn content model - Incremental
GrokCursor (chat_history + updates offsets) - Fixtures in
tests/fixtures/grok/
PR 3 — Ingest orchestration
ingest_grok_into(), ingest_grok_sessions()- Wire into
ingest_all(), default_session_roots(), source_fingerprint() - Pending-stamp resolution, gap warning adapter
PR 4 — Classifier & tool aliases
| Grok tool | Canonical |
|---|
Shell | Bash |
Read | Read |
Write | Write |
StrReplace / Edit | Edit |
Grep | Grep |
Glob | Glob |
Task | Task |
WebSearch / WebFetch | WebFetch |
CallMcpTool | Mcp |
PR 5 — Pricing
Add xAI entries to models.dev.json for grok-composer-2.5-fast, grok-build, and fallback aliases.
PR 6 — Harness adapter & registry
crates/relayburn-cli/src/harnesses/grok.rs via pending_stamp::session_store_adapter- Register in
registry.rs; update harness name tests
PR 7 — Overhead (AGENTS.md)
- Treat
SourceKind::Grok like Codex/OpenCode for AGENTS.md - Optionally ingest
prompt_context.json for overhead attribution
PR 8 — Subagents & relationships
- Parse
Task tool calls; walk subagents/ for child sessions - Emit
SessionRelationshipRecord with NativeGrok - Update
subagent_tree tests
PR 9 — Node SDK + MCP
PendingStampHarness::Grok, ingest harness option, overhead harness- MCP fixture test with Grok-ingested session
PR 10 — Docs & changelog
README.md, Agents.md, CHANGELOG.md, packages/sdk-node/CHANGELOG.md- Document partial-fidelity caveat
PR 11 — Integration tests
- SDK integration: ingest fixture → summary with non-zero turns
- CLI smoke: pinned
grok_sessions_dir - Fidelity: grok turns classified
partial
Suggested milestones
MVP (PRs 1–5, 3, 10): ingest + summary + hotspots + pricing. Partial fidelity; no subagents.
Follow-up (PRs 6–8): harness adapter, overhead, subagents.
Known gaps (document in README)
- No native billing tokens — costs are estimates
- No cache read/create attribution
totalTokens can decrease on compaction — input math must handle resets- Encrypted reasoning blobs excluded from token counts (only
summary text) - Model ID drift — alias table may need updates
Verification
cargo test --workspace
cargo run -p relayburn-cli -- ingest
cargo run -p relayburn-cli -- summary --since 7d
cargo run -p relayburn-cli -- hotspots --project .
cargo run -p relayburn-cli -- overhead --kind agents-md
cargo run -p relayburn-cli -- compare --since 30d
pnpm run test
Manual: run a short grok session, then confirm burn summary shows grok-composer-* with estimated cost.
References
- Grok session docs:
~/.grok/README.md (Session Persistence section) - Grok storage:
~/.grok/sessions/ - Burn harness pattern:
Agents.md → "Adding a harness" - Codex reader reference:
crates/relayburn-sdk/src/reader/codex.rs - OpenCode ingest reference:
crates/relayburn-cli/src/harnesses/opencode.rs
Summary
Add Grok CLI as a fourth harness in burn with maximum feature parity to Claude Code, Codex, and OpenCode. Grok sessions live under
~/.grok/sessions/<url-encoded-cwd>/<session-id>/but do not currently emit per-turn billing tokens in on-disk logs, so usage will be estimated until native usage fields appear in session files.Motivation
Grok CLI persists rich session data locally (
chat_history.jsonl,updates.jsonl,summary.json,prompt_context.json,signals.json) but burn does not ingest it today. Users running Grok alongside other harnesses cannot get unifiedburn summary,hotspots,compare, oroverheadviews.Feature parity matrix
burn ingest/--watch~/.grok/sessions/burn summaryburn hotspotschat_historyburn compareburn overheadCLAUDE.mdAGENTS.mdprompt_context.json+Agents.mdwritePendingStamp({ harness: "grok" })pending_stamp+ watch loopTasktool +subagents/child sessionscompaction_checkpoints/,signals.compactionCountFidelityClass::PartialxaiGrok session layout
Design choice: parse
chat_history.jsonlfor semantic content; joinupdates.jsonlfor turn boundaries and context-size proxies.chat_history.jsonlrecord types:system,user,reasoning,assistant,tool_result.Unlike Claude/Codex (single authoritative JSONL with billing
usageblocks), Grok splits model transcript from UI stream and does not loginput_tokens/output_tokens/ cache breakdown per turn.Pricing
Known Grok rates (to ship as xAI model overrides):
Model IDs observed in sessions:
grok-composer-2.5-fastgrok-buildAdd to vendored
models.dev.jsonand support$RELAYBURN_HOME/models.dev.jsonoverrides. No cache pricing (not exposed in logs).Usage estimation strategy
For each turn (bounded by
turnStartMschanges inupdates.jsonl, aligned with<user_query>→ assistant completion inchat_history):HeuristicCounter(bytes/4) overreasoning.summary,assistant.content, and serializedtool_calls[].arguments.input ≈ max(0, totalTokens_end − totalTokens_start)for thatturnStartMs, subtract estimated output, floor at user-prompt heuristic size. Fallback: full heuristic on messages since prior turn.FidelityClass::Partial,UsageGranularity::PerTurn; coverage: input/output true, cache false.signals.json(contextTokensUsed,turnCount); warn if drift >15%.burn summaryshould surface a fidelity note when Grok turns are present (similar to missing-pricing warnings).Future: if Grok adds
usageblocks to session logs, feature-detect and parse natively (Claude-style) behind the estimator.Implementation plan (PR stack)
PR 1 — Types & enums (
relayburn-sdk)SourceKind::Grok("grok")RelationshipSourceKind::Grok,NativeGrokPendingStampHarness::GrokIngestRoots.grok_sessions_dir(default~/.grok/sessions)AdapterName::Grok,FileCursor::Grok(GrokCursor)index.d.tsupdatesFiles:
reader/types.rs,ingest/cursors.rs,ingest/gap.rs,ingest/ingest.rs,pending_stamps.rs,relayburn-sdk-node,packages/sdk-nodePR 2 — Grok reader (
reader/grok.rs)chat_history.jsonl; start turn onuserwith<user_query>reasoning,assistant,tool_resultuntil next user querysummary.jsontool_calls/tool_resultto burn content modelGrokCursor(chat_history + updates offsets)tests/fixtures/grok/PR 3 — Ingest orchestration
ingest_grok_into(),ingest_grok_sessions()ingest_all(),default_session_roots(),source_fingerprint()PR 4 — Classifier & tool aliases
ShellBashReadReadWriteWriteStrReplace/EditEditGrepGrepGlobGlobTaskTaskWebSearch/WebFetchWebFetchCallMcpToolMcpPR 5 — Pricing
Add xAI entries to
models.dev.jsonforgrok-composer-2.5-fast,grok-build, and fallback aliases.PR 6 — Harness adapter & registry
crates/relayburn-cli/src/harnesses/grok.rsviapending_stamp::session_store_adapterregistry.rs; update harness name testsPR 7 — Overhead (
AGENTS.md)SourceKind::Groklike Codex/OpenCode forAGENTS.mdprompt_context.jsonfor overhead attributionPR 8 — Subagents & relationships
Tasktool calls; walksubagents/for child sessionsSessionRelationshipRecordwithNativeGroksubagent_treetestsPR 9 — Node SDK + MCP
PendingStampHarness::Grok, ingest harness option, overhead harnessPR 10 — Docs & changelog
README.md,Agents.md,CHANGELOG.md,packages/sdk-node/CHANGELOG.mdPR 11 — Integration tests
grok_sessions_dirpartialSuggested milestones
MVP (PRs 1–5, 3, 10): ingest + summary + hotspots + pricing. Partial fidelity; no subagents.
Follow-up (PRs 6–8): harness adapter, overhead, subagents.
Known gaps (document in README)
totalTokenscan decrease on compaction — input math must handle resetssummarytext)Verification
Manual: run a short
groksession, then confirmburn summaryshowsgrok-composer-*with estimated cost.References
~/.grok/README.md(Session Persistence section)~/.grok/sessions/Agents.md→ "Adding a harness"crates/relayburn-sdk/src/reader/codex.rscrates/relayburn-cli/src/harnesses/opencode.rs