app
Grok Bot
Public Made by Adomby adom
Grok Bridge lets Adom talk to Grok Bot. Adom's AI environment is for electrical engineers: any provider, any desktop power tool, one place.
main
John Lauer
v1.3.15 (insiders): Second route and wake for Grok's agent computer: grok_chat_send types into the grok-bridge chat through UIA when the webhook is refused, grok_wake keeps the paused agent computer running for N minutes, and Grok's rate-limit refusal reports its limit and count.
b702936
5d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
"""grok_describe — machine-readable verb catalog (hint / related / pitfalls)."""
from __future__ import annotations
PREFIX = "grok_"
# Keyed by the INTERNAL (unprefixed) command name.
VERB_CATALOG = {
"readiness": {
"summary": "Read-only: is Grok Bot.exe installed / running? Cursor is last-resort fallback.",
"long": False,
"hint": "Zero side effects, never downloads. Branch on hostAppInstalled / hostAppRunning / hostAppFallback / errorCode host_app_not_installed. When running, also computerState / computerReachable (false = Grok Bot shows Couldn't Reach Grok Bot's Computer).",
"related": ["grok_prewarm", "grok_open", "grok_status"],
"pitfalls": [
"ready=false is NOT a user-download. Offer grok_open.",
"hostAppFallback:Cursor means Grok Bot.exe is missing — do not kill Cursor.",
"Do not treat a yellow /status chip as a crash — the bridge is up, Grok Bot isn't.",
],
},
"prewarm": {
"summary": "No-op re-detect. {wait:true} just re-detects; nothing to fetch.",
"long": False,
"hint": "Grok Bot is a host app, not a runtime asset. Cheap enough to call anytime.",
"related": ["grok_readiness", "grok_open"],
"pitfalls": ["wait:true does not install Grok Bot or steal focus"],
},
"describe": {
"summary": "This catalog — every grok_* verb with hint/related/pitfalls.",
"long": False,
"hint": "Completeness escape hatch. In practice read the per-call _hint.",
"related": ["grok_readiness", "grok_status"],
"pitfalls": ["the catalog is static; live state is grok_readiness / grok_status"],
},
"status": {
"summary": "Detect + last grok_send + inbox path + webhook bound (host only, never the key).",
"long": False,
"hint": "Use this after a send to confirm the durable inbox got the line.",
"related": ["grok_send", "grok_readiness", "grok_webhook_status"],
"pitfalls": ["lastSend is in-process; a bridge restart clears it (inbox file survives)"],
},
"open": {
"summary": "Launch Grok Bot in the BACKGROUND if installed. Polls process/window; Start-Process minimized fallback.",
"long": True,
"hint": "Returns launched, opened, alreadyOpen, hwnd. Polls process_list/window after launch/desktop_open; Start-Process -WindowStyle Minimized if those do not take. Never steals focus. Every launch carries --force-renderer-accessibility and the no-occlusion switches so a background window paints and is readable. {restart:true, reason} relaunches a Grok Bot that was started without them (launchedWithAccessibility:false, e.g. after its own auto-update).",
"related": ["grok_list_windows", "grok_screenshot", "grok_close", "grok_readiness"],
"pitfalls": [
"success:true requires a live process/window after poll — not just callback ok.",
"Background by default. foreground:true needs foregroundReason >= 10 chars.",
"Host is Grok Bot.exe, not Cursor. Cursor is last-resort fallback only.",
"cliRequired verbs (shell_execute, pull_file, send_files) are never used here.",
],
},
"screenshot": {
"summary": "Screenshot a Grok Bot window via ab desktop_screenshot_window.",
"long": False,
"hint": "Captures the picked MAIN window by hwnd (largest visible Grok Bot window, never one under 400x300); explicit titleContains only when you pass it. main_window_hidden when the main window is hidden (a hidden window cannot be captured; showing it takes focus, so only grok_open {foreground:true, foregroundReason}). grok_chat_read still reads it hidden. Does not raise the window.",
"related": ["grok_list_windows", "grok_open", "grok_record_start"],
"pitfalls": [
"Needs a live window — grok_open first if hostAppRunning is false.",
"The PNG lands on the desktop; pull it with the CLI, not from this HTTP callback.",
],
},
"list_windows": {
"summary": "List Grok Bot windows (desktop_find_window preferred, then list_windows + process_list).",
"long": False,
"hint": "titleContains exact Grok Bot (not bare Grok / Chrome ai-grok-bot). Read-only; does not focus or click.",
"related": ["grok_screenshot", "grok_open", "grok_chat_status", "grok_close", "grok_resize"],
"pitfalls": [
"empty list usually means Grok Bot isn't running — grok_open, don't panic",
"Do not treat Google Chrome / ai-grok-bot as the host.",
],
},
"chat_status": {
"summary": "Read-only: is the focused Grok Bot thread thinking or idle? Never steals focus.",
"long": False,
"hint": "thinking=true when UIA exposes a name like \"<agent> is working\" (proven: \"New Bot is working\"). idle when not thinking. Carries computerState / computerReachable. errorCode no_transcript (window has no page yet) or computer_unreachable answer at once.",
"related": ["grok_chat_read", "grok_list_windows", "grok_screenshot"],
"pitfalls": [
"focusedThread null + focusedThreadReason when the page has no conversation heading; never a caption-button name.",
"Needs a live Grok Bot window — grok_open first.",
"Never steal focus. UIA first, not OCR, never CDP 9222.",
"Do not treat Google Chrome / ai-grok-bot as the host.",
],
},
"chat_read": {
"summary": "Read the visible transcript of the focused Grok Bot thread (UIA Document). Returns focusedThread.",
"long": False,
"hint": "desktop_ui_text {hwnd, role:Document, range:all}. Optional thread/agent clicks that sidebar row then re-reads. Optional limit is CHARACTERS from the END (not messages; values under 500 are coerced). Returns focusedThread + agent + computerState. errorCode no_transcript (blank window, answered at once with visibleText) or computer_unreachable. Never returns webhook keys.",
"related": ["grok_chat_status", "grok_list_windows", "grok_send", "grok_open"],
"pitfalls": [
"After cold launch the focused thread may not be grok-bridge — pass thread/agent or wait after grok_open.",
"Visible transcript only, not a full history API.",
"limit is CHARACTERS from the end, not messages. limit:20 will miss a nonce. Use 4000+.",
"Do not treat Prompt compose-box garbage as a message.",
"Never echo webhook keys. Never OCR-first. Never CDP 9222.",
],
},
"send": {
"summary": "Queue a message to Grok Bot: toast + durable inbox. Typing is opt-in.",
"long": False,
"hint": "grok_send {\"message\":\"...\", \"agent\"?: \"...\"}. notify_user toast AND ~/.adom/grok-inbox.jsonl. Does NOT type into the chat unless the caller opts in — don't steal the keyboard.",
"related": ["grok_status", "grok_list_windows", "grok_open"],
"pitfalls": [
"queued:true is notify+inbox, not proof the chat widget received it.",
"Desktop typing is opt-in. Default is toast + inbox.",
"The Anywhere character polls the inbox; cloud AIs should still --ai-thread.",
],
},
"uninstall": {
"summary": "Tell the caller to bridge_uninstall {name:grok}. Does not kill Grok Bot or Cursor.",
"long": False,
"hint": "adom-bridge bridge_uninstall '{\"name\":\"grok\"}'. Skills: ./uninstall.sh.",
"related": ["grok_status"],
"pitfalls": ["never kills Grok Bot.exe or Cursor.exe — those are the user's apps"],
},
"close": {
"summary": "Hide the Grok Bot window (desktop_set_window_state hide). Never process_kill Cursor.",
"long": False,
"hint": "Prefer hide over kill. Returns closed:true. grok_open to show it again.",
"related": ["grok_open", "grok_list_windows", "grok_resize"],
"pitfalls": [
"Does not kill Grok Bot.exe or Cursor.exe.",
"Will not hide a generic Cursor IDE window even on fallback.",
],
},
"resize": {
"summary": "desktop_set_window_bounds on the Grok Bot hwnd. Physical px (same space as ab).",
"long": False,
"hint": "grok_resize {w, h, x?, y?}. Restores first if maximized. Omitting x,y keeps the current origin.",
"related": ["grok_list_windows", "grok_screenshot", "grok_open"],
"pitfalls": [
"w and h are required. Units are ab physical pixels, not DIPs.",
"Background — does not steal focus.",
],
},
"record_start": {
"summary": "desktop_record_window_start on the Grok Bot hwnd. reason required.",
"long": True,
"hint": "grok_record_start {\"reason\":\"...\"}. Background WGC. Stop with grok_record_stop.",
"related": ["grok_record_stop", "grok_record_status", "grok_screenshot"],
"pitfalls": [
"reason is required and is passed through.",
"The mp4 lands on the desktop; pull it with the CLI, never pull_file from this HTTP callback.",
],
},
"record_stop": {
"summary": "desktop_record_window_stop wrap.",
"long": False,
"hint": "Optional recordingId. File is on the desktop.",
"related": ["grok_record_start", "grok_record_status"],
"pitfalls": ["does not pull the file — use the adom-bridge CLI"],
},
"record_status": {
"summary": "desktop_record_window_status wrap.",
"long": False,
"hint": "Poll after grok_record_start.",
"related": ["grok_record_start", "grok_record_stop"],
"pitfalls": [],
},
"login": {
"summary": "Open Grok Bot settings (grokbot://app/v1/settings?id=theme) in the BACKGROUND. No passwords.",
"long": False,
"hint": "Human clicks Sign In with Cursor on the account card. This verb never types credentials.",
"related": ["grok_logout", "grok_open"],
"pitfalls": [
"Do not type passwords or 2FA.",
"Only grokbot:// settings?id=* and plugin/add?id= routes exist in v1.2.",
],
},
"logout": {
"summary": "Open settings; try background UIA Sign Out. Else needsHuman:true.",
"long": False,
"hint": "If Sign Out is not background-actionable, the human clicks Sign Out on the account card.",
"related": ["grok_login", "grok_open"],
"pitfalls": [
"Never invent UI paths beyond sidebar account button / Sign In with Cursor / Sign Out.",
"needsHuman:true is success, not a crash — surface _hint.",
],
},
"plugin_install": {
"summary": "Open grokbot://app/v1/plugin/add?id=<id>. Does not confirm install (the app UI does).",
"long": False,
"hint": "id required. Launches Grok Bot.exe with grokbot://app/v1/plugin/add?id=<id> as an arg (desktop_open_url refuses grokbot://).",
"related": ["grok_open", "grok_login"],
"pitfalls": ["does not confirm or wait for install", "id is required"],
},
"webhook_status": {
"summary": "Whether ~/.adom/grok-webhook.json has a url. Returns bound + urlHost (never the key).",
"long": False,
"hint": "Key is never logged or returned. Prefer grok_webhook_ensure to read the routine pane.",
"related": ["grok_webhook_ensure", "grok_webhook_bind", "grok_bot_list"],
"pitfalls": ["never echo the sender key", "bound:false → grok_webhook_ensure first"],
},
"webhook_ensure": {
"summary": "Scrape the Grok Bridge webhook routine pane (UIA Edit Webhook URL / Webhook key) and bind locally. No human copy-paste.",
"long": True,
"hint": "grok_webhook_ensure {}. Opens Open routine Grok Bridge webhook, expands When a webhook fires, reads Edit values, writes ~/.adom/grok-webhook.json. Never returns the key. force:true re-scrapes.",
"related": ["grok_webhook_status", "grok_webhook_fire", "grok_bot_create"],
"pitfalls": [
"Needs a live Grok Bot window.",
"Never echo the sender key.",
"Do not ask a human to copy the URL/key — this verb is the auto-setup.",
],
},
"webhook_bind": {
"summary": "Write ~/.adom/grok-webhook.json {url, key, header, boundAt}. url must be https. key required.",
"long": False,
"hint": "Manual bind. Prefer grok_webhook_ensure {} which reads UIA Edits Webhook URL / Webhook key.",
"related": ["grok_webhook_ensure", "grok_webhook_status", "grok_webhook_fire"],
"pitfalls": [
"url must be https.",
"The key is stored locally and never put in _hint or logs.",
],
},
"webhook_ensure": {
"summary": "Read the Grok Bridge webhook routine pane via UIA Edits and write ~/.adom/grok-webhook.json.",
"long": False,
"hint": "Clicks \"Open routine Grok Bridge webhook\", expands \"When a webhook fires\" if needed, reads Edit names Webhook URL / Webhook key / Authorization header. No OCR. Never echoes the key.",
"related": ["grok_webhook_status", "grok_webhook_bind", "grok_bot_list"],
"pitfalls": [
"Settings gear is NOT the Routines list.",
"Do not type into Prompt (clear leftover garbage; do not submit).",
"ListItem \"When a webhook fires\" is not invokable — prefer the Button, else click its center.",
"Never log or return the sender key.",
],
},
"chat_send": {
"summary": "Second route to the grok-bridge agent: type a message into the user's grok-bridge chat through UIA (no focus steal) and press Send message.",
"long": False,
"hint": "grok_chat_send {message, reason, thread?=grok-bridge}. Use when grok_webhook_fire is refused (webhook_throttled). Every message carries '[from AI thread \"<name>\" via grok-bridge, not typed by John]'. Refuses with prompt_busy if the user has a draft in the box. Shares the webhook's per-thread / per-PC budget. Needs the main window visible.",
"related": ["grok_webhook_fire", "grok_chat_read", "grok_wake"],
"pitfalls": ["The message shows in the user's own chat as theirs, with the AI prefix: not a way to fake the user's approval.", "Each message starts an agent run and costs Grok usage."],
},
"wake": {
"summary": "Keep Grok's agent computer running for N minutes (it pauses a few minutes after each agent run).",
"long": False,
"hint": "grok_wake {minutes?=10 (max 30), reason}. Starts an agent run that only sleeps, via the webhook (chat fallback when throttled). The box rejoins the mesh within about a minute; check adom-bridge targets. Costs Grok usage per wake.",
"related": ["grok_webhook_fire", "grok_chat_send"],
"pitfalls": ["No Grok Bot setting keeps the computer awake (checked 2026-10-15).", "Wake shortly before you need the box, not in a loop."],
},
"activity": {
"summary": "Who called which grok_* verb on this PC, when, and what came back; webhook fires, throttles and the shared budget.",
"long": False,
"hint": "grok_activity {minutes?=60, verb?, thread?, limit?=40}. Reads ~/.adom/grok-bridge-activity.jsonl (one line per call: ts, caller thread, verb, ms, ok, errorCode, httpStatus, event, nonce, runUuid). webhookBudget shows fires in the last minute per thread and any Grok cooldown.",
"related": ["grok_webhook_fire", "grok_webhook_status"],
"pitfalls": ["Per PC: each PC running grok-bridge has its own log and budget.", "Never contains webhook keys or message text."],
},
"webhook_fire": {
"summary": "POST {event, payload, source:grok-bridge, agent?} to the bound url. Auth is Authorization: Bearer, never a body key.",
"long": False,
"hint": "Optional agent (name or id) as args.agent or payload.agent — grok-bridge relays into that teammate and pastes the reply into its own thread. Header Authorization: Bearer <key>. errorCode webhook_not_bound if unbound — grok_webhook_ensure first. requireApproval:true + approvalSummary raises an Allow/Deny toast on the user's PC, fires only on Allow and stamps payload.approval (caller-supplied approval fields are stripped). The verb budget is 300 s (bridge.json timeouts). Shared mailbox: 6 fires/min per PC, 3/min per thread; errorCode webhook_throttled (throttledBy thread-budget | pc-budget | grok, retryAfterSeconds) means NOT sent: wait, never loop. After a Grok 429 the PC holds all fires for Retry-After.",
"related": ["grok_webhook_ensure", "grok_bot_create", "grok_channel_create", "grok_bot_list"],
"pitfalls": [
"A JSON field named key is WRONG — auth is a header.",
"Never log the sender key.",
"There is still one mailbox (the Grok Bridge webhook routine). agent is a relay, not a second webhook.",
"HTTP 200 is only a runUuid (now also a top-level runUuid field). Poll grok_chat_read for payload.nonce.",
],
},
"run_status": {
"summary": "Echo last grok_webhook_fire runUuid (in-process). No public run HTTP API.",
"long": False,
"hint": "grok_run_status {runUuid?}. Returns last fire runUuid/event/httpStatus. Poll grok_chat_read for the answer.",
"related": ["grok_webhook_fire", "grok_chat_read"],
"pitfalls": [
"Clears if the grok-bridge process restarts.",
"Never logs the webhook key.",
],
},
"bot_create": {
"summary": "Webhook event=create_bot. {name, description?}. Needs grok_webhook_bind first.",
"long": False,
"hint": "If unbound: errorCode webhook_not_bound — grok_webhook_ensure {} first.",
"related": ["grok_webhook_ensure", "grok_bot_list", "grok_channel_create"],
"pitfalls": ["name required", "does nothing local if webhook_not_bound"],
},
"channel_create": {
"summary": "Webhook event=create_channel. {name, member_ids?}.",
"long": False,
"hint": "Same bind requirement as grok_bot_create.",
"related": ["grok_webhook_ensure", "grok_bot_create"],
"pitfalls": ["name required", "errorCode webhook_not_bound if unbound"],
},
"bot_list": {
"summary": "Webhook event=list_bots (cloud agent lists agents).",
"long": False,
"hint": "If unbound: errorCode webhook_not_bound.",
"related": ["grok_webhook_ensure", "grok_bot_create"],
"pitfalls": ["errorCode webhook_not_bound if unbound"],
},
"settings": {
"summary": "Open a Grok Bot Settings page: general / computer / usage (plan + limits) / updates. Background.",
"long": False,
"hint": "grok_settings {page}. usage answers 'what plan am I on / what am I paying'. Then grok_screenshot.",
"related": ["grok_screenshot", "grok_login"],
"pitfalls": ["The overlay covers the chat; close it before typing a prompt."],
},
"install": {
"summary": "Install Grok Bot on this PC from its public update feed. Background job, per-user, no admin, no login.",
"long": True,
"hint": "grok_install {force?}. Resolves the current installer for this OS/arch from api2.cursor.sh/updates, downloads it (~120 MB), checks Authenticode Anysphere (Windows) or the feed sha256 (Linux), then installs silently per-user. Returns at once; poll grok_install_status.",
"related": ["grok_install_status", "grok_readiness", "grok_open", "grok_login"],
"pitfalls": [
"Already installed returns alreadyInstalled:true and does nothing unless force:true.",
"Sign-in is still a human step afterwards (grok_login); this never types credentials.",
"Never send the user to a download page; this verb is the install path.",
],
},
"install_status": {
"summary": "Progress of the grok_install job: resolving / downloading (percent) / installing / done / failed.",
"long": False,
"hint": "Poll about every 10 s. done -> grok_open {}. failed -> read error; a signature/sha256 rejection is not retryable.",
"related": ["grok_install", "grok_readiness"],
"pitfalls": ["Job state is in-process; a bridge restart resets it to idle (grok_readiness still tells the truth)."],
},
"computer_screenshot": {
"summary": "Fire screenshot_computer, wait until the nonce is in grok-bridge, then thumbnail Grok Bot.exe. Screenshots grok-bridge's computer (the agent box), not Grok Bot.exe.",
"long": True,
"hint": "grok_computer_screenshot {nonce?, timeoutSeconds?}. Mints a unique BOX-SHOT-XXXX-NNNN nonce if omitted. Waits (default 180s) for that nonce in grok_chat_read. Do not bash-poll. Do not reuse a nonce.",
"related": ["grok_webhook_fire", "grok_chat_read", "grok_screenshot"],
"pitfalls": [
"This is NOT grok_screenshot of Grok Bot.exe.",
"Do not click the monitor icon — that is the same window grok_screenshot already covers.",
"Do not poll grok_chat_read yourself — this verb waits.",
"Never reuse a nonce; omit nonce to mint BOX-SHOT-XXXX-NNNN.",
],
},
}
def handle_describe(_args: dict) -> dict:
verbs = []
for cmd, meta in VERB_CATALOG.items():
entry = {
"name": PREFIX + cmd,
"summary": meta["summary"],
"hint": meta.get("hint", ""),
"related": meta.get("related", []),
"pitfalls": meta.get("pitfalls", []),
"longRunning": bool(meta.get("long")),
}
if meta.get("long"):
entry["statusVerb"] = PREFIX + "readiness"
verbs.append(entry)
verbs.sort(key=lambda v: v["name"])
names = [v["name"] for v in verbs]
return {
"success": True,
"prefix": PREFIX,
"verbCount": len(verbs),
"commands": names,
"commandNames": names,
"verbs": verbs,
"_hint": (
"Full grok_* catalog. names are grok_* in commands / commandNames / verbs[].name (JSON — grep those keys, not adom-bridge commands unprefixed internals). "
"Every verb ALSO returns its own rich _hint when called; that's what to read in practice. "
"Host app is Grok Bot.exe (Cursor last-resort fallback). "
"Drive the app: grok_open / grok_close / grok_resize / grok_screenshot / grok_record_start. "
"Chat: grok_chat_status / grok_chat_read (UIA, no focus steal). "
"Bots/channels: grok_webhook_ensure then grok_bot_create / grok_channel_create / grok_bot_list. Computer shot: grok_computer_screenshot {} (not grok_screenshot). "
"CLI: adom-bridge grok_* . Always --ai-thread. Background by default."
),
}