main
History Download
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

CLAUDE.md — grok-bridge (READ THIS, it is YOUR project)

This repo is the Grok Bot ("grok") bridge — the canonical source of truth, published to wiki.adom.inc/adom/grok-bridge. If you are an Adom AI touching anything grok / grok_* / Grok Bot / Grok Bot.exe-as-host, you own and maintain this code here. Bridge (ab) will seed/stream the runtime from the release zip via updateManifestUrl in bridge.json.

You vs adom-bridge (ab) core — the boundary

  • ab core owns: the adom-bridge CLI, the relay / /command passthrough (relays your response VERBATIM incl. _hint/errorCode/statusVerb), bridge lifecycle (bridge_install / streaming this bridge into …\bridges-cache\grok, the stable port, supervisor), and generic desktop_* / notify_user / launch verbs this runtime calls back through caller_identity.ad_callback. Do not edit /home/box/project/adom_modules/adom/adom-bridge (ab-core) from this repo.
  • YOU (this bridge) own: every grok_* verb + its response _hints, Grok Bot host-app detect (grok_detect.py; Cursor is last-resort fallback only if Grok Bot.exe is missing), the status-chip fields on /status, the grok_describe catalog, the grok + grok-anywhere skills, install.sh, and the edit → zip → release-upload → reinstall loop.
  • So: a grok_* verb misbehaves, a hint is missing, Grok Bot detect lies, the chip lies → it's your code, fix it here. It is NOT an ab-core request. If a GENERIC ab capability is missing (a new lifecycle verb), file that against ab — don't re-absorb the bridge.

Map of what you manage

  • server.py — ThreadingHTTPServer, bind ADOM_BIND_HOST (loopback only), --port, POST {command, args}, GET /status + /health. Keep it small (~250-400 lines).
  • grok_detect.py — Grok Bot.exe / Grok Bot.app / grok-bot + running probe. Cursor fallback only when Grok Bot.exe is missing (hostAppFallback:"Cursor").
  • caller_identity.py — copy of kicad's; DELEGATE = "grok". All ab callbacks go through ad_callback. Never shell_execute / pull_file / send_files from the HTTP path.
  • handlers/*.py — readiness, describe, windows (open/screenshot/list), chat (status/read), send, app (close/resize/record/login/logout/plugin), webhook, bots.
  • bridge.json + BRIDGE_VERSION — KEEP IN LOCKSTEP (tools/ship.sh does it).
  • adom-bridge-grok-manifest.json — streaming manifest ab's updateManifestUrl points at; its url is the RELEASE download URL of the zip, with matching sha256/size.
  • SKILL.md (root) — core USER skill, installed as grok (not grok-bridge).
  • skills/grok-anywhere|app-control|chat|record|webhook|account/ — USER sub-skills (in the pkg).
  • dev-skills/grok-dev/ and dev-skills/grok-publish/ — repo only, not in files[].
  • package.json — wiki skills pkg. Description is the skills-not-runtime sentence. Runtime files and *.zip do not belong in files[].

Verbs

Existing: grok_readiness grok_prewarm grok_describe grok_status grok_open grok_screenshot grok_list_windows grok_chat_status grok_chat_read grok_send grok_uninstall.

App: grok_close grok_resize grok_record_start grok_record_stop grok_record_status grok_login grok_logout grok_settings grok_plugin_install.

Window picking: _is_host_impostor rejects ANY browser window (Edge/Chrome/Firefox/...), since sign-in tabs are titled "Sign in to Grok Bot"; exact title "Grok Bot" ranks first.

Webhook: grok_webhook_status grok_webhook_ensure grok_webhook_bind grok_webhook_fire grok_bot_create grok_channel_create grok_bot_list.

Install (1.3.0): grok_install {force?} background job + grok_install_status. See handlers/install.py. grok_webhook_ensure scrapes UIA Edit Webhook URL / Webhook key (no human copy-paste). grok_webhook_fire optional agent / payload.agent (name or id) relays into that teammate.

Agent-box state (1.3.3, wiki #5): handlers/chat.py page_probe / probe_computer read the Document once (8 s per UIA callback, 15 s budget) and report computerState / computerReachable from the "Couldn't Reach Grok Bot's Computer" page. chat_read / chat_status answer at once with no_transcript or computer_unreachable; focusedThread is never a caption button. readiness, webhook_fire (warning) and computer_screenshot (refuses) use it.

Launch switches (1.3.4): HOST_FLAGS in handlers/windows.py go on every launch. Without them a background Grok Bot window never paints and UIA sees only caption buttons. Grok Bot's auto-update relaunch drops them; host_launch_flags_ok() spots that and grok_open {restart:true, reason} fixes it.

Windows + approval (1.3.5, wiki #5 items 5-6): pick_grok_window skips strays (< 400x300), takes the largest, remembers the main hwnd in ~/.adom/grok-main-window.json; main_window_hidden when hidden; chat verbs read it in place by hwnd (read_target_hwnd), and grok_open re-shows it only with foreground+foregroundReason (ab's show activates; there is no show-without-activate). grok_webhook_fire {requireApproval, approvalSummary} waits on a notify_user Allow/Deny toast and stamps payload.approval; caller-supplied approval fields are always stripped.

Activity + governor (1.3.13): handlers/activity.py. server.py logs every verb call to ~/.adom/grok-bridge-activity.jsonl (ts, caller, verb, ms, result fields; never keys/text; 5 MB rotation) and stamps text-log lines with time. grok_webhook_fire passes activity.admit() (6/min per PC, 3/min per thread, overridable in ~/.adom/grok-bridge-settings.json) and, after a Grok 429, a shared cooldown (~/.adom/grok-webhook-cooldown.json, Retry-After or 60 s doubling to 300 s). grok_activity reads it. probe_computer is cached 30 s because Hydrogen polls readiness thousands of times a day.

Chat route + wake (1.3.15, wiki #8-#10): handlers/compose.py. grok_chat_send sets the Prompt Edit (desktop_ui_set text) and invokes the "Send message" button, refuses on a user draft, always prefixes [from AI thread "..." via grok-bridge, not typed by John], shares activity.admit's budget. grok_wake {minutes<=30, reason} asks the agent to sleep, because the agent computer suspends between runs and Grok Bot has no keep-awake setting. A Grok rate-limit 400 parses rateLimitPerMinute / currentCount and suggests chat_send.

Webhook bind file: ~/.adom/grok-webhook.json {url, key, header, boundAt} (never log the key). grok_webhook_ensure reads UIA Edits Webhook URL / Webhook key (no OCR).

The publish loop: insiders first, public on a human's words (wiki #2)

tools/ship.sh <ver> "<changelog>" does all of it: lockstep bump (BRIDGE_VERSION, bridge.json, package.json) → zip the runtime at zip root → pkg publish --org adom (same version, so the top version row has a tarball) → release upload on adom/grok-bridge → insiders manifest at adom/insiders grok-bridge/version.json + a release-log entry in grok-bridge/README.md ("Not promoted") → push source + skills to this page. The public manifest adom-bridge-grok-manifest.json is NOT touched.

tools/promote.sh <ver> "<the human's exact words>" --by "<name>" is the only way the public manifest moves. It refuses without the words and records them in the manifest. Never promote on your own judgment.

Desktops on ab >= 2.0.99 follow insidersManifestUrl when the login can read adom/insiders. A desktop whose installed bridge.json predates the field needs one bootstrap: adom-bridge --target <box> bridge_install '{"manifestUrl":"https://wiki.adom.inc/api/v1/pages/insiders/files/grok-bridge/version.json","force":true}'. Other threads ship this bridge too: check adom-wiki repo log adom/grok-bridge right before shipping.

Hard rules

  • The .zip is a RELEASE asset, never a git file. *.zip is gitignored.
  • sha256/size in the manifest MUST match the served release asset or bridge_install rejects it.
  • Never hand-edit the bridges-cache. Edit here, publish.
  • Never tell the user to download Grok Bot / Cursor. grok_install installs it (public feed api2.cursor.sh/updates/api/update/<platform>/sand/0.0.1/0/stable, Authenticode Anysphere / sha256 gated); grok_open launches.
  • Never kill Cursor. Prefer hide (grok_close) over process_kill.
  • Background by default. Don't steal focus or the keyboard. grok_send is toast + inbox.
  • Repo name ≠ skill name. Install as grok.
  • Do not invent grokbot:// routes other than settings?id=* and plugin/add?id=.