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.
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-bridgeCLI, the relay //commandpassthrough (relays your response VERBATIM incl._hint/errorCode/statusVerb), bridge lifecycle (bridge_install/ streaming this bridge into…\bridges-cache\grok, the stable port, supervisor), and genericdesktop_*/notify_user/launchverbs this runtime calls back throughcaller_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, thegrok_describecatalog, thegrok+grok-anywhereskills,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, bindADOM_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 throughad_callback. Nevershell_execute/pull_file/send_filesfrom 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'supdateManifestUrlpoints at; itsurlis the RELEASE download URL of the zip, with matchingsha256/size.SKILL.md(root) — core USER skill, installed asgrok(notgrok-bridge).skills/grok-anywhere|app-control|chat|record|webhook|account/— USER sub-skills (in the pkg).dev-skills/grok-dev/anddev-skills/grok-publish/— repo only, not infiles[].package.json— wiki skills pkg. Description is the skills-not-runtime sentence. Runtime files and*.zipdo not belong infiles[].
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
.zipis a RELEASE asset, never a git file.*.zipis gitignored. sha256/sizein the manifest MUST match the served release asset orbridge_installrejects it.- Never hand-edit the bridges-cache. Edit here, publish.
- Never tell the user to download Grok Bot / Cursor.
grok_installinstalls it (public feedapi2.cursor.sh/updates/api/update/<platform>/sand/0.0.1/0/stable, Authenticode Anysphere / sha256 gated);grok_openlaunches. - Never kill Cursor. Prefer hide (
grok_close) overprocess_kill. - Background by default. Don't steal focus or the keyboard.
grok_sendis toast + inbox. - Repo name ≠ skill name. Install as
grok. - Do not invent grokbot:// routes other than
settings?id=*andplugin/add?id=.
# 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 `_hint`s, 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=`.