Grok Bot is a stateful agent service that runs inside a Linux "box." The model is only one part of it. A host process accepts commands, owns conversations, assembles prompts, calls an inference backend, delegates tool work, checkpoints each turn, and publishes events. A separate execution daemon gives the host controlled access to shells, files, terminals, MCP servers, browsers, and virtual desktops.
This document explains the deployed system recovered from the Grok Bot image and the local VM built to preserve and run that image. It keeps those two systems separate. The recovered source describes the original runtime. The clone-lab code describes the recovery VM, its routing, and its known parity gaps.
The source reconstruction comes from the deployed host-main.cjs, five auxiliary
host bundles, the separate exec-daemon bundle, exact unbundled runtime scripts,
protocol reflection, and native binaries. The original TypeScript source maps were
not present. Recovered JavaScript bodies are strong evidence of behavior, but they
do not recover erased TypeScript annotations or every original import spelling.
This document uses four labels:
- Exact runtime source is a byte-identical script captured from the image.
- Recovered source is a body extracted from a deployed JavaScript bundle.
- Derived means a relationship can be reproduced mechanically from recovered files or protocols.
- Inference means several sources support an architectural conclusion that no single source states as a contract.
The canonical recovered tree contains 1,804 modules. The clean developer-facing
projection divides them into sand-host, exec-daemon, dune, and 36
@anysphere/* workspace packages. These counts come from the reconstruction at
commit 8740c03c8c6f14f28d1af653c2f0869da021b359.
Grok client or control plane
|
| authenticated HTTP command
| long-lived SSE event stream
v
+----------------------- Linux box ------------------------+
| |
| host-main.cjs |
| +---------------- SandHost ---------------------------+ |
| | gateway -> transcript manager -> per-agent runner | |
| | | | | |
| | | +-> inference RPC | |
| | | +-> Task children | |
| | | +-> approvals | |
| | | +-> tools | |
| | v | |
| | store.db + blob DB + transcript projections | |
| +------------------------------------------------------+ |
| | authenticated ConnectRPC/WS |
| v |
| exec-daemon |
| +-> shell and file operations |
| +-> PTY and tmux sessions |
| +-> MCP subprocesses |
| +-> X11 computer use and screenshots |
| |
| sand-window-router -> per-display exec daemons |
| sand-supervisor -> host, Xvfb, Chrome, VNC, noVNC |
+-----------------------------------------------------------+
|
| short-lived access token
v
Cursor-backed inference service
The useful mental model is a durable coordinator connected to replaceable
services. host-main.cjs decides what a turn means. The inference backend
generates model steps. exec-daemon performs operating-system work. The gateway
translates client commands and streams state changes. No one component is the
whole bot.
The captured deployment ran as a Docker-style container. /tini was PID 1 and
started pod-daemon. pod-daemon created processes on demand and parented the
long-lived Sand runtime. The observed process tree was:
/tini
βββ /pod-daemon gRPC process creation, TCP 26500
βββ sand-exit-watch top-level child ownership
βββ supervise-exec-daemon
β βββ exec-daemon ConnectRPC 1337, PTY WS 1338
βββ supervise-sand-supervisor
β βββ sand-supervisor.mjs
β βββ host-main.cjs HTTP/SSE gateway 1340
β βββ x11vnc children
β βββ fork noVNC router TCP 6081
βββ sand-window-router.mjs TCP 1339
βββ sand-session-sync.mjs
βββ browser authentication and cookie helpers
βββ desktop :1 primary agent desktop
βββ desktops :2, :3, :4 forked task desktops
pod-daemon is below the hosting control plane and above the application. It is
useful for creating a process inside the box, but it is not the conversational
API. The client experience enters through host-main.cjs on port 1340.
The VM boundary matters. Same-user processes inside the box can often reach loopback listeners, inspect process metadata, and share X11 state. Display numbers separate desktops and browser profiles. They are not separate operating-system users or security principals.
The recovered entry point recovered-monorepo-final/src/host/main.ts
acquires a host lock, starts SandHost, resolves gateway settings, starts the
server, writes discovery data, and installs shutdown handlers. The composition
root in recovered-monorepo-final/src/host/sand-host.ts loads
extensions, restores transcript state, creates runner services, wires events, and
exposes the gateway API.
The exact sand-supervisor.mjs script owns a wider dependency graph. It starts or
re-adopts the host and desktop processes, writes health snapshots, detects crash
loops, and probes the VNC path. supervise-exec-daemon separately restarts the
primary execution daemon and checks its listener. The host adds an authenticated
ping because an open TCP port does not prove that the daemon event loop can answer.
Shutdown and upgrade are coordinated states. The host stops new work, expires pending approvals, checkpoints active turns at safe boundaries, records agents that need continuation, and lets the replacement process consume those resume markers.
recovered-monorepo-final/src/host/gateway-server.ts provides
HTTP authentication, body-size limits, JSON command routing, health, SSE, avatars,
local-exec queues, WebAuthn queues, and upgrade preparation. The dispatch table in
recovered-monorepo-final/src/host/gateway-protocol.ts maps
command names to methods in
recovered-monorepo-final/src/host/host-gateway-api.ts.
The ordinary command path is:
POST /api/<command>
-> check the browser Origin and Host policy
-> verify the bearer token in constant time when auth is configured
-> enforce the request-body limit and parse JSON
-> resolve <command> in the dispatch table
-> call the host API adapter
-> mutate or read the owning subsystem
-> return JSON
The gateway covers messages, transcripts, named agents, rooms, channels, automations, workflows, memories, settings, permissions, approvals, secrets, plugins, skills, box state, and updates. It does not execute model tokens or shell commands. It routes requests to the services that own those operations.
sendPrompt returns after the transcript manager durably accepts the prompt. It
normally returns { "accepted": true } before inference finishes. Replies arrive
as later transcript events over GET /events.
This split is why the gateway has clientNonce and
promptAcceptanceStatus. A client that times out after sending a prompt cannot
know whether the server committed it. The correct retry sequence is:
1. Open and authenticate GET /events.
2. Generate one clientNonce for the logical prompt.
3. POST /api/sendPrompt with the agent ID, prompt, and clientNonce.
4. If the response is ambiguous, call promptAcceptanceStatus.
5. Retry only the identical payload with the identical nonce when needed.
6. Follow transcript events until the turn settles or waits for input.
Changing the payload while reusing a nonce is a conflict. Generating a new nonce for an ambiguous retry risks running the mutation twice.
createAgent has its own bounded in-memory nonce ledger. It prevents concurrent
duplicate creation requests from minting more than one agent while the operation
is active.
GET /events is a long-lived Server-Sent Events stream with heartbeat, optional
gzip, and optional channel filtering. SandHost.wireEvents() fans out changes to
transcripts, agents, outlines, subagents, asynchronous tasks, memory, automations,
workflows, trays, and box state.
The client therefore does not poll one "run" object for everything. It sends commands and observes a stream of domain events. This is how prompt acceptance can return fast while thinking, tool calls, child agents, approvals, and final messages continue in the background.
The main turn path spans the gateway, transcript manager, runner, inference transport, tools, and persistence:
prompt accepted and enqueued
-> allocate request ID, trace, and cancellation generation
-> snapshot privacy mode and agent profile
-> build the ConversationAction
-> create main and summarization inference sessions
-> discover MCP tools
-> restore or skip a transcript checkpoint
-> ensure that the agent has a box
-> compose the tool-bearing agent
-> stream model steps
-> text and reasoning parts
-> tool calls
-> approval s
-> Task child dispatches
-> persist step checkpoints
-> settle as success, awaiting-user, aborted, quiesced, or error
-> persist final state and emit events
recovered-monorepo-final/src/host/runner/prompt-collector-glue.ts
combines the visible message with reply context, attachments, recent messages,
profile changes, automation markers, trusted hidden context, and unanswered
questions. recovered-monorepo-final/src/host/runner/turn-run-shell.ts
then creates the model sessions and drives the turn.
MCP discovery degrades to no MCP tools if discovery fails. That failure does not erase the conversation. First-token deadlines and retry policy belong to the runner, while transport-specific request and stream conversion belong to the inference layer.
Each run has an ownership generation. A cancelled or superseded run cannot write over a newer generation. The transcript manager also checks whether a replacement run can deliver a superseding user message before it cancels the old run. This guard prevents a fast cancellation from stranding the new message.
The runner records step checkpoints separately from the final turn state. A widget request, secret request, approval request, or forced upgrade can at a committed boundary. After restart or user input, the host resumes from that boundary instead of blindly replaying the whole turn.
This is an exactly-once approximation, not a universal transaction across the model, filesystem, network, and third-party APIs. Side-effecting tools still need idempotency. The checkpoint prevents many accidental repeats by recording which step completed before the host continues.
recovered-monorepo-final/src/host/extensions/auth/credential-renewer.ts
exchanges a renewal credential for a short-lived access token. It refreshes before
expiry, coalesces concurrent refresh requests, backs off after errors, and redacts
diagnostics. recovered-monorepo-final/src/host/extensions/auth/auth-service.ts
keeps the access token in memory and rejects a token that is too close to expiry.
recovered-monorepo-final/src/host/extensions/inference/inference-service.ts
combines authentication, settings, experiments, default-model selection, and
special models for browser or computer work. cursor-session.ts creates the
Cursor-backed prompt session. The protobuf client serializes messages, tools,
parameters, lineage, and provenance, then converts streamed response parts into
typed text, reasoning, tool, metadata, usage, and error events.
The runner creates a separate summarization session. General Task children inherit the normal host model selection. Media-review children may force a specialized model.
Inference credentials and execution credentials have different jobs. A shell in the box can perform an approved command without receiving the host's renewal credential or short-lived model token. This separation limits how much authority a tool subprocess needs.
The user-visible agent list contains durable named agents. The gateway can create, open, update, duplicate, interrupt, and delete them. A named agent owns persistent conversation state, profile, schedules, memory, source identity, box assignment, and permission state. Host startup reloads these agents.
A Task subagent is a logical child session created for one delegated job. It is not a new VM and usually is not a separate operating-system process.
parent model calls Task
-> review the proposed delegation against the parent conversation
-> create a child SandAgentRunner
-> assign child transcript and request identities
-> record parent, type, tool call, title, and lineage
-> arm the parent's pending wake and a stall watchdog
-> run the child in the background
-> publish child status and outline events
-> on completion, capture the result and free any desktop window
-> revive the parent with a completion event
-> parent model reads the result and continues
recovered-monorepo-final/src/host/runner/turn-agent-composition.ts
creates the child runner with shared host services for inference, box access, MCP,
policy, and events. The child gets distinct transcript and request identity plus
the parent's provenance. The recovered composition disables nested Task
configuration inside a Task child, so the ordinary child cannot recursively fan
out another level.
recovered-monorepo-final/src/host/runner/subagent-runtime.ts
keeps separate maps for live sessions, run promises, metadata, registry status,
outlines, watchdogs, pending steering messages, and abort state. Steering records a
message, interrupts the current child turn, and starts a new turn on the same child
context after settlement. Stopping a child clears the pending wake, interrupts the
turn, and suppresses later parent revival.
The host can offer several child types:
- A general-purpose child handles research or coding in the background.
- A
browserUsechild drives Chrome at the page and element level. - A
computerUsechild operates the whole X11 desktop through screenshots and input events. - Media-review children use specialized prompts and may select a different model.
Computer-use windows are scarce resources. The host allocates a display to the child and releases it when the child settles. Browser use and computer use are separate tools because DOM-level automation is faster and less disruptive, while pixel-level control works with native applications and hostile web interfaces.
The recovered host also exposes cloud-agent launch and watch tools. A cloud coding agent is not a durable named Sand agent and is not an in-process Task child. It can run on a separate remote worker or VM with its own checkout, generated branch, transcript, status, and artifacts. The parent watches or imports its result through the cloud-agent service.
The three categories have different ownership:
| Category | Runner location | Machine | Durable state | How completion appears |
|---|---|---|---|---|
| Named Sand agent | SandHost |
Its assigned box | Per-agent directory, SQLite, and blobs | Direct transcript and SSE updates |
| Task child | Another SandAgentRunner in the same host |
Reuses the parent's box, with an optional fork display | Child conversation state plus live runtime maps | Completion wake revives the parent |
| Cloud coding agent | Remote cloud-agent service | Separate worker or VM | Remote transcript, branch, and artifacts | Parent watches and imports the result |
The generic Task package contains richer resume and cloud-placement concepts than the recovered Sand background adapter visibly persists. The code proves steering a live Sand child and delivering its completion. It does not, by itself, prove that a completed child's private runner can resume after a host restart. That behavior needs a live-runtime test before publication as a durable guarantee.
The host composes separate review providers for host shell, box shell, MCP, computer use, automation writes, cloud-agent operations, and Task launch. A review can allow an action, block it, or the turn for the user.
model proposes an action
-> surface-specific policy and auto-review
-> allow: execute the exact action
-> deny: return the refusal
-> needs user: persist approval request and
-> gateway receives resolution
-> resume from the checkpoint or expire the request
The runtime permits only one pending approval at a time for an audited turn. Task launch is reviewed in the real parent context before the child sees the delegated prompt. The child must still pass review for each concrete shell, MCP, browser, or desktop action it proposes.
Execution-side permissions merge administrator, user, repository, and hardcoded policy. The daemon checks parsed commands, redirects, delete protection, sandbox availability, workspace access, extra paths, and network policy. Approval is best understood as permission for one exact proposed action, not a permanent grant for a tool category.
exec-daemon starts two authenticated servers. The HTTP ConnectRPC server exposes
execution and control services. The WebSocket server exposes PTY operations such as
spawn, attach, input, resize, list, and terminate. Optional tmux services keep
terminal sessions alive across individual requests.
The control service covers health, capabilities, direct file operations, diffs, artifacts, environment refresh, plugin operations, and MCP . The execution service carries typed streaming envelopes to registered resource executors. Shell, files, MCP, and computer use share transport, but each has its own executor and policy.
Shell sessions can persist executable Bash, zsh, or PowerShell state. Before each command, the daemon unsets old conversation and agent-store variables and injects the current request's server-derived values. This ordering prevents an older shell snapshot from impersonating a later conversation.
The sandbox policy describes workspace read or write access, read boundaries, extra read-only and read-write paths, protected mappings, temporary-directory rules, and network rules. Hardcoded policy protects Git hooks, agent settings, SSH material, and other executable configuration. If sandbox enforcement is required but unavailable, a safe replica must fail closed rather than run unrestricted.
MCP servers run as workload processes behind the execution daemon. The host
discovers their tools for each turn and presents those tools to the model. MCP has
its own sandbox policy and approval path. A long-lived railway mcp or
XcodeBuildMCP process in the observed box was workload state, not a boot daemon.
Each desktop is an Xvfb display with a window manager, compositor, dock, VNC
server, and a Chrome profile. For display N >= 2, the exact runtime maps ports as
follows:
exec ConnectRPC: 14000 + N
PTY WebSocket: 13600 + N
VNC: 5900 + N
Chrome CDP: 9222 + N
recovered-monorepo-final/src/host/box/box-windows.ts allocates
the display and mints an owner token. Requests carry x-sand-display. Fork routes
also carry x-sand-window-owner, which must match the token bound to that display.
sand-window-router.mjs selects either the primary daemon or the daemon for that
display.
Local computer use sends X11 input and captures screenshots. Browser use talks to
the browser at a page level. sand-session-sync.mjs connects to live Chrome
instances over loopback CDP and mirrors cookies, including HttpOnly cookies, plus
localStorage. It does not mirror IndexedDB. A per-display busy lease delays page
reloads while computer use is acting.
Session sync makes login state convenient across an agent's windows, but it expands the authentication trust domain. The display token protects routing. It does not turn each display into a separate user account or filesystem boundary.
Each durable agent has a SQLite store.db with key-value state, legacy blobs, and
transcript entries. A separate strict SQLite blob database stores
content-addressed conversation payloads. A root in the agent state points to the
reachable payload graph.
store.db
+-> current root and transcript metadata
|
+-> conversation-blobs.db
|
+-> transcript JSONL journal and mirror
+-> search-index.db
profile, memory, routines, workflows, and store snapshots
+-> box-store manifest and immutable uploaded objects
The JSONL transcript and search index are projections. The host can rebuild them from canonical agent and blob state. Search corruption must not decide whether a conversation exists. Database recovery quarantines damaged files, salvages rows that can be read independently, verifies replacements, and only then installs them.
The blob store uses Node worker threads. AgentWorkerPool creates one worker per
blob-database path, up to its capacity, and evicts idle workers. The worker owns
blob reads, writes, checkpoint-root lookup, stale-root cleanup, garbage collection,
legacy retirement, flush, and close. These are storage workers. They are unrelated
to model Task children, which are SandAgentRunner objects in the host process.
Live SQLite files are captured through database-safe immutable snapshots. Box-store hydration uses manifests and an explicit completeness state. Deletion propagation starts only after a trusted baseline exists, which prevents a partial download from being mistaken for an authoritative empty state.
Profiles use atomic profile.json updates. Memory is split into agent, shared-user,
and project scopes with single-writer shards. Automations store definitions and a
bounded run history. Workflows merge user, managed, and plugin-owned definitions
without discarding ownership.
Agent identity, source identity, conversation identity, box identity, Task child identity, and automation-run identity are distinct. Treating any two as the same ID would break routing or persistence isolation.
Schedules, listeners, and backend events feed a trigger hub. The hub creates a durable wake for a named agent and sends it through the ordinary turn queue. The turn gets automation provenance and a trusted or untrusted origin marker, then uses the same runner, tools, approvals, checkpoints, transcript, and inference path as an interactive prompt.
At startup, the host reconciles definitions, rearms pending wakes, and retries acknowledgements that did not complete. During upgrade, it suspends new scheduler wakes while backend events remain queued for the replacement process. Deleting a named agent also deletes its schedules.
There is no separate "automation agent runtime." Automation is another producer of durable turns.
The captured /dev/vda was a 128 GiB ext4 container filesystem. It had no partition
table, boot, or kernel, so it could not boot as a VM. The clone uses a Debian
12 x86-64 wrapper disk to supply the missing operating-system pieces.
Apple Silicon Mac
βββ QEMU x86-64 with TCG translation
βββ writable Debian 12 wrapper disk
βββ captured ext4 disk attached read-only
βββ reconstructed Docker overlay
βββ 66 captured lower layers, read-only
βββ /var/lib/grok-clone/upper, writable
βββ /mnt/grok-container, merged chroot
grok-clone-mount.service reconstructs the overlay and mounts /proc, /dev, and
/sys into the merged tree. grok-pod-daemon.service runs the captured /tini and
pod-daemon. grok-supervisor.service reads the protected captured environment,
enters the chroot, drops to UID and GID 1000, and executes the original Node runtime
and sand-supervisor.mjs.
The original evidence disk remains read-only. Local transcripts and runtime changes
land in /var/lib/grok-clone/upper. This design preserves the capture while giving
the restored application a writable filesystem.
The supervisor environment contains credential-bearing state and is stored as a
root-owned mode 0600 NUL-separated file. The launcher reads it before chroot,
sets the box identity, drops privileges, and passes it directly to the process. The
scripts do not print the values.
At the 2026-08-18 runtime audit, the clone had the restored named agents, gateway, transcripts, external inference, pod-daemon, window router, and several desktop components. Single-turn and multi-turn conversations worked. The audit did not prove full platform parity. The main exec daemon, per-window exec daemons, PTY WebSockets, session sync, cookie persistence, and one desktop were missing or not validated at that capture.
Current clone-lab scripts have continued to change after that audit. For example, the current window-router launcher deliberately points its primary route at local port 1337, while the noVNC bridge maps restored display 4 to both historical and local tokens. Those scripts express the intended current topology. They do not, by themselves, prove that every daemon is running in a live VM now.
QEMU uses software CPU translation because the guest is x86-64 and the Mac is Arm. Short turns work, but CPU-heavy tool runs can starve the emulated gateway. Running the disks on an x86-64 KVM host would preserve the binaries and remove most of that translation cost.
The clone lab keeps the original gateway address stable while allowing a local VM
to serve requests. A streaming proxy on the original box selects either the
original host-main.cjs or an SSH path to the local clone.
client
-> original stable address :1340
-> firewall redirect :21341
-> streaming gateway proxy
+-> original host-main :1340
`-> reverse SSH :21340
-> Mac forward :31340
-> local VM host-main :1340
An authenticated SSE connection pins the selected backend. Concurrent commands use the same backend while that event stream is open. This affinity prevents a client from sending a prompt to the local transcript while listening for its result on the original host.
Failover is active/passive. It never mirrors a mutating request and never replays a request that may have been partially sent. Both gateway processes may be alive, but only one receives a given client session. This rule matters because both copies use the same logical agent IDs. Mirroring would create duplicate tool actions and divergent transcripts.
Gateway failover covers the HTTP and SSE service on port 1340. It does not automatically cover pod-daemon, exec ConnectRPC, PTY WebSockets, window routing, noVNC, raw VNC, Chrome CDP, Docker, or unknown provider services. Gateway parity is not platform parity.
The system relies on layered capabilities rather than one universal login:
- The external gateway checks browser origin and bearer authentication.
- Internal execution RPC checks a daemon bearer token.
- Fork-window routes require a display and owner token.
- Model access uses a short-lived token held by the host.
- Shell and MCP actions pass policy and approval checks.
- The sandbox constrains filesystem and network access when the platform supports enforcement.
- The VM or container remains the final boundary for same-user processes, X11, loopback services, and a browser launched without its own kernel sandbox.
The observed original box also exposed an unauthenticated Docker HTTP API on port 2375 and an unidentified plaintext gRPC listener on port 50052. Neither belongs in a safe public clone. Docker API access is close to container-administrator access. The unknown service must remain blocked until its owner and authentication contract are identified.
Raw VNC was loopback-only and had no VNC password. Its protection came from network reachability and the SSH or noVNC boundary. CDP, daemon tokens, owner-token files, process environments, and X sockets also need loopback binding or stronger OS isolation.
Several mechanisms combine to make the product look like one persistent agent:
- The gateway accepts commands fast and SSE streams every later state change.
- Durable named agents retain transcripts, profiles, memory, workflows, and box state across turns and host restarts.
- Step checkpoints let approvals, secret requests, widgets, cancellations, and upgrades without restarting the entire turn.
- Task children work in the background and wake the parent when they finish.
- Persistent shells, MCP processes, browser profiles, cookies, and desktops let tools continue where an earlier turn stopped.
- Automations enter the same queue as user prompts, so unattended work follows the same persistence and policy rules.
- Active/passive routing keeps commands and events on one stateful gateway copy.
The apparent single bot is therefore a coordinated set of state machines. The
conversation, model stream, Task children, approval request, shell, desktop, and
automation can each be in a different state. SandHost joins them through stable
identities, checkpoints, event fanout, and explicit ownership.
client opens /events
client sends sendPrompt with clientNonce
gateway authenticates and durably accepts
transcript manager emits the user message
runner restores context and builds the prompt
inference streams text
runner checkpoints and persists the assistant message
SSE delivers transcript changes to the client
model proposes Shell
host and execution policy inspect the exact command
review requires the user
runner checkpoints and emits an approval request
client resolves it through the gateway
runner resumes
exec-daemon runs the command under the computed sandbox policy
typed output returns to the model
model finishes and the transcript settles
parent calls Task(type=browserUse)
parent-context review accepts the delegation
host creates child runner and child transcript identity
child receives browser tools and a routed Chrome session
child works while parent is suspended on a pending wake
child result and outline are stored
host revives the parent
parent reads the result and answers the user
host loads automation definitions
trigger hub rearms an unfulfilled wake
wake enters the named agent's ordinary queue
runner marks automation provenance in the prompt
turn uses the normal inference, tools, approvals, and checkpoints
result is persisted and acknowledgement is retried until settled
The main source roots used for this explanation are:
- Gateway and composition:
src/host/main.ts,sand-host.ts,gateway-server.ts,gateway-protocol.ts, andhost-gateway-api.ts. - Turns:
src/host/extensions/transcript/transcript-manager.ts,turn-runtime.ts,src/host/runner/sand-agent-runner.ts,turn-run-shell.ts, andprompt-collector-glue.ts. - Task children:
src/host/runner/subagent-runtime.ts,turn-agent-composition.ts, andtools/sand-subagent-management-tools.ts. - Inference:
src/host/extensions/auth/,src/host/extensions/inference/, andpackages/chat-inference-proto/dist/. - Execution:
exec-daemon/src/,packages/agent-exec/dist/,packages/local-exec/dist/, andpackages/shell-exec/dist/. - Persistence:
src/host/extensions/session/,src/host/agent-isolation/,src/host/extensions/content-search/, andsrc/host/extensions/box-store-sync/. - Exact deployment scripts:
exact-runtime-source/runtime/.
Operational VM and failover claims come from wtfsayo/grok-bot-clone-lab at
commit 2b1c877038b56a35b7643bf5082ae88a60f7b685, especially
docs/GROK-BOT-CLONE-HANDBOOK.md, docs/GROK-BOT-DAEMONS-AND-INGRESS.md,
systemd/, and failover/. Those documents sanitize tokens, private addresses,
agent IDs, transcripts, and disk locations.
The recovered system does not include the hosting provider's external control plane, the original host's vsock service, or a bootable source disk. Some native components can be described only through symbols, protocols, literals, call graphs, and disassembly because their source and debug metadata were absent.
The reconstruction is still enough to explain the application architecture with high confidence: a durable host owns conversation semantics, a gateway owns client transport, an inference service owns model transport and tokens, an execution daemon owns operating-system effects, and supervisors keep the box and its desktops alive. The Grok Bot experience appears when those parts share identities, checkpoints, and events without sharing more authority than each part needs.