
SpaceXAI has open-sourced Grok Build, the terminal-based AI coding agent behind its grok CLI. The source landed on GitHub today. The release covers the agent harness, TUI, CLI shell, and developer tooling under the Apache 2.0 license
What is Grok Build?
A harness is the scaffolding around a model. It assembles context, calls the model, parses the reply, and dispatches tool calls.
Grok Build was launched as an early beta on May 25, 2026. It is an agent that understands your codebase, edits files, executes shell commands, and searches the web. It also manages long-running tasks. It runs as a full-screen, mouse-interactive TUI.
Three surfaces exist. There is the interactive TUI, headless mode for scripting and CI. Editors embed it through the Agent Client Protocol (ACP).
var STEPS=[
{id:’entry’,x:20,y:56,crate:’crates/codegen/xai-grok-pager’},
{id:’ctx’,x:250,y:56,crate:’crates/codegen/xai-grok-shell’,name:’Assemble context’,desc:’The harness discovers what this directory gives the model.’,
list:[‘AGENTS.md, skills, plugins, hooks, MCP servers’,’config.toml picks the model and base_url’,’grok inspect prints exactly what was found’],log:’ctx discovered AGENTS.md, 3 skills, 1 MCP server’},
{id:’model’,x:480,y:56,crate:’model endpoint (api.x.ai or your own)’,name:’Call the model’,desc:’The assembled context goes to grok-4.5, or to any model you configure.’,
list:[‘Default binary authenticates in the browser’,’XAI_API_KEY works in non-browser environments’,’A local base_url keeps the whole loop on your machine’],log:’model grok-4.5 -> 1 tool call‘},
{id:’parse’,x:710,y:56,crate:’crates/codegen/xai-grok-shell’,name:’Parse the response’,desc:’The runtime splits prose from tool calls and validates arguments.’,
list:[‘Text goes to the transcript’,’Tool calls go to the dispatcher’,’Malformed calls are rejected, not executed’]},
{id:’tools’,x:710,y:216,crate:’crates/codegen/xai-grok-tools’,name:’Dispatch tools’,desc:’Tool implementations run: terminal, file edit, search, and web.’,
list:[‘Read and edit files across the repo’,’Run shell commands’,’Search the codebase and the web’]},
{id:’work’,x:480,y:216,crate:’crates/codegen/xai-grok-workspace’,name:’Touch the workspace’,desc:’The workspace layer owns the filesystem, VCS, execution, and checkpoints.’,
list:[‘Every edit is checkpointed for rollback’,’Git state is tracked as the agent works’,’Sandboxing config lives in the CLI crate closure’]},
{id:’gate’,x:250,y:216,crate:’crates/codegen/xai-grok-shell’,name:’Loop or finish’,desc:’Tool results re-enter context. More tool calls mean another pass.’,
list:[‘Results are appended, then the model runs again’,’The loop exits when no tool call comes back’,’Long tasks can run many passes’]},
{id:’out’,x:20,y:216,crate:’crates/codegen/xai-grok-pager’}
];
var W=170,H=64;
function mid(s){return {x:s.x+W/2,y:s.y+H/2};}
var PATHS=[
‘M190 88 L246 88’, // entry -> ctx
‘M420 88 L476 88’, // ctx -> model
‘M650 88 L706 88’, // model -> parse
‘M795 120 L795 212’, // parse -> tools
‘M706 248 L654 248’, // tools -> work
‘M476 248 L424 248’, // work -> gate
‘M335 216 L335 124’, // gate -> ctx (loop up)
‘M246 248 L194 248’ // gate -> out
];
function el(t,a){var e=document.createElementNS(NS,t);for(var k in a)e.setAttribute(k,a[k]);return e;}
var wireEls=[];
PATHS.forEach(function(d,i){
var p=el(‘path’,{d:d,’class’:’wire’,’marker-end’:’url(#gbA)’});
WIRES.appendChild(p); wireEls.push(p);
});
// loop label
var lt=el(‘text’,{x:342,y:172,’class’:’ncrate’}); lt.textContent=”loop while tool_calls”; WIRES.appendChild(lt);
var boxEls={},labEls={};
STEPS.forEach(function(s,i){
var g=el(‘g’,{});
var r=el(‘rect’,{x:s.x,y:s.y,width:W,height:H,rx:2,’class’:’nbox’});
var bar=el(‘rect’,{x:s.x,y:s.y,width:4,height:H,fill:BANDS[i%BANDS.length]});
var t1=el(‘text’,{x:s.x+14,y:s.y+26,’class’:’nlab’});
var t2=el(‘text’,{x:s.x+14,y:s.y+45,’class’:’ncrate’});
g.appendChild(r);g.appendChild(bar);g.appendChild(t1);g.appendChild(t2);
NODES.appendChild(g);
boxEls[s.id]=r; labEls[s.id]={t:t1,c:t2};
});
function shortCrate(c){var p=c.split(‘/’);return p[p.length-1];}
function paintLabels(){
STEPS.forEach(function(s){
var nm=s.name, cr=s.crate;
if(s.id===’entry’){nm=ENTRY[mode].name;}
if(s.id===’out’){nm=OUT[mode].name;}
labEls[s.id].t.textContent=nm;
labEls[s.id].c.textContent=shortCrate(cr);
});
}
paintLabels();
var LOG=root.querySelector(‘#gb-log’);
function logline(html){
LOG.innerHTML+=’\n’+html;
LOG.scrollTop=LOG.scrollHeight;
}
function resetLog(){
LOG.innerHTML=’'+ENTRY[mode].log+'\n> Add retry logic to fetch_user() and run the tests.‘;
}
var TOOLPASS=[
{t:’tool search “fn fetch_user”‘,w:’work read src/api/user.rs (1 match)‘},
{t:’tool edit src/api/user.rs +14 -2′,w:’work checkpoint written (rollback available)‘},
{t:’tool terminal cargo test -p api‘,w:’work 12 passed 0 failed‘}
];
var side={crate:root.querySelector(‘#gb-crate’),name:root.querySelector(‘#gb-name’),desc:root.querySelector(‘#gb-desc’),list:root.querySelector(‘#gb-list’)};
var AG=root.querySelector(‘#gb-agents’);
var fills=AG.querySelectorAll(‘.fill’);
function showSide(s){
var nm=s.name,ds=s.desc,ls=s.list;
if(s.id===’entry’){nm=ENTRY[mode].name;ds=ENTRY[mode].desc;ls=ENTRY[mode].list;}
if(s.id===’out’){nm=OUT[mode].name;ds=OUT[mode].desc;ls=OUT[mode].list;}
side.crate.textContent=s.crate;
side.name.textContent=nm;
side.desc.textContent=ds;
side.list.innerHTML=”;
(ls||[]).forEach(function(x){var li=document.createElement(‘li’);li.textContent=x;side.list.appendChild(li);});
AG.style.display=(subs&&(s.id===’tools’||s.id===’work’))?’block’:’none’;
if(subs&&s.id===’tools’){
fills[0].style.width=”0%”;fills[1].style.width=”0%”;fills[2].style.width=”0%”;
setTimeout(function(){fills[0].style.width=”90%”;fills[1].style.width=”65%”;fills[2].style.width=”40%”;},60);
}
}
function litWires(i){
wireEls.forEach(function(p,j){
var on=false;
if(i>0&&i<7) on=(j===i-1);
if(i===1&&pass>1) on=(j===0)||(j===6);
if(i===7) on=(j===7);
p.setAttribute(‘class’,on?’wire lit’:’wire’);
p.setAttribute(‘marker-end’,on?’url(#gbB)’:’url(#gbA)’);
});
}
function highlight(i){
STEPS.forEach(function(s,j){boxEls[s.id].setAttribute(‘class’,j===i?’nbox on’:’nbox’);});
DOT.setAttribute(‘r’,’7′);
DOT.setAttribute(‘fill’,BANDS[i%BANDS.length]);
var c=mid(STEPS[i]);
DOT.setAttribute(‘cx’,c.x);DOT.setAttribute(‘cy’,c.y);
litWires(i);
showSide(STEPS[i]);
}
function reduced(){return window.matchMedia&&window.matchMedia(‘(prefers-reduced-motion: reduce)’).matches;}
function travel(from,to,cb){
var a=mid(STEPS[from]),b=mid(STEPS[to]);
if(reduced()){cb();return;}
var t0=null,dur=520;
function frame(ts){
if(!t0)t0=ts;
var k=Math.min(1,(ts-t0)/dur), e=k<.5?2*k*k:-1+(4-2*k)*k;
DOT.setAttribute(‘cx’,a.x+(b.x-a.x)*e);
DOT.setAttribute(‘cy’,a.y+(b.y-a.y)*e);
if(k<1){raf=requestAnimationFrame(frame);}else{cb();}
}
raf=requestAnimationFrame(frame);
}
function emit(i){
var s=STEPS[i];
if(i===0){return;}
if(s.id===’ctx’){logline(pass===1?s.log:’ctx tool results appended (pass ‘+pass+’)‘);}
else if(s.id===’model’){logline(pass<3?s.log:’model grok-4.5 -> no tool calls, done‘);}
else if(s.id===’tools’){logline(TOOLPASS[Math.min(pass-1,2)].t);if(subs)logline(‘tool task -> 3 subagents, own context windows‘);}
else if(s.id===’work’){logline(TOOLPASS[Math.min(pass-1,2)].w);}
else if(s.id===’gate’){logline(pass<3?’loop tool call returned, another pass’:’loop exit’);}
else if(s.id===’out’){logline(‘done 1 file changed, 12 tests passing’);}
}
function next(){
if(idx<0){pass=1;idx=0;highlight(0);root.querySelector(‘#gb-it’).textContent=pass;return;}
var from=idx,to;
if(idx===6){ to=(pass<3)?1:7; if(to===1){pass++;root.querySelector(‘#gb-it’).textContent=Math.min(pass,3);} }
else if(idx===7){ stop(); reset(); return; }
else { to=idx+1; }
idx=to;
travel(from,to,function(){highlight(to);emit(to);if(playing)setTimeout(function(){if(playing)next();},680);});
}
function stop(){playing=false;root.querySelector(‘#gb-play’).textContent=”Play”;if(raf)cancelAnimationFrame(raf);}
function reset(){stop();idx=-1;pass=0;root.querySelector(‘#gb-it’).textContent=”0″;
STEPS.forEach(function(s){boxEls[s.id].setAttribute(‘class’,’nbox’);});
wireEls.forEach(function(p){p.setAttribute(‘class’,’wire’);p.setAttribute(‘marker-end’,’url(#gbA)’);});
DOT.setAttribute(‘r’,’0′);AG.style.display=’none’;
side.crate.textContent=”crates/codegen/xai-grok-pager”;
side.name.textContent=”Ready”;
side.desc.textContent=”Pick a mode, then press Play. The loop repeats while the model keeps returning tool calls.”;
side.list.innerHTML=”;
resetLog();
}
root.querySelector(‘#gb-play’).addEventListener(‘click’,function(){
if(playing){stop();return;}
playing=true;this.textContent=”Pause”;
if(idx<0){next();emit(0);setTimeout(function(){if(playing)next();},600);}else{next();}
});
root.querySelector(‘#gb-step’).addEventListener(‘click’,function(){stop();next();});
root.querySelector(‘#gb-reset’).addEventListener(‘click’,reset);
root.querySelector(‘#gb-sub’).addEventListener(‘click’,function(){
subs=!subs;this.setAttribute(‘aria-pressed’,subs?’true’:’false’);
if(idx>=0)showSide(STEPS[idx]);
});
root.querySelectorAll(‘.gb-seg button’).forEach(function(b){
b.addEventListener(‘click’,function(){
root.querySelectorAll(‘.gb-seg button’).forEach(function(x){x.setAttribute(‘aria-pressed’,’false’);});
b.setAttribute(‘aria-pressed’,’true’);mode=b.dataset.mode;paintLabels();reset();
});
});
resetLog();
function post(){
var h=root.offsetHeight+40;
if(window.parent!==window)window.parent.postMessage({mtpHeight:h,frame:’mtp-gbloop’},’*’);
}
new ResizeObserver(post).observe(root);
window.addEventListener(‘load’,post);
setTimeout(post,120);
})();
“>
What does the published area contain?
Building on that framing, SpaceXAI lists four published areas. The agent loop covers context assembly, response parsing, and tool-call dispatch. The tools cover how the agent reads, edits, and searches code. The terminal UI covers rendering, input handling, plan review, and the inline diff viewer. The extension system covers skills, plugins, hooks, MCP servers, and subagents.
Those areas map onto named crates:
| Path | Contents |
|---|---|
crates/codegen/xai-grok-pager-bin | Composition-root package; builds the xai-grok-pager binary |
crates/codegen/xai-grok-pager | The TUI: scrollback, prompt, modals, rendering |
crates/codegen/xai-grok-shell | Agent runtime plus leader/stdio/headless entry points |
crates/codegen/xai-grok-tools | Tool implementations (terminal, file edit, search) |
crates/codegen/xai-grok-workspace | Host filesystem, VCS, execution, checkpoints |
third_party/ | Vendored upstream source (Mermaid diagram stack) |
Read that table as a reading order. Start at xai-grok-shell for the loop, then xai-grok-tools. One build note is easy to miss. The root Cargo.toml is generated, and the README says to treat it as read-only.
How does the local-first path work?
Beyond inspection, SpaceXAI frames one practical outcome. Grok Build can now run fully local-first. Compile it yourself, point it at local inference, and drive everything from config.toml.
# ~/.grok/config.toml (Windows: %USERPROFILE%\.grok\config.toml)
[model.my-model]
model = "model-id"
base_url = "https://api.example.com/v1"
name = "Display Name"
env_key = "API_KEY"
[models]
default = "my-model"grok inspect then prints what the harness discovered in the current directory. That covers config sources, instructions, skills, plugins, hooks, and MCP servers.
How does Grok Build compare?
| Agent | First-party license | Fork and modify | Model choice | External PRs |
|---|---|---|---|---|
Grok Build (xai-org/grok-build) | Apache 2.0 | Permitted | Any, via config.toml | Not accepted |
Codex CLI (openai/codex) | Apache 2.0 | Permitted | OpenAI models | Open PR queue |
OpenCode (anomalyco/opencode) | MIT | Permitted | 75+ providers | Community project |
| Claude Code | Proprietary | Not granted | Anthropic models | n/a |
Use cases and examples
Given all of that, four uses hold up today.
- Audit before adoption: Read
xai-grok-toolsbefore letting an agent run shell commands in a regulated repo. - Fork for an internal harness: Apache 2.0 permits it; upstream merge is not on offer.
- Air-gapped runs: Compile locally, set
base_urlto an internal endpoint, and skipapi.x.ai. - CI automation: Headless mode feeds structured output into a pipeline step.
# Prebuilt binary (macOS, Linux, Windows)
curl -fsSL https://x.ai/cli/install.sh | bash
grok --version
# Or build from source (needs protoc and the pinned Rust toolchain)
cargo build -p xai-grok-pager-bin --release # -> target/release/xai-grok-pager
# Audit path: per-crate commands, because full-workspace builds are slow
cargo check -p xai-grok-tools
cargo test -p xai-grok-config
cargo clippy -p xai-grok-shell
# Headless run with machine-readable output
grok -p "Explain the architecture" --output-format streaming-json
# Route one run through a model declared in ~/.grok/config.toml
grok inspect
grok -p "Hello" -m my-modelCheck out the GitHub Repo, the announcement, and the documentation.







