{"owner":"ComposioHQ","repo":"agent-orchestrator","hasSkills":true,"totalSkillsCount":73,"totalTokensCount":36708,"categories":["anthropic-skill","root-instruction","claude-rule","project-spec","plugin-manifest","command-prompt"],"hasMcp":false,"mcpConfig":null,"found":["backend/internal/skillassets/using-ao/SKILL.md",".agents/skills/pr-description/SKILL.md",".claude/skills/ao-desktop-dev/SKILL.md",".claude/skills/bug-triage/SKILL.md","integrations/grok-bot/skills/ao-actions/SKILL.md",".agents/skills/ao-desktop-dev/SKILL.md",".agents/skills/bug-triage/SKILL.md","integrations/grok-bot/skills/ao-setup/SKILL.md","integrations/grok-bot/skills/ao-answer/SKILL.md","integrations/grok-bot/skills/ao-orchestrator/SKILL.md","integrations/grok-bot/skills/ao-status/SKILL.md","integrations/grok-bot/skills/ao-rules/SKILL.md","integrations/grok-bot/skills/ao-update/SKILL.md","AGENTS.md","CLAUDE.md","DESIGN.md","docs/architecture.md","packages/ao-darwin-arm64/package.json","packages/ao-darwin-x64/package.json","packages/ao-linux-x64/package.json","packages/ao-win32-x64/package.json","packages/ao/package.json","packages/cloud-client/README.md","packages/cloud-client/package-lock.json","packages/cloud-client/package.json","packages/cloud-client/tsconfig.json","packages/cloud-client/tsconfig.test.json","packages/mobile/README.md","packages/mobile/app.json","packages/mobile/eas.json","packages/mobile/package-lock.json","packages/mobile/package.json","packages/mobile/tsconfig.json","packages/product-ui/README.md","packages/product-ui/package-lock.json","packages/product-ui/package.json","packages/product-ui/tsconfig.build.json","packages/product-ui/tsconfig.json","packages/mobile/scripts/README.md",".agents/skills/ao-desktop-dev/agents/openai.yaml",".claude/skills/bug-triage/scripts/push_fix_to_github.py","packages/mobile/assets/AO.icon/icon.json","packages/mobile/native/image-paste/package.json","packages/mobile/native/response-selection/package.json","backend/internal/skillassets/using-ao/commands/automation.md","backend/internal/skillassets/using-ao/commands/browser-remote.md","backend/internal/skillassets/using-ao/commands/browser.md","backend/internal/skillassets/using-ao/commands/cua.md","backend/internal/skillassets/using-ao/commands/cue.md","backend/internal/skillassets/using-ao/commands/doctor.md","backend/internal/skillassets/using-ao/commands/import.md","backend/internal/skillassets/using-ao/commands/orchestrator.md","backend/internal/skillassets/using-ao/commands/preview.md","backend/internal/skillassets/using-ao/commands/project.md","backend/internal/skillassets/using-ao/commands/remote-host.md","backend/internal/skillassets/using-ao/commands/render.md","backend/internal/skillassets/using-ao/commands/report.md","backend/internal/skillassets/using-ao/commands/review.md","backend/internal/skillassets/using-ao/commands/send.md","backend/internal/skillassets/using-ao/commands/session.md","backend/internal/skillassets/using-ao/commands/spawn.md","backend/internal/skillassets/using-ao/commands/start.md","backend/internal/skillassets/using-ao/commands/status.md","backend/internal/skillassets/using-ao/commands/stop.md","frontend/src/docs/content/plugins/meta.json","packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json","frontend/src/docs/content/plugins/agents/meta.json","frontend/src/docs/content/plugins/notifiers/meta.json","frontend/src/docs/content/plugins/runtimes/meta.json","frontend/src/docs/content/plugins/scm/meta.json","frontend/src/docs/content/plugins/terminals/meta.json","frontend/src/docs/content/plugins/trackers/meta.json","frontend/src/docs/content/plugins/workspaces/meta.json"],"skills":{"backend/internal/skillassets/using-ao/SKILL.md":"---\nname: using-ao\ndescription: \"Catalog of the AO (Agent Orchestrator) `ao` CLI: spawning workers, managing sessions and projects, creating reusable Cues, sending messages, controlling the shared browser, previewing pages, and daemon control. Use when using the ao CLI, creating Cues, spawning workers, or managing AO sessions in an AO workspace.\"\ntrigger: \"Using the ao CLI in an AO workspace: creating Cues, spawning workers, managing sessions/projects, sending messages, controlling or previewing pages.\"\n---\n\n# AO CLI Catalog\n\n`ao` is a thin CLI over the local AO daemon. Every command is `ao <command> --help` for the authoritative flag list.\n\n| Command | What it does | When to use | Details |\n|---|---|---|---|\n| `spawn` | Spawn a project worker, orchestrator, or projectless standalone worker | Starting a new task or issue | [commands/spawn.md](commands/spawn.md) |\n| `session` | Manage agent sessions (list, kill, rename, restore, history, etc.) | Inspecting or controlling running/terminated sessions, or reading the full conversation after taking over from another agent | [commands/session.md](commands/session.md) |\n| `agent` | Inspect installed harnesses and launch readiness | Choosing or diagnosing an agent harness | `ao agent ls --refresh` |\n| `pr` | Merge a PR or resolve its review threads | Completing a reviewed change | `ao pr merge` / `ao pr resolve-comments` |\n| `project` | Register, inspect, configure, or remove projects | Setting up or managing repos AO knows about | [commands/project.md](commands/project.md) |\n| `automation` | Manage durable recurring session automations | Creating, editing, disabling, deleting, and inspecting scheduled runs | [commands/automation.md](commands/automation.md) |\n| `cue` | Create or list reusable project Cues | Saving a repetitive command or agent task at the user's request | [commands/cue.md](commands/cue.md) |\n| `orchestrator` | List orchestrator sessions | Viewing which sessions are orchestrators | [commands/orchestrator.md](commands/orchestrator.md) |\n| `review` | Start, list, cancel, or submit AO's native reviewer for a worker's PR (default: this session) | Reviewing implementation PRs owned by AO workers. Use a normal review-only worker for someone else's PR | [commands/review.md](commands/review.md) |\n| `send` | Send a message to a running agent session | Messaging a live agent; use `--steer` to correct it mid-turn | [commands/send.md](commands/send.md) |\n| `report` | Persist a meaningful worker report | Checkpoints, blockers, decisions, outputs, and completion | [commands/report.md](commands/report.md) |\n| `preview` | Start a session-owned app or open an exact URL/file | Running and showing the worker's relevant app, Markdown, HTML, PDF, or image | [commands/preview.md](commands/preview.md) |\n| `render` | Show a self-contained HTML page inline in a chat thread | Answering with a chart, table, diagram, or mockup | [commands/render.md](commands/render.md) |\n| `browser` | Inspect and control the session's shared live browser | Verifying a web app through snapshots, interactions, waits, screenshots, console, and errors | [commands/browser.md](commands/browser.md) |\n| `browser` (remote host) | Drive the host's shared remote Chromium, used when `AO_AGENT_BROWSER_URL` is set | Same browser verification on a self-hosted remote host; one browser is shared across sessions | [commands/browser-remote.md](commands/browser-remote.md) |\n| `remote-host` | Link this machine to the user's AO account, or turn its remote access on or off | Setting up a VM or other headless machine so the user's desktops and phones can use it | [commands/remote-host.md](commands/remote-host.md) |\n| `start` | Fetch (if needed) and open the AO desktop app | Launching the app | [commands/start.md](commands/start.md) |\n| `stop` | Stop the AO daemon | Shutting down AO | [commands/stop.md](commands/stop.md) |\n| `status` | Show daemon status | Verifying the daemon is up and healthy | [commands/status.md](commands/status.md) |\n| `doctor` | Run local health checks | Diagnosing AO setup problems | [commands/doctor.md](commands/doctor.md) |\n| `import` | Import projects from a legacy AO install | Migrating from the old flat-file store | [commands/import.md](commands/import.md) |\n| `version` | Print version information | Checking installed version | - |\n| `completion` | Generate shell completion scripts | Setting up tab completion | - |\n\n## Conventions\n\n- Most read commands accept `--json` for machine-readable output.\n- `-p / --project` scopes session subcommand lookups to one project.\n- Session and project ids are shown by `ao session ls` and `ao project ls`.\n- To refer to a session in AO Chat or the AO terminal, use the canonical in-app\n  link `ao://sessions/{project-id}/{session-id}`. Read\n  [commands/session.md](commands/session.md) for identity, encoding, and safety\n  rules before constructing one.\n- When the user asks to save a repeatable task as a Cue, use `ao cue list --json` to check existing definitions, then `ao cue create`. An agent Cue stores a reusable instruction; a command Cue stores an exact shell command. This agent-facing command can create and read Cues, but cannot edit or delete them. Direct the user to project settings for changes to existing Cues.\n- `--agent` is an alias for `--harness` on `ao spawn`.\n- Every command accepts `-h / --help` for the full flag list.\n- For frontend launch, preview selection, or artifact handoff, read\n  [commands/preview.md](commands/preview.md) before acting. Its static-file,\n  project-runtime, and automatic-handoff rules are load-bearing.\n- For page inspection, interaction, or request diagnosis, read\n  [commands/browser.md](commands/browser.md). It defines shared-tab behavior\n  and the opt-in network policy.\n\nUse [references.md](references.md) only when a natural-language request does\nnot map clearly to a command above.\n",".agents/skills/pr-description/SKILL.md":"---\nname: pr-description\ndescription: Write and maintain pull request descriptions in this repository, including the required change-count header, the before-and-after section, and screenshots or recordings for visible changes.\n---\n\n# PR description\n\nUse the section order in `.github/pull_request_template.md`: change-count header,\nWhat, Why, Before / After, How, Testing, Checklist. Preserve the rest of an existing\nPR description when updating it.\n\n## Change-count header\n\nBegin every PR description with these three lines, using Markdown hard line breaks\nso each renders separately:\n\n```text\nCode changes: +<added> -<deleted>\nTests: +<added> -<deleted>\nOthers: +<added> -<deleted>\n```\n\nCalculate the numbers from the net diff against the PR's actual base. For a local\nbranch, use `git diff --numstat <base>...<head>`. After pushing, prefer GitHub's\nper-file additions and deletions. Recalculate after the final push rather than\nsumming commit churn or estimating counts.\n\nCount every changed file exactly once:\n\n- **Code changes:** handwritten implementation, including SQL, migrations, styles,\n  and executable scripts.\n- **Tests:** test code, fixtures, snapshots, and test-only helpers.\n- **Others:** generated or vendored files, lockfiles, documentation, configuration,\n  and assets. Generated output belongs here even when it contains source code.\n\nShow `+0 -0` for empty categories. Binary files have no line count; mention their\ncount separately when present. Add a brief qualifier when useful, such as\n`Others: +11 -0 (generated sqlc)`.\n\n## Before / After\n\nEvery PR has a `## Before / After` section with a two-column table, one row per\nbehavior that changed:\n\n```markdown\n| Before | After |\n| --- | --- |\n| ![Before: empty model list](before.png) | ![After: list filtered to six models](after.png) |\n| `ao session ls` exits 1 when a project has no sessions | Prints `No sessions` and exits 0 |\n```\n\n- **UI changes** need a screenshot of each changed state, before and after. Use a\n  short recording for flows, animations, focus or keyboard behavior, and timing.\n- **Non-visual changes** compare observable behavior: command output, API\n  responses, errors, logs, or measured numbers with their units.\n- **No user-visible change:** write `No user-visible change` and one line saying why,\n  such as an internal refactor or a test-only change.\n\nCapture both sides from the real app with the same screen, window size, and data,\nso they compare directly. Take the before capture from the PR's base branch. The\n`ao-desktop-dev` skill launches the desktop app from a checkout.\n\nScreenshots and GIFs go in the table. GitHub renders a video player only for a\nbare attachment URL on its own line, so put MP4 or MOV recordings on their own\nline below the table, with one line saying what they show.\n\nNever commit screenshots or recordings to the repository. Attach them in the PR\ndescription, or in a PR comment when the description gets long. If you cannot\nupload, give the capture file paths to the person who will attach them. Remove\nsecrets, tokens, and personal data from every capture.\n\n## Verify\n\nAfter creating or updating the PR, read the published description and verify that:\n\n- its opening lines match the current GitHub diff counts and required order;\n- every image and recording in Before / After, or in a PR comment, loads.\n",".claude/skills/ao-desktop-dev/SKILL.md":"---\nname: ao-desktop-dev\ndescription: Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data.\n---\n\n# AO Desktop Dev\n\nRead and follow [`../../../.agents/skills/ao-desktop-dev/SKILL.md`](../../../.agents/skills/ao-desktop-dev/SKILL.md) completely before launching or troubleshooting the desktop app. That file is the canonical cross-agent workflow for this repository.\n",".claude/skills/bug-triage/SKILL.md":"---\nname: bug-triage\ndescription: Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft.\n---\n\n# Bug triage\n\nRead and follow [`../../../.agents/skills/bug-triage/SKILL.md`](../../../.agents/skills/bug-triage/SKILL.md) completely before clarifying, drafting, or filing anything. That file is the canonical cross-agent workflow for this repository.\n","integrations/grok-bot/skills/ao-actions/SKILL.md":"---\nname: ao-actions\ndescription: >-\n  Direct actions on one AO session or PR: stop or interrupt, resume, merge a PR,\n  start a review, screenshot a session's browser, send a session's files, keep\n  a host awake, and recurring AO automations. Use for \"stop <session>\",\n  \"merge <PR>\", \"review <session>'s PR\", \"show me what <session> built\",\n  \"keep the Mac awake tonight\", \"every night, ...\".\n---\nFollow the ao-rules skill. Find the session first (ao-rules \"AO hosts\": `<host>/<session id>`). Run each action on the owner host from its `via` computer. \"Yes\" means the user's yes for that exact action in this chat.\n\n| Ask | Do | Yes needed | Hosts |\n|---|---|---|---|\n| Stop what it's doing now | `aoapi POST \"sessions/<id>/conversation/interrupt\"` | No | All |\n| End the session | `aoapi POST \"sessions/<id>/kill\" '{}'` | Yes | All |\n| Resume an exited agent | `aoapi POST \"sessions/<id>/resume-agent\" '{}'` | No | All |\n| Restore an ended session | `aoapi POST \"sessions/<id>/restore\" '{}'` (an ended orchestrator can't come back while its project has another live one) | Yes | All |\n| Merge a PR | see \"Merge\" | Yes, per PR | All |\n| Start AO's reviewer on a session's PR | `ao review trigger <id>` | Yes | Local |\n| Screenshot a session's browser | see \"Screenshot\" | No | Local |\n| A session's files | see \"Files\" | No | Local |\n| Keep the host awake | see \"Keep awake\" | Yes | Local |\n| Recurring agent work | see \"Automations\" | Yes | Local |\n| Start one worker directly | `aoapi POST sessions '<json>'` with `projectId`, `displayName`, `prompt` | Yes | All |\n\nFor an action marked Local on a remote host, ask that host's orchestrator to do it (ao-orchestrator).\n\nStart a worker directly only when the project has no orchestrator and the user doesn't want one (ao-rules \"orchestrator first\").\n\n## Merge\nFirst show the PR and ask:\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions/<session id>/pr\" | python3 -c '\nimport json,sys\nfor p in json.load(sys.stdin).get(\"prs\") or []:\n    if str(p.get(\"number\"))==sys.argv[1]: print(json.dumps({\"url\":p.get(\"url\"),\"headSha\":p.get(\"headSha\"),\"state\":p.get(\"state\"),\n        \"ci\":(p.get(\"ci\") or {}).get(\"state\"),\"review\":(p.get(\"review\") or {}).get(\"decision\"),\"mergeability\":(p.get(\"mergeability\") or {}).get(\"state\")}))' '<pr number>'; }; f\n```\nTell the user the link, checks (`ci`), review decision and whether it can merge (`mergeability`). Never merge on failing checks or `conflicting` without the user saying so for that PR. On yes, merge exactly the commit you showed:\n```sh\nf(){ <aoapi helper>; aoapi POST \"prs/<pr number>/merge\" \"$(python3 -c 'import json,sys; print(json.dumps({\"prUrl\":sys.argv[1],\"expectedHeadSha\":sys.argv[2]}))' '<url>' '<headSha>')\"; }; f\n```\nIf the PR got new commits since you showed it, AO refuses the merge. Show it again and ask again.\n\n## Screenshot\nThe session must have a browser page open. `BROWSER_CAPABILITY_INVALID` means it has none: say so.\n```sh\nf(){ mkdir -p ~/.ao-grok/out && AO_SESSION_ID='<id>' ao browser screenshot ~/.ao-grok/out/<id>-$(date +%H%M%S).png; }; f\n```\nThen CopyToBox and SendToUser.\n\n## Files\nA session's deliverables are in its artifact folder:\n```sh\nf(){ ls -la \"${AO_DATA_DIR:-$HOME/.ao/data}/artifacts/<id>/\"; }; f\n```\nSend the file the user asks for with CopyToBox and SendToUser. HTML reports render best opened on the phone as a file.\n\n## Keep awake\nFor a run that must last overnight, after a yes:\n```sh\nf(){ <aoapi helper>; aoapi POST awake/sessions \"$(python3 -c 'import json,sys; print(json.dumps({\"mode\":\"duration\",\"durationSeconds\":int(sys.argv[1]),\"scope\":\"ao\"}))' '<seconds>')\"; }; f\n```\nSay when it ends. The user can stop it in AO. An `AWAKE` error that mentions a safety stop means AO stopped keep-awake on purpose (for example on battery): tell the user to resume it in AO. Don't resume it yourself.\n\n## Automations\nFor recurring agent work that should run on the host even when the bot is off (for example \"every night, update dependencies in <project>\"), create an AO automation after a yes:\n```sh\nao automation create --project '<project>' --name '<name>' --cron '<m h dom mon dow>' --timezone '<IANA zone>' --prompt '<task>'\n```\n`ao automation list` shows them. To remove one after a yes: `ao automation delete --yes <id>`. Use a Grok routine instead when the job is to tell the user something (ao-status \"Digest\", ao-answer waiting check).\n",".agents/skills/ao-desktop-dev/SKILL.md":"---\nname: ao-desktop-dev\ndescription: Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data.\n---\n\n# AO Desktop Dev\n\nRun the Electron application from the current checkout and verify it in the native window. Keep the dev daemon, renderer, Electron preload, and selected data mode explicit so the user never reviews a mock or stale build by accident.\n\n## Choose the data mode\n\nAsk only when the request does not make the desired data source clear.\n\n- Use **isolated mode** by default for implementation and destructive testing. Electron uses port `3002`, `~/.ao/dev/running.json`, `~/.ao/dev/data`, and `~/.ao/dev/electron`.\n- Use **real-data mode** only when the user explicitly asks to see this machine's actual AO projects or sessions. Start the checkout's dev daemon on the isolated dev port/run file while pointing `AO_DATA_DIR` at the real AO data directory. This is a separate daemon process using real data; do not describe it as the installed app's daemon.\n- Never try to attach an unpackaged Electron app directly to a packaged daemon from another checkout. The supervisor intentionally rejects daemon identity mismatches.\n- Warn before actions in real-data mode that create, terminate, rename, or otherwise mutate sessions. Merely opening and inspecting the UI is expected.\n- Real-data mode reads the same database as the installed app, and only one daemon can own a data directory. Quit the packaged app first: while its daemon runs, the dev daemon waits for the data-dir lock (9 x `AO_SHUTDOWN_TIMEOUT` + 18s, 108s by default) and then exits with code 75. The dev window is marked with an `Agent Orchestrator (dev)` title, an orange-badged `DEV` dock icon, and an in-app `dev` badge — verify those markers before acting.\n\n## Preflight\n\n1. Work from the repository root and inspect `git status --short --branch`.\n2. Read `frontend/package.json`, `frontend/src/main.ts`, and `frontend/forge.config.ts` when the launch behavior may have changed. Treat source as authoritative over this skill.\n3. Confirm Node/npm and the Go version required by `backend/go.mod` are available. Run `npm ci` in `frontend/` only when dependencies are absent or inconsistent; do not reinstall on every launch.\n4. Check for an existing dev instance from this exact checkout before starting another. Do not kill by process name alone, and never terminate every Electron process.\n\nOn macOS/Linux, inspect checkout-scoped processes and listeners with finite commands:\n\n```bash\nps -axo pid=,ppid=,pgid=,lstart=,command= | rg 'frontend/(node_modules/.bin/electron-forge|node_modules/electron/dist/Electron)'\nlsof -nP -iTCP:3002 -sTCP:LISTEN\n```\n\nUse the full command paths and start times to distinguish this checkout from other AO worktrees. On Windows, use `Get-CimInstance Win32_Process` and `Get-NetTCPConnection`; preserve the same exact-target rule.\n\n## Launch the app\n\nRun Electron Forge in a foreground interactive process so its output and restart input remain available. Do not append `&`, use a detached shell, or start a browser preview instead.\n\n### Isolated mode\n\nOn macOS/Linux:\n\n```bash\ncd frontend\nenv -u AO_DATA_DIR -u AO_RUN_FILE -u AO_PORT npm run dev\n```\n\nOn PowerShell:\n\n```powershell\nSet-Location frontend\nRemove-Item Env:AO_DATA_DIR, Env:AO_RUN_FILE, Env:AO_PORT -ErrorAction SilentlyContinue\nnpm run dev\n```\n\n### Real-data mode\n\nFirst resolve and report the actual data directory. In an AO worker session, `AO_DATA_DIR` normally already identifies it. Otherwise the repository default is the absolute path corresponding to `~/.ao/data`.\n\nKeep the real data directory but remove inherited port/run-file overrides so the dev app retains its own daemon handshake and port:\n\n```bash\ncd frontend\nenv -u AO_RUN_FILE -u AO_PORT AO_DATA_DIR=\"${AO_DATA_DIR:-$HOME/.ao/data}\" npm run dev\n```\n\nPowerShell equivalent:\n\n```powershell\nSet-Location frontend\n$realAoData = if ($env:AO_DATA_DIR) { $env:AO_DATA_DIR } else { Join-Path $HOME \".ao/data\" }\nRemove-Item Env:AO_RUN_FILE, Env:AO_PORT -ErrorAction SilentlyContinue\n$env:AO_DATA_DIR = $realAoData\nnpm run dev\n```\n\nDo not print unrelated environment variables: AO sessions may carry credentials. It is safe to report only `AO_DATA_DIR`, `AO_RUN_FILE`, and `AO_PORT`.\n\n## Confirm the correct app is ready\n\nWait for all of these signals:\n\n- Electron Forge reports `Launched Electron app`.\n- The daemon reports `daemon listening`, normally on `127.0.0.1:3002` unless it explicitly reports another bound port.\n- The renderer makes successful requests such as `/api/v1/projects` and `/api/v1/sessions`.\n- The native Electron window shows the checkout's UI. A Vite URL opened in a normal browser is not equivalent because it lacks the Electron preload bridge.\n\nIf several AO windows exist, identify the newest Electron main process belonging to this checkout. On macOS, foreground that exact PID only when needed:\n\n```bash\nosascript -e 'tell application \"System Events\" to set frontmost of first process whose unix id is <verified-pid> to true'\n```\n\nDo not claim real data from appearance alone. Verify the selected data directory and successful API responses. Do not claim visual success from compilation alone; interact with the requested flow in Electron or ask the user for a screenshot when screen capture is unavailable.\n\n## Reload changes correctly\n\n- Renderer-only React/CSS changes normally hot reload.\n- Changes to `frontend/src/main.ts`, preload files, Forge configuration, shared bridge types, or IPC registration require an Electron main-process restart. Type `rs` into the active Forge terminal or fully stop and relaunch the dev process.\n- A renderer error such as `aoBridge.<method> is not a function` almost always means the renderer hot-reloaded against a stale preload. Restart Electron before changing code to add guards around a bridge method that should exist.\n- Backend changes require restarting the managed dev daemon or the Electron process; renderer hot reload cannot apply Go changes.\n\nAfter a restart, confirm the new Electron PID/start time and re-check the logs for the original error.\n\n## Preview multiple PRs locally\n\nWhen the user wants to see multiple unmerged PRs together:\n\n1. Require a clean worktree and fetch each PR head.\n2. Create a clearly named local-only integration branch using the session/repository branch convention.\n3. Merge or cherry-pick the requested PR heads without rewriting or pushing either source branch.\n4. Resolve overlaps according to the requested combined behavior and run focused typechecks/tests.\n5. Let renderer changes hot reload; restart Electron if either PR changes main/preload/IPC code.\n6. State that the integration branch is local-only. Do not push it unless the user explicitly requests a combined PR.\n\nOnce one PR merges, prefer rebasing the remaining PR onto current `main`; the normal PR branch then contains both views without a local integration merge.\n\n## Stop without collateral damage\n\n1. Send Ctrl+C to the foreground dev process and wait briefly for Electron and its managed daemon to exit.\n2. Re-run the checkout-scoped process query. If the exact process group remains, identify the group created by this launch before sending `TERM` to that group.\n3. On Windows, terminate the verified parent tree only. Never use a broad Electron, Node, Go, or port-based kill.\n4. Confirm the captured Electron PID and dev daemon listener are gone. Leave installed AO and other worktrees untouched.\n\n## Common mistakes\n\n- `ao preview` controls the AO Browser panel; it does not launch the desktop shell.\n- `npm run dev:web` is useful for browser-only renderer work but does not provide Electron APIs or native chrome.\n- Renderer URLs can move from `5173` when a port is occupied. Trust Forge's printed URL rather than assuming one.\n- Multiple dev instances share `~/.ao/dev/electron` by default, and Chromium's\n  singleton lock lives in the profile, so a second checkout's `npm run dev`\n  loses `requestSingleInstanceLock()` and exits immediately with code 0. To run\n  two worktrees at once, give each its own profile, run file, and data dir:\n\n  ```bash\n  env -u AO_PORT \\\n    AO_DEV_ELECTRON_DIR=\"$HOME/.ao/dev/<name>/electron\" \\\n    AO_RUN_FILE=\"$HOME/.ao/dev/<name>/running.json\" \\\n    AO_DATA_DIR=\"$HOME/.ao/dev/<name>/data\" \\\n    npm run dev\n  ```\n\n  Without all three the instances still collide, on the profile lock, the run\n  file, or the daemon's SQLite data.\n- An inherited `AO_DATA_DIR` changes dev mode from isolated data to real data. Always choose and report the mode instead of inheriting it accidentally.\n- Repeated `/healthz/` 404 entries from external probes can be noisy; readiness is determined by Electron's daemon status and successful API traffic, not by log volume.\n\n## Completion report\n\nReport:\n\n- checkout and branch being displayed;\n- isolated or real-data mode and the non-sensitive data/run-file paths;\n- renderer and daemon addresses actually reported;\n- whether Electron was restarted for main/preload changes;\n- user flows exercised in the native window;\n- any remaining stale process, port, or visual-verification limitation.\n",".agents/skills/bug-triage/SKILL.md":"---\nname: bug-triage\ndescription: Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft.\n---\n\n# Bug triage\n\nHelp the reporter describe what they observed and add useful evidence. A short human\nobservation is enough to report a bug; reproduction, logs, and a diagnosis are optional.\nUse this skill for reports from chat, an existing issue, or a local user.\n\n## Clarify the observation\n\nRead the available report, screenshots, and follow-ups first. Preserve the original\nreporter's words and attribution, including when someone else relays their report.\nDon't infer a GitHub username from a chat display name.\n\nAsk only questions that would materially clarify the symptom, a few at a time. Don't\nrepeat questions already answered or turn these suggestions into required fields:\n\n- What did you do, and what happened instead of what you expected?\n- Where did it happen, and does it happen every time or only sometimes?\n- For a visual problem, can you share a screenshot or short recording showing it?\n- If relevant, which AO version and OS were you using, and did it start after a change?\n\nIf a screenshot is unavailable, accept a description. If the reporter cannot remember\nsteps or reproduce the problem, preserve that uncertainty and proceed with what is\nknown. Never invent steps or make the reporter diagnose the bug before accepting it.\n\n## Keep the report and investigation separate\n\nDraft a specific symptom-based title and a short body, normally one paragraph or a few\nbullets. Include only details supplied directly by the human: their observation,\nexpected behavior, steps, frequency, environment, and impact when they provided them.\nLight editing for clarity is fine; preserve meaning and uncertainty. Omit empty\nsections and unnecessary background. Do not add agent-inferred impact, root cause,\nconfidence scores, or proposed fixes to the report.\n\nExample human report:\n\n> After I switched projects, the terminal stayed blank. I expected to see the session\n> prompt. It happened twice today on macOS; I don't know how to reproduce it reliably.\n\nKeep agent-discovered information separate from the human report and label it\n**Agent-collected evidence**, even when it confirms the report. Include only relevant\nexcerpts and:\n\n- The command or read-only query used, collection time, and relevant AO version or\n  checkout commit, so another person can interpret the result.\n- Observed output, screenshots, or reproduction results, with enough context to verify\n  the finding. Distinguish the reporter's environment from a separate test build.\n- A brief explanation of what the evidence supports and its limits. Label hypotheses\n  explicitly; don't present a code-path guess as a confirmed cause.\n\nIf no useful evidence is available, deliver the human report alone. Never pad it with\nspeculation or claim a reproduction succeeded when it didn't.\n\n## Gather relevant evidence\n\nUse diagnostics that fit the symptom, within the user's requested scope. Prefer\nread-only checks against the affected installation. Don't restart sessions, upgrade\nAO, change live data, or alter the user's checkout just to collect evidence.\n\nAO uses a Go daemon and an Electron/React frontend. Read `docs/architecture.md` for\ncurrent boundaries and locate actual files with `rg` before citing code. Do not rely\non the old TypeScript implementation or assume which runtime backs a session.\n\nBefore trusting diagnostics, identify the AO executable and affected daemon. A PATH\nlookup may resolve to a legacy install. Check the executable's version and status,\nand the configured run file/data directory (`AO_RUN_FILE` / `AO_DATA_DIR` when set).\nThe primary daemon normally uses loopback port 3001; port alone does not establish\nwhich version or installation is affected. Consult the installed CLI help for commands.\n\nFor local-daemon evidence, use the affected binary's `--version` and `status --json`;\nstatus reads existing state without starting the daemon. For a known affected session,\nuse `session get <id> --json` and keep only fields relevant to the symptom. If the\ndaemon is unavailable, record its status or error and mark session evidence unavailable.\n\nRecord app and CLI versions separately from daemon identity. Health probes provide no\ndaemon release version; `dev` alone or missing build metadata does not identify the\nsource. Label source findings approximate when the affected build cannot be matched.\n\nDo not run `doctor` or `agent ls` as routine evidence collectors: doctor writes files\nand checks remote authentication; agent listing triggers readiness checks.\n`remote-host status` can print the pairing password. Desktop status refresh may start\na replacement daemon; prefer the CLI status check or already available evidence.\n\nCollect only what helps explain this symptom:\n\n| Symptom | Potential evidence |\n| --- | --- |\n| UI rendering or interaction | Screenshot/recording, relevant console errors, affected view |\n| Session or terminal state | Affected session's daemon state, relevant log excerpt, runtime details |\n| Daemon or CLI failure | Version/status, exact command and error, relevant daemon logs |\n| Persisted state mismatch | Relevant rows and schema from a read-only SQLite query |\n\nLocate logs for the affected process rather than assuming `~/.ao/daemon.log` is current.\nDaemon output goes to stderr and may not persist; that file mostly covers keep-alive\nlaunches. Record missing evidence instead of enabling logging just to create it.\n\nUse the daemon API/CLI for state first. If database evidence is needed, discover the\nactual database location and schema, open it read-only, and select only relevant rows\nand columns. Never attach an entire database, broad log dump, or Electron profile\nfolder, which also holds browser cookies and storage. Redact tokens,\ncredentials, private prompts, and unrelated personal or repository data from every\nartifact, including screenshots. Keep diagnostic artifacts under `~/.ao` and out of\nGit commits. Preserve evidentiary content when redacting, and verify that unrelated\ncontent did not change. Share a useful excerpt rather than a wall of output.\n\nThe report form's sanitizer masks known patterns only; review the exact draft and\nartifacts before sharing.\n\nTry a safe reproduction when practical, recording the build actually tested. Failure\nto reproduce does not invalidate the human report. Code tracing or dependency research\nis optional when it can add concrete evidence. Keep findings in the separate evidence.\n\n## Check for duplicates\n\nResolve AO's canonical repository name before searching. GitHub issue and PR searches\ncan return empty results for a former owner even when repository API requests redirect.\nUse the resolved name, not the reporter's project repository. Search open and closed\nissues and related PRs using the symptom or exact error:\n\n```bash\nif ao_triage_repo=$(gh api repos/OrchestratorInc/agent-orchestrator --jq .full_name) && [ -n \"$ao_triage_repo\" ]; then\n  gh issue list --repo \"$ao_triage_repo\" --state all --search '<symptom or error>' --limit 100\n  gh pr list --repo \"$ao_triage_repo\" --state all --search '<symptom or error>' --limit 100\nelse\n  printf '%s\\n' 'Repository lookup failed; duplicate search skipped.' >&2\nfi\n```\n\nInclude the searched repository and candidates considered in the separate evidence.\nTry useful symptom synonyms or a shorter error fragment when needed.\n\nRead likely matches before calling a report a duplicate. If one matches, give the\nreporter its link and draft only their new observation for a comment, with evidence\nattached separately. If a closed issue appears to have regressed, explain that to the\nreporter rather than silently treating it as resolved. If repository lookup or either\nsearch fails or is unavailable, say which part could not be checked. Empty, truncated,\nor failed searches do not prove there is no duplicate; continue preparing the report.\n\n## Preserve attribution and submission scope\n\nA local coding agent may help draft and gather attachments. Existing authorization\nstill applies; triage alone is not permission to publish.\n\nFor an existing issue, preserve its human body and attribution. Add evidence separately\nwhen authorized. Don't rewrite the report into an investigation narrative.\n\nWhen authorized to publish, include useful collected evidence before finishing. Use a\nclearly labeled comment or attachment, whichever fits the evidence. If evidence cannot\nbe published, state the exact blocker and provide its local path. Never invent\nattachment URLs or create asset branches to host diagnostics. Keep the report body\nlimited to human details. Apply only existing, relevant labels; don't add\npriority/confidence prose just to fill a template.\n\nFinish with the concise draft (or issue link if submitted), any duplicate link, and\nattachment paths/links. Do not automatically file an issue, implement a fix, push a\nPR, or spawn a worker. Follow the user's requested scope and the repository's normal\ncontribution workflow if they separately ask for implementation.\n\nThe bundled `scripts/push_fix_to_github.py` is a legacy fix publisher, not a triage step.\n","integrations/grok-bot/skills/ao-setup/SKILL.md":"---\nname: ao-setup\ndescription: >-\n  First run of Orchestrator Bot: find every computer that runs AO, save them as\n  AO hosts, add a remote AO host that has no Grok Bot desktop app, and turn on\n  optional routines. On a computer without Orchestrator.inc it helps install it\n  and get it ready: a coding agent, a first project and the first orchestrator.\n  Use on the first chat, when memory has no \"AO hosts\" note, or when the user\n  says \"set up AO\", \"add a host\", \"add remote host\", \"check my AO setup\" or\n  \"install Orchestrator\".\n---\nFollow the ao-rules skill. Detection is read-only. Nothing is written until the user says yes.\n\nOpen with one line: \"Give me a few seconds to look for AO on your computers.\"\n\n## 1. Detect\n1. ListMachines. Use desktops only. If none is connected, say: \"Install the Grok Bot desktop app on the computer where you run Orchestrator.inc (or want to), sign in, and tell me when it shows up,\" then stop.\n2. On each connected desktop, in parallel, run this read-only probe with the `aoapi` helper from ao-rules: run \"Probe\" below.\n3. Each desktop where the probe prints a `projects=` line is a **local** AO host; an empty list means it still needs \"First run\". For any other result, see \"Missing pieces\". On a Windows desktop, don't run the probe: say once \"These skills need macOS or Linux; Windows isn't supported yet,\" and skip it.\n\n### Probe\n```sh\nf(){ <aoapi helper>; echo \"ao=$(command -v ao >/dev/null && ao version 2>/dev/null | head -1 || echo missing)\"\n  if [ \"$(uname -s)\" = Darwin ] && [ \"$(command -v python3)\" = /usr/bin/python3 ] && ! xcode-select -p >/dev/null 2>&1; then echo \"python=missing\"\n  else echo \"python=$(command -v python3 >/dev/null && python3 -c 'import sys;print(\"%d.%d\"%sys.version_info[:2])' || echo missing)\"; fi\n  [ \"$(uname -s)\" = Darwin ] && A=$(find /Applications \"$HOME/Applications\" -maxdepth 1 -name '*Orchestrator*.app' 2>/dev/null | head -1) && echo \"app=${A:-missing}\"\n  if P=$(aoapi GET projects 2>/dev/null); then\n    echo \"$P\" | python3 -c 'import json,sys; d=json.load(sys.stdin); p=d.get(\"projects\",d) if isinstance(d,dict) else d; print(\"projects=\" + \", \".join(x.get(\"id\",\"?\") for x in p))'\n    aoapi GET 'sessions?active=true' | python3 -c 'import json,sys; print(\"live_sessions=%d\" % len(json.load(sys.stdin)[\"sessions\"]))'\n  else echo \"daemon=not running\"; fi; }; f\n```\n\n## Missing pieces\nUse the probe result for each computer. Install or open anything only after the user's yes.\n\n| Probe shows | Next step |\n|---|---|\n| `python=missing` | Fix this first: every step needs it. macOS: `xcode-select --install` (the user confirms the system dialog). Linux: give the package manager line for python3 |\n| `daemon=not running` and `app=missing` (macOS) | Say: \"Orchestrator.inc isn't installed on <computer>. Want me to install it? It's about a 300 MB download.\" On yes, run \"Install on a Mac\" |\n| `daemon=not running` and `app=<path>` | On yes, open it with `open \"<path>\"`, then \"Wait for the app\" |\n| `daemon=not running` on Linux | If Orchestrator.inc is installed, ask the user to open it and say **check again**. Otherwise give the download for the user's distribution: [AppImage](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.AppImage), [.deb](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.deb) or [.rpm](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.rpm). The user installs and opens it, then says **check again** |\n| `projects=` with nothing after it | Run \"First run\" |\n| `ao=missing` with projects listed | Everything works except starting a review, screenshots and automations, which use the `ao` CLI. Say so once |\n\n**check again** runs the probe on that computer again and goes on from its result.\n\n**Wait for the app:** run the probe every 15 seconds, for up to 2 minutes, until it prints a `projects=` line. Still `daemon=not running` after that: ask the user to look at the Orchestrator.inc window and say **check again** when it's open.\n\n### Install on a Mac\nAfter a yes, on that computer. The download takes a few minutes, so the install runs in the background, in its own session so it keeps going after this command returns, and writes its progress to `~/.ao-grok/install.log`. It picks the build for the Mac's chip, checks the app's code signature (Orchestrator.inc's Developer ID team `X9LNSP8MC2`), copies it to Applications (or `~/Applications` if that isn't writable) and opens it:\n```sh\nf(){ mkdir -p ~/.ao-grok && cat > ~/.ao-grok/install-orchestrator.sh <<'EOF'\na=$([ \"$(sysctl -n hw.optional.arm64 2>/dev/null)\" = 1 ] && echo arm64 || echo x64); d=$(mktemp -d)\necho \"downloading the $a build\"\ncurl -fsSL -o \"$d/o.dmg\" \"https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/Orchestrator-darwin-$a.dmg\" || { echo DOWNLOAD_FAILED; rm -rf \"$d\"; exit 1; }\nm=$(hdiutil attach -nobrowse -readonly \"$d/o.dmg\" | awk -F'\\t' '/\\/Volumes\\//{print $NF}' | tail -1)\n[ -n \"$m\" ] || { echo INSTALL_FAILED; rm -rf \"$d\"; exit 1; }\napp=$(find \"$m\" -maxdepth 1 -name '*.app' 2>/dev/null | head -1)\ndone_(){ [ -n \"$m\" ] && hdiutil detach -quiet \"$m\"; rm -rf \"$d\"; }\nif [ -z \"$app\" ] || ! codesign --verify --deep --strict \"$app\" 2>/dev/null || ! codesign -dv \"$app\" 2>&1 | grep -q 'TeamIdentifier=X9LNSP8MC2'; then echo BAD_SIGNATURE; done_; exit 1; fi\ndest=/Applications\ncp -R \"$app\" \"$dest/\" 2>/dev/null || { dest=\"$HOME/Applications\"; mkdir -p \"$dest\" && cp -R \"$app\" \"$dest/\"; } || { echo INSTALL_FAILED; done_; exit 1; }\ndone_\nopen \"$dest/${app##*/}\" && echo \"INSTALLED $dest/${app##*/}\" || echo \"INSTALLED_NOT_OPENED $dest/${app##*/}\"\nEOF\nnohup python3 -c 'import os,sys; os.setsid(); os.execvp(\"sh\", [\"sh\", sys.argv[1]])' ~/.ao-grok/install-orchestrator.sh > ~/.ao-grok/install.log 2>&1 & echo STARTED; }; f\n```\nTell the user it has started. Then check `tail -1 ~/.ao-grok/install.log` every 20 seconds, for up to 15 minutes:\n\n| Last line | Next step |\n|---|---|\n| `downloading …` | Still going |\n| `INSTALLED <path>` | Say \"Orchestrator.inc is open on <computer>. I'll get it ready: a coding agent and your first project.\" Then \"Wait for the app\" and run \"First run\" |\n| `INSTALLED_NOT_OPENED <path>` | Open it with `open \"<path>\"`, then as above |\n| `DOWNLOAD_FAILED`, `BAD_SIGNATURE`, `INSTALL_FAILED`, or no change after 15 minutes | Say what happened and give the user the [download page](https://orchestrator.inc/download/) instead. Never retry `BAD_SIGNATURE` |\n\n## First run\nGets a computer ready for work once Orchestrator.inc is running there: a coding agent, a project, and the first orchestrator. Every change needs the user's yes. If Orchestrator.inc shows its own welcome steps and the user prefers them, let them finish there and say **check again**.\n\n### 1. A coding agent\n```sh\nf(){ <aoapi helper>; aoapi POST agents/refresh '{}' >/dev/null; aoapi GET agents/readiness | python3 -c '\nimport json,sys\nfor a in json.load(sys.stdin).get(\"agents\") or []:\n    inst=(a.get(\"installation\") or {}).get(\"state\",\"\"); auth=(a.get(\"authentication\") or {}).get(\"state\",\"\")\n    if inst!=\"not_installed\" or a.get(\"id\") in (\"claude-code\",\"codex\"):\n        print(\"\\t\".join([a.get(\"id\",\"\"), a.get(\"label\",\"\"), a.get(\"effectiveReadiness\",\"\"), inst, auth]))'; }; f\n```\nColumns: id, name, readiness, installed, signed in.\n- **Some agent is `ready`:** use it. If more than one is ready, ask which one should do the work. Don't pick for the user.\n- **Installed but not signed in:** on yes, `aoapi POST \"agents/<id>/auth\" '{}'` and relay its `guidance`. The sign-in runs in a terminal inside Orchestrator.inc; the user finishes it there (it may open their browser). When they say done, run this step again: it refreshes the checks.\n- **None installed:** ask \"Which coding agent do you want to use: Claude Code or Codex?\" On the pick and a yes, `aoapi POST \"agents/<id>/install\" '{}'`, then check `aoapi GET \"agents/<id>/install\"` every 15 seconds. `status` `succeeded`: sign in as above. `failed`, `unsupported` or `interrupted`: relay it, and point the user to the agent settings in Orchestrator.inc.\n\n### 2. A project\nSuggest the git clones the user worked in most recently (read-only; worktrees are left out):\n```sh\npython3 -c '\nimport glob,os\nhome=os.path.expanduser(\"~\"); found=set()\nfor r in (\"Development\",\"Projects\",\"projects\",\"code\",\"Code\",\"src\",\"dev\",\"GitHub\",\"Documents/GitHub\"):\n    for pat in (\"*/.git\",\"*/*/.git\",\"*/*/*/.git\"): found.update(os.path.dirname(g) for g in glob.glob(os.path.join(home,r,pat)) if os.path.isdir(g))\nfor p in sorted(found,key=lambda p:-os.path.getmtime(os.path.join(p,\".git\")))[:10]: print(p.replace(home,\"~\",1))'\n```\nShow them as one card, plus a typed option for another folder. On the pick, register it with the agent from step 1:\n```sh\nf(){ <aoapi helper>; aoapi POST projects \"$(python3 -c 'import json,os,sys; print(json.dumps({\"path\":os.path.expanduser(sys.argv[1]),\"config\":{\"worker\":{\"agent\":sys.argv[2]},\"orchestrator\":{\"agent\":sys.argv[2]}}}))' '<repo path>' '<agent id>')\" 2>/dev/null | python3 -c '\nimport json,sys\nd=json.load(sys.stdin); p=d.get(\"project\",d)\nif p.get(\"id\"): print(\"added\", p[\"id\"])\nelse: print(d.get(\"code\",\"ERROR\"), d.get(\"message\",\"\"), (d.get(\"details\") or {}).get(\"existingProjectId\",\"\"))'; }; f\n```\n- `added <id>`: done.\n- `NOT_A_GIT_REPO`: the folder needs to be a git repository with at least one commit. Ask for another folder.\n- `PATH_ALREADY_REGISTERED <id>`: it is already a project; use that id.\n\n### 3. The first orchestrator\nAsk: \"Want me to start the orchestrator for <project>? Tell me what you'd like done first, or I'll ask it to look around the repo and suggest a first task.\" On yes, run ao-orchestrator \"Start an orchestrator\" with that request.\n\nThen continue with section 2.\n\n## 2. Report and ask once\nOne message, at most 6 lines: per computer, AO found or not, its projects, and how many sessions are live. For a computer without a working AO, add the one next step from \"Missing pieces\". Then:\n\"Reply **yes** and I'll save these as your AO hosts. Is AO also running on a computer without the Grok Bot desktop app? Say **add remote host** and I'll connect to it from one of these.\"\n\nOn yes, save the **AO hosts** note (ao-rules \"AO hosts\") with `reach: local` and `via` = the same computer. Name each host with its short name (ao-rules `name`) and say the names in one line: \"I'll call them Pro and Air. Say if you want other names.\"\n\n## 3. Remote host (optional)\nUse this when AO runs on a computer that has no Grok Bot desktop app, for example a Mac mini host that a laptop's AO app already connects to.\n\n1. Ask for a short host name (letters, digits, `-`) and which connected computer to use as `via`. Default: the one the user's message came from.\n2. Tell the user, in one message:\n   \"On the host, open AO, go to remote access (Connect Mobile) and turn on network access. It shows an address and a password. Send me the **address** here. You'll type the password on <via> in a window I open, so it never passes through this chat.\"\n   On the host's own terminal, `ao remote-host enable` turns on the same network access, and `ao remote-host status` shows the address and the password.\n3. When the address arrives, check it looks like `http://<ip or name>:<port>`. Then, on `via`, write a one-time password window and open it. Replace `<name>` with the host name you checked: run \"Password window\" below.\n   Tell the user: \"A Terminal window opened on <via>. Type the password there and press Return.\"\n   On Linux, `open` doesn't run `.command` files: write the same lines to `~/.ao-grok/add-<name>.sh` and ask the user to run `zsh ~/.ao-grok/add-<name>.sh` in a terminal on `via`.\n4. When they say done, test it from `via`: run \"Connection test\" below.\n   HTTP 401 means a wrong password: open the window again. A timeout means the host is not reachable from `via` (another network, asleep, or access off).\n5. Add the host to the **AO hosts** note with `reach: remote`, `via`, `base` and `header`.\n\n### Password window\n```sh\nf(){ mkdir -p ~/.ao-grok/out && cat > ~/.ao-grok/add-<name>.command <<'EOF'\n#!/bin/zsh\numask 077\nread -rs \"p?AO password for <name>: \"; echo\nprintf 'Authorization: Bearer %s\\n' \"$p\" > ~/.ao-grok/<name>.header\necho \"Saved. You can close this window.\"; rm -- \"$0\"\nEOF\nchmod +x ~/.ao-grok/add-<name>.command && open ~/.ao-grok/add-<name>.command; }; f\n```\n\n### Connection test\n```sh\nf(){ <aoapi helper>; AO_REMOTE_BASE='<address>' AO_REMOTE_HEADER=\"$HOME/.ao-grok/<name>.header\" aoapi GET 'sessions?active=true' | python3 -c 'import json,sys; print(\"live_sessions=%d\" % len(json.load(sys.stdin)[\"sessions\"]))'; }; f\n```\n\nLimits of a remote host, said once: keep-awake, browser screenshots and starting a review work only on local hosts. For those, ask the host's orchestrator (ao-orchestrator). Quick-tunnel addresses change when the tunnel restarts, so prefer the LAN address or a named tunnel. If the user presses Regenerate in AO, run this section again.\n\n## 4. Mode and routines\n1. Save **Mode: default** in memory (ao-rules \"Decisions\"). Say in one line that away mode exists: \"Say 'I'm away till 6' and I'll keep routine work moving.\"\n2. Offer the routines in one multi-select card, nothing pre-selected, plus **none**:\n   - **AO waiting check**: every 30 minutes, 9:00 to 19:00 on weekdays. Runs ao-answer \"Find what's waiting\" and messages only when something new is waiting.\n   - **AO daily digest**: weekdays at 9:00. Runs ao-status \"Digest\".\n   Create the picked routines, then save \"Routines on: <names>\" in memory. Never create a second copy.\n3. Say once: \"AO's mobile app pushes questions to your phone the moment they happen. These routines check on a schedule.\"\n\n## 5. Finish\nOne line: the hosts saved (local and remote), the mode and the routines on. Then run ao-status as a first look, then:\n\nThings to try:\n- what's waiting on me\n- catch me up on <project>\n- in <project>: <what you want done>\n- I'm away till 6, keep things moving\n- what's ready to merge\n- show me what <session> built\n","integrations/grok-bot/skills/ao-answer/SKILL.md":"---\nname: ao-answer\ndescription: >-\n  Find AO sessions that wait on the user, show each question or approval as\n  tap-to-answer options, and send the answer back to that session, following\n  ao-rules \"Decisions\" (default, away mode, standing approvals). Use for\n  \"what's waiting on me\", \"answer <session>\", \"approve it\", the AO waiting\n  check routine, and away mode.\n---\nFollow the ao-rules skill. Its \"Decisions\" section says who may answer. Answers go straight to the worker, not through the orchestrator: the user's pick must arrive exactly as given.\n\n## 1. Find what's waiting\nOn every host, in parallel:\n```sh\nf(){ <aoapi helper>\n  aoapi GET 'sessions?active=true' | python3 -c '\nimport json,sys,time,calendar\nnow=time.time()\nfor s in json.load(sys.stdin)[\"sessions\"]:\n    st=(s.get(\"activity\") or {}).get(\"state\"); t=(s.get(\"lastEventAt\") or \"\")[:19]\n    if st in (\"waiting_input\",\"blocked\"): print(\"W\", s[\"id\"])\n    elif st==\"idle\" and t and now-calendar.timegm(time.strptime(t,\"%Y-%m-%dT%H:%M:%S\"))<86400: print(\"I\", s[\"id\"], s.get(\"lastEventAt\"))' |\n  while read -r k id at; do\n    if [ \"$k\" = W ]; then\n      aoapi GET \"sessions/$id/conversation\" | python3 -c '\nimport json,sys\nd=json.load(sys.stdin); found=False\nfor a in d.get(\"activities\") or []:\n    if a.get(\"activityKind\") in (\"approval\",\"user_input\") and a.get(\"status\")==\"pending\":\n        found=True; print(json.dumps({\"session\":sys.argv[1],\"kind\":a[\"activityKind\"],\"requestId\":a.get(\"requestId\"),\n            \"summary\":a.get(\"summary\"),\"decisions\":a.get(\"decisions\") or (a.get(\"detail\") or {}).get(\"decisions\"),\"detail\":a.get(\"detail\")}))\nif not found: print(json.dumps({\"session\":sys.argv[1],\"kind\":\"reply\"}))' \"$id\" 2>/dev/null\n    else\n      aoapi GET \"sessions/$id/history?offset=0&limit=1\" | python3 -c '\nimport json,sys,re\nt=(json.load(sys.stdin).get(\"turns\") or [{}])[0]; r=(t.get(\"agentResponse\") or \"\").strip()\nif re.search(r\"\\?[\\s*_`)\\]]*$\", r): print(json.dumps({\"session\":sys.argv[1],\"kind\":\"reply\",\"lastEventAt\":sys.argv[2],\"asked\":r[-300:]}))' \"$id\" \"$at\" 2>/dev/null\n    fi\n  done; }; f\n```\nEach line is one thing waiting:\n\n| `kind` | What it is |\n|---|---|\n| `approval` | Permission to run a command or change files. `summary` and `detail.input` say what; `decisions` are the options `[{id, kind, label}]` |\n| `user_input` | A question. `detail.message` asks it; `detail.schema.properties` are the fields, with choices in `enum` or `oneOf` |\n| `reply` | The agent asked in plain text: a session that waits with no request (or a terminal session), or an idle session from the last 24 hours whose last reply ends with a question (`asked` holds its end). Read its last reply (ao-status \"One session in detail\") |\n\nIn the **AO waiting check** routine: keep what you already showed in `~/.ao-grok/shown.txt` on `via`, one line per item (`<host> <session> <requestId>`, or `<host> <session> reply <lastEventAt>` for a `reply`), and message only about new items. Send nothing when nothing new is waiting.\n\n## 2. Show it\nPer session, one short briefing first: `<host>/<session>` and its name, what it is doing, and what it asks, in one or two sentences. Don't recommend anything. Then:\n- `approval`: the command or change verbatim, the risk you judge (ao-rules), and the `decisions` labels exactly as options in one card. Mark a decision whose `kind` is `allow_always` as \"changes this agent's permissions for good\".\n- `user_input`: one card with every question in it, in order (the card pages through them). A field with `oneOf` or `enum` is a question: use the `oneOf` titles or `enum` values as its options, exactly. A field whose `_meta._askUserQuestionCustomAnswer.questionId` names another field is that question's \"Other\" box: show it as a typed-answer option on that question, not as its own question. Any other free-text field is a question with a typed answer. `detail.inputMode` `url` can't be answered from chat: tell the user to open AO.\n- `reply`: the agent's question from its last reply, with options if it gave clear ones, else ask for a typed answer.\n\nSeveral sessions at once: explain them together, then cards per session.\n\n## 3. Answer\nOn the owner host, from its `via` computer:\n- **Approval**:\n  `aoapi POST \"sessions/<id>/conversation/approvals/<requestId>/resolve\" \"$(python3 -c 'import json,sys; print(json.dumps({\"decisionId\":sys.argv[1]}))' '<decision id>')\"`\n- **Question**: `content` maps each field name to the pick. For a picked option use its `oneOf` `const` (or the `enum` value), not the title. For a typed \"Other\" answer, put the text under the \"Other\" field (for example `question_0_custom`) and leave its question out:\n  `aoapi POST \"sessions/<id>/conversation/inputs/<requestId>/resolve\" \"$(python3 -c 'import json,sys; print(json.dumps({\"action\":\"accept\",\"content\":json.loads(sys.argv[1])}))' '{\"<field>\":\"<pick>\"}')\"`\n  The user says no or skip: `{\"action\":\"decline\"}`.\n- **reply**: send the answer as a message (ao-rules \"Messages to agents\"):\n  `aoapi POST \"sessions/<id>/send\" \"$(python3 -c 'import json,sys; print(json.dumps({\"message\":\"[via Grok Bot] \"+sys.argv[1],\"userAuthored\":True}))' '<answer>')\"`\n\nConfirm in one line. An error that says the request is not pending or not found means it was already answered or closed: say so. Then run step 1 for that session again, and deal with anything still open.\n\n## Away mode\nWhen memory says away mode is on and its end time hasn't passed, answer as ao-rules \"Decisions\" allows instead of showing cards, and log each one. Tell the user afterwards in one line per answer: session, what it asked, what you picked, why. Anything you may not decide: show it as in step 2, and say away mode left it for them.\n","integrations/grok-bot/skills/ao-orchestrator/SKILL.md":"---\nname: ao-orchestrator\ndescription: >-\n  Talk to a project's AO orchestrator: pass the user's request to it, wait for\n  its reply and relay it. The default route for starting or changing work,\n  \"catch me up\", \"why\", \"what next\" and plans. Use for \"in <project>: <ask>\",\n  \"tell the orchestrator ...\", \"catch me up on <project>\", \"start work on ...\".\n---\nFollow the ao-rules skill (\"Who does what: orchestrator first\"). Sending a message is a write: do it only for what the user asked in this turn.\n\n## 1. Pick the host and project\nMatch the user's words against project ids on every host (`aoapi GET projects`). One match: use it. The same project id on two hosts (two separate projects that share a folder name): ask which host, unless the user named one or memory has a default for that project. No match: list the projects and ask.\n\n## 2. Find the orchestrator\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions?orchestratorOnly=true&active=true&project=<project>\" | python3 -c '\nimport json,sys\nfor s in json.load(sys.stdin)[\"sessions\"]: print(s[\"id\"], (s.get(\"activity\") or {}).get(\"state\",\"\"), s.get(\"provisionState\",\"\"))'; }; f\n```\n- One line: that is the orchestrator. Its state tells you if it is busy (`active`).\n- `exited`: resume it first with `aoapi POST \"sessions/<id>/resume-agent\" '{}'`, then go on.\n- Provision state `failed`: AO could not create its workspace, and messages to it fail. Read the reason with `aoapi GET \"sessions/<id>\"` (field `provisionError`), tell the user in plain words, and ask them to fix it in AO. Stop here.\n- No line: ask \"There's no orchestrator in <project> on <host>. Start one with your request?\" On yes, start it with the request as its first message (step 3's file and tag), then go to step 4. Its reply is its first turn:\n\n### Start an orchestrator\n```sh\nf(){ <aoapi helper>; P='<project>'; TAG=\"[via Grok Bot #$(date +%H%M%S)]\"; F=~/.ao-grok/out/$(date +%F)-<short name>.md\n  mkdir -p ~/.ao-grok/out; { printf '%s ' \"$TAG\"; cat <<'EOF'\n<message>\nEOF\n  } > \"$F\"\n  H=$(aoapi GET \"projects/$P\" | python3 -c 'import json,sys; d=json.load(sys.stdin); c=(d.get(\"project\",d).get(\"config\") or {}); print((c.get(\"orchestrator\") or {}).get(\"agent\") or (c.get(\"worker\") or {}).get(\"agent\") or \"\")')\n  aoapi POST sessions \"$(python3 -c 'import json,sys; b={\"projectId\":sys.argv[1],\"kind\":\"orchestrator\",\"mode\":\"chat\",\"displayName\":\"Orchestrator\",\"prompt\":open(sys.argv[2]).read()}; b.update({\"harness\":sys.argv[3]} if sys.argv[3] else {}); print(json.dumps(b))' \"$P\" \"$F\" \"$H\")\" | python3 -c 'import json,sys; d=json.load(sys.stdin); d=d.get(\"session\",d); print(\"started\", d[\"id\"])' && echo \"TAG=$TAG\"; }; f\n```\nAfter about 10 seconds, check `provisionState` with `aoapi GET \"sessions/<new id>\"`. If it is `failed`, handle it as above.\n\n## 3. Send\nWrite the message to a file on `via`, then send it. The message is the user's request in their words, plus only the context from this chat the orchestrator needs. Don't add your own design choices. Start it with a tag so you can find the reply:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; TAG=\"[via Grok Bot #$(date +%H%M%S)]\"; F=~/.ao-grok/out/$(date +%F)-<short name>.md\n  mkdir -p ~/.ao-grok/out; { printf '%s ' \"$TAG\"; cat <<'EOF'\n<message>\nEOF\n  } > \"$F\"\n  B=$(python3 -c 'import json,sys; print(json.dumps({\"message\":open(sys.argv[1]).read(),\"userAuthored\":True}))' \"$F\")\n  if aoapi POST \"sessions/$O/send\" \"$B\" >/dev/null; then echo \"sent TAG=$TAG F=$F\"; return 0; fi\n  echo \"SEND_FAILED: resuming the agent and trying once more\"\n  aoapi POST \"sessions/$O/resume-agent\" '{}' >/dev/null; sleep 5\n  aoapi POST \"sessions/$O/send\" \"$B\" >/dev/null && echo \"sent TAG=$TAG F=$F\"; }; f\n```\nA failed send prints AO's error. If it still fails after the retry, tell the user the orchestrator isn't accepting messages and to open it in AO.\n\nIf the orchestrator was `active` in step 2, the message waits and runs as its own turn after the current one. Tell the user right away, in one line: \"The orchestrator is busy with <what its last turn is about>. Your question is queued and runs next.\" Then go on to step 4.\n\nIf the user wants to change what it is doing right now (\"stop that\", \"use X instead\"), steer instead. Write the file and tag as above, then:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; F='<message file>'\n  aoapi POST \"sessions/$O/conversation/steer-or-send\" \"$(python3 -c 'import json,sys,uuid; print(json.dumps({\"text\":open(sys.argv[1]).read(),\"clientMessageId\":str(uuid.uuid4())}))' \"$F\")\"; }; f\n```\n`\"outcome\":\"sent\"` means it arrived (in the running turn, or as a new turn if the orchestrator was idle). Then go to step 4.\n\n## 4. Wait for the reply\nCheck every 10 seconds for up to 5 minutes. Done when the orchestrator is no longer `active` and a turn that starts with your tag has a reply:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; TAG='<tag>'\n  for i in $(seq 30); do sleep 10\n    st=$(aoapi GET \"sessions/$O\" | python3 -c 'import json,sys; d=json.load(sys.stdin); d=d.get(\"session\",d); print((d.get(\"activity\") or {}).get(\"state\",\"\"))')\n    [ \"$st\" = active ] && continue\n    aoapi GET \"sessions/$O/history?offset=0&limit=5\" | python3 -c '\nimport json,sys\nfor t in json.load(sys.stdin).get(\"turns\") or []:\n    if (t.get(\"userRequest\") or \"\").startswith(sys.argv[1]) and t.get(\"agentResponse\"):\n        print(t[\"agentResponse\"]); raise SystemExit(0)\nraise SystemExit(1)' \"$TAG\" && return 0\n  done; echo STILL_WORKING; }; f\n```\n- A reply: relay it. Keep it faithful. Shorten only for a phone, and send a long reply as a file.\n- `STILL_WORKING`: tell the user the orchestrator is still on it, and offer: \"I'll message you when it replies.\" On yes, create a routine that runs step 4 once every 5 minutes for that tag, reports the reply, then deletes itself.\n- The orchestrator asks the user something back: show it as a card if it gives clear options, and send the pick as a new message (step 3).\n\n## 5. After\nIf the orchestrator started workers, list them in one line (ao-status \"Sessions\" for that project). Don't watch them unless the user asks. Their questions reach the user through ao-answer.\n","integrations/grok-bot/skills/ao-status/SKILL.md":"---\nname: ao-status\ndescription: >-\n  What AO is doing on every host: which sessions are running, waiting on the\n  user, idle or exited, which PRs are ready to merge or got a review, and a\n  daily digest. Read-only. Use for \"status\", \"what's running\", \"what's waiting\n  on me\", \"what's ready to merge\", \"anything stuck\", and the AO daily digest\n  routine.\n---\nFollow the ao-rules skill. Read-only in AO: it never marks anything read there. It keeps its own seen list in `~/.ao-grok/` on each `via` computer. Run on every host in the **AO hosts** note, in parallel, each from its `via` computer with the `aoapi` helper (set `AO_REMOTE_BASE` and `AO_REMOTE_HEADER` for remote hosts). If memory has no **AO hosts** note, run ao-setup first. Don't save hosts without the user's yes.\n\n## 1. Sessions\n```sh\nf(){ <aoapi helper>; aoapi GET 'sessions?active=true' | python3 -c '\nimport json,sys\nfor s in json.load(sys.stdin)[\"sessions\"]:\n    a=s.get(\"activity\") or {}\n    print(\"\\t\".join([s[\"id\"], s.get(\"kind\",\"\"), a.get(\"state\",\"\"), str(len(s.get(\"prs\") or [])), (s.get(\"displayName\") or \"\")[:60]]))'; }; f\n```\nColumns: id, kind (`orchestrator` or `worker`), state, PR count, name. States:\n\n| State | Say |\n|---|---|\n| `active` | running |\n| `waiting_input`, `blocked` | waiting on you |\n| `idle` | idle: finished its turn, or not started |\n| `exited` | the agent exited; it can be resumed (ao-actions) |\n\nFor what's waiting on the user, run ao-answer \"Find what's waiting\": it finds sessions in `waiting_input` or `blocked`, and idle sessions whose last reply asked the user a question. Never use notifications for it. Group by host, then by project (the session id starts with the project id).\n\nKeep the reply short enough for a phone, at most 6 lines: first what needs the user, then what's running, then one line per host with counts (for example \"MacBook Pro: 25 idle, 9 exited\"). Name a session only when it needs the user or is running. Leave out idle orchestrators, PR numbers and exited sessions unless asked. Report what you saw; don't guess why (a crash, a restart) unless the user asks.\n\n## 2. PRs and reviews\n```sh\nf(){ <aoapi helper>\n  aoapi GET 'notifications?status=unresolved' | python3 -c '\nimport json,sys\nfor n in json.load(sys.stdin)[\"notifications\"]:\n    if n.get(\"type\")==\"ready_to_merge\": print(\"\\t\".join([\"ready_to_merge\", n.get(\"sessionId\",\"\"), n.get(\"prUrl\",\"\"), (n.get(\"title\") or \"\")[:80]]))'\n  SEEN=\"$HOME/.ao-grok/<host name>.seen-news\"; mkdir -p ~/.ao-grok; touch \"$SEEN\"\n  aoapi GET 'notifications?status=unread' | python3 -c '\nimport json,sys\nseen=set(open(sys.argv[1]).read().split()); new=[]\nfor n in json.load(sys.stdin)[\"notifications\"]:\n    if n.get(\"type\") in (\"review_completed\",\"review_changes_requested\",\"pr_merged\",\"pr_closed_unmerged\") and not n.get(\"resolvedAt\") and n.get(\"id\") not in seen:\n        new.append(n[\"id\"]); print(\"\\t\".join([n[\"type\"], n.get(\"sessionId\",\"\"), n.get(\"prUrl\",\"\"), (n.get(\"title\") or \"\")[:80]]))\nopen(sys.argv[1],\"a\").writelines(i+\"\\n\" for i in new)' \"$SEEN\"\n  tail -n 500 \"$SEEN\" > \"$SEEN.tmp\" && mv \"$SEEN.tmp\" \"$SEEN\"; }; f\n```\n- `ready_to_merge` comes from the unresolved list, so a PR that was merged or changed since drops off. For \"what's ready to merge\", list these with the PR link, and offer the merge (ao-actions; needs the user's yes per PR).\n- `review_completed`, `review_changes_requested`, `pr_merged`, `pr_closed_unmerged` are news. The command prints only news this bot hasn't reported before, and records it as reported, so each item appears once, in a status reply or in the digest, whichever comes first. Mention each in one line. For \"what's new again\" or \"show all news\", run it without the seen list.\n- Never use `needs_input` notifications. They can outlive the wait (the session answered or exited); section 1 is the source for what's waiting.\n\n## 3. One session in detail\nFor \"what is <session> doing\": find it (ask which host if the id is on two hosts), then read its last turn:\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions/<id>/history?offset=0&limit=1\" | python3 -c '\nimport json,sys\nt=(json.load(sys.stdin).get(\"turns\") or [{}])[0]\nprint(\"asked:\", (t.get(\"userRequest\") or \"\")[:500]); print(\"replied:\", (t.get(\"agentResponse\") or \"\")[-1500:])'; }; f\n```\nSummarise in two or three lines. For \"catch me up on <project>\", ask the project's orchestrator instead (ao-orchestrator). It has the workers' reports.\n\n## Digest\nThe **AO daily digest** routine runs this skill. Per host: what finished since the last digest (idle sessions with `lastEventAt` since then), what's waiting on the user, what's ready to merge, and anything exited unexpectedly. Skip quiet projects. Send nothing if nothing happened and nothing is waiting. Write the time of this digest to `~/.ao-grok/<host name>.last-digest` on `via` and read it next time, instead of keeping it in memory.\n","integrations/grok-bot/skills/ao-rules/SKILL.md":"---\nname: ao-rules\ndescription: >-\n  Shared rules and the connection helper for every ao-* skill (run\n  Orchestrator from chat). Read before running any ao-* skill.\n---\n# AO rules\n\nEvery ao-* skill follows these rules. Other skills link here instead of repeating them.\n\n## AO hosts\nAn **AO host** is one computer that runs the AO daemon. Each host has its own projects, sessions and orchestrators, and AO never links them: a repo cloned on two hosts is two separate projects. AO names a project after its folder, so both can still get the same id, and then the same session id (for example `agent-orchestrator-1-12`) can exist on both. Always name a session as `<host>/<session id>`, and act only on the host that owns it.\n\nMemory keeps one note named **AO hosts**, with one line per host:\n\n| Field | Example | Meaning |\n|---|---|---|\n| `name` | `Pro` | A short name: the user's pick, else the model word of the ListMachines label (`Pro`, `Air`, `mini`). Never the network hostname such as `MacBookAir.lan` |\n| `reach` | `local` or `remote` | How you get to its AO |\n| `via` | `laptop` | The ListMachines label of the computer whose shell you use |\n| `base` | `http://192.168.1.20:7444` | Remote only. The host's LAN address from AO's remote access settings |\n| `header` | `~/.ao-grok/studio.header` | Remote only. File on `via` that holds the host's password |\n\n- **local**: the Grok Bot desktop app runs on the AO host. `via` is the host itself.\n- **remote**: the Grok Bot desktop app runs on another computer. You call the host's AO API over the network from `via`. The `ao` CLI on `via` talks only to `via`'s own AO, so never use it for a remote host.\n\nOne computer can be `via` for itself (local) and for other hosts (remote) at the same time.\n\nEvery run: call ListMachines, then use every host whose `via` computer is connected, in parallel, labelled by host name. Say once which hosts you could not reach. Never hard-code machine ids or home paths.\n\n## Calling AO\nStart every shell command that calls AO with this helper. It works in zsh and bash:\n\n```sh\naoapi(){ # aoapi METHOD PATH [JSON]\n  local base hdr=() data=() f=\"${AO_RUN_FILE:-$HOME/.ao/running.json}\"\n  if [ -n \"$AO_REMOTE_BASE\" ]; then base=\"$AO_REMOTE_BASE\"; hdr=(-H @\"$AO_REMOTE_HEADER\")\n  else [ -f \"$f\" ] || { echo \"AO_NOT_RUNNING\" >&2; return 3; }\n    base=\"http://127.0.0.1:$(grep -o '\"port\": *[0-9]*' \"$f\" | grep -o '[0-9]*$')\"; fi\n  [ -n \"$3\" ] && data=(--data \"$3\")\n  curl -sS --fail-with-body --max-time 30 -X \"$1\" \"${hdr[@]}\" -H 'Content-Type: application/json' \"${data[@]}\" \"$base/api/v1/$2\"\n}\n```\n\n- Local host: use `aoapi` as is.\n- Remote host: on the `via` computer, first set `AO_REMOTE_BASE='<base>' AO_REMOTE_HEADER=\"$HOME/.ao-grok/<name>.header\"`.\n- Build JSON bodies with `python3 -c 'import json,sys; print(json.dumps(...))' \"$ARG\"`, never by pasting text into quotes.\n- Anything longer than one line goes in a file first: `~/.ao-grok/out/<date>-<short name>.md` on `via`. The user can see what was sent.\n- Use the `ao` CLI only where a skill says \"local only\".\n\n### Errors\n| You see | Meaning and next step |\n|---|---|\n| `AO_NOT_RUNNING`, or connection refused on a local host | AO is not running there. Ask the user to open AO |\n| Connection refused or timeout on a remote host | The host is asleep, off this network, or remote access is off. Ask the user to check AO's remote access settings on the host |\n| HTTP 401 or 403 on a remote host | The host's password changed. Run ao-setup \"Remote host\" again |\n| HTTP 404 on a session path | No such session on that host. Check the host name |\n| Any other error | AO returns JSON with `message`. Relay it in plain words |\n\n## Who does what: orchestrator first\nEach project on a host has at most one live **orchestrator**: an agent that plans the project's work, starts and steers workers, and gets their reports. It has more context than you do. You are the user's phone line to it.\n\n- **Send to the orchestrator** (ao-orchestrator): starting or changing work, \"catch me up\", \"why\", \"what next\", plans, and anything that needs judgement about the code.\n- **Do directly**: status lists (ao-status), answering a pending request with the user's own pick (ao-answer), stop and interrupt, merges after the user's yes, files and screenshots (ao-actions).\n- Never start a worker yourself in a project that has a live orchestrator. Ask the orchestrator instead. With no orchestrator, ask the user whether to start one or to start the worker directly.\n- After you act directly on a worker (answer, stop, merge), the orchestrator sees it through AO. Don't send it a separate note.\n\n## Decisions\nA worker asks for two kinds of decision. A **question** (`user_input`) asks what to build. An **approval** asks permission to run a command or change files. Who decides depends on the mode, saved in memory:\n\n1. **Default mode**: show each question or approval to the user as a card with the exact options. Answer only with their pick for that request. Never reuse a pick for a new request.\n2. **Away mode** starts when the user says something like \"I'm away\", \"decide for me\" or \"keep it moving\". Save the scope and the end time in memory. Then:\n   - Answer routine questions yourself, and tell the user afterwards what you picked and why.\n   - Accept `low` and `normal` approvals with the one-time option (`kind` `allow_once`). Never pick an `allow_always` option: it changes the agent's permissions for good. Never accept a `high` approval without the user's yes for that request.\n   - Leave product direction, money, publishing and anything the user kept for themselves to the user.\n   - Away mode ends at the end time or when the user is back. Say when it ended.\n3. **Standing approvals**: the user may list kinds of approvals to always accept. Follow the list exactly.\n\nAO gives no risk level, so you judge it. Treat these as a floor. If a command looks riskier, call it high.\n\n| Risk | Examples |\n|---|---|\n| high | Deletes outside the session's worktree, `rm -rf`, `git push --force`, push to `main` or `master`, `git reset --hard`, history rewrites, deploy, publish, release, secrets, credentials, tokens, `sudo`, system installs, payments |\n| low | Reading or searching files, `git status`/`diff`/`log`, tests, lint, typecheck, builds |\n| normal | Everything else, such as edits and commits in the session's worktree, or pushing the session's own branch |\n\nNever invent the user's preferences. The worker decides how to do the work. The user decides what to build.\n\n## Writes\nChange nothing on the user's computers unless the user approved that exact change in chat, or away mode or a standing approval covers it. Approval for one change is not approval for the next. Never delete or archive sessions or projects, never change AO settings, and never merge, publish or deploy without the user's yes for that item.\n\n## Secrets\n- The `header` file holds a host's password. Pass it only to curl as `-H @<file>`. Never open, print, copy or paste it.\n- Never read AO's own credential files: `~/.ao/mobile/`, `~/.ao/data/agent-accounts/`, `~/.ao/electron/`, or any `*token*`, `*auth*`, `.env` or keychain item.\n- If session text contains a key, never repeat it.\n\n## Messages to agents\n- Before you send a follow-up, read the last turn (`aoapi GET \"sessions/<id>/history?offset=0&limit=1\"`) so you don't repeat or contradict it.\n- Keep messages short and concrete: what is right so far, then the next step. Leave out check-ins, your own process and these rules.\n- Start every message you send with `[via Grok Bot]`, so the user can tell it apart in AO.\n\n## Output\n- Answer first, in short plain words. Say what you could not check.\n- Write every session as `<host name>/<session id>`, every time, in every skill and every line, even when only one host has that id: `Air/agent-orchestrator-31`, `Pro/agent-orchestrator-1-249`. Add the display name when it helps.\n- Give times in the user's timezone.\n- One message per event. If two checks report the same thing, say it once. News (a merge, a finished review) is reported once: ao-status keeps a seen list.\n- Send files with SendToUser. Copy them to the box first with CopyToBox.\n\n## Memory\n- Save hosts, modes and preferences, not activity. A check where nothing changed is not worth a note.\n- When the user corrects you, save the correction.\n- A follow-up you promise for later (\"I'll tell you when it's done\") goes into a Routine, not only into memory.\n\n## Grok Bot only\nThese steps need tools only Grok Bot has. Any other agent (Claude Code, Codex, Cursor) runs on one computer and does this instead:\n\n| Grok Bot step | Other agents |\n|---|---|\n| ListMachines, every connected computer | Only the computer you run on, as a local host |\n| Routines | Run the check once when asked |\n| Cards | Plain text with numbered options |\n| Memory | Ask, or use the notes file the user names |\n| SendToUser, CopyToBox | Give the file path |\n","integrations/grok-bot/skills/ao-update/SKILL.md":"# ao-update\n\nPath: `integrations/grok-bot/skills/ao-update/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-update/SKILL.md)","AGENTS.md":"# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/AGENTS.md)","CLAUDE.md":"# Claude Agent Guidelines & System Prompt\n\nPath: `CLAUDE.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/CLAUDE.md)","DESIGN.md":"# UI Design System & Style Tokens\n\nPath: `DESIGN.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/DESIGN.md)","docs/architecture.md":"# docs - System Architecture & Module Boundaries\n\nPath: `docs/architecture.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/docs/architecture.md)","packages/ao-darwin-arm64/package.json":"# Ao-darwin-arm64 Skill\n\nPath: `packages/ao-darwin-arm64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-arm64/package.json)","packages/ao-darwin-x64/package.json":"# Ao-darwin-x64 Skill\n\nPath: `packages/ao-darwin-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-x64/package.json)","packages/ao-linux-x64/package.json":"# Ao-linux-x64 Skill\n\nPath: `packages/ao-linux-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-linux-x64/package.json)","packages/ao-win32-x64/package.json":"# Ao-win32-x64 Skill\n\nPath: `packages/ao-win32-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-win32-x64/package.json)","packages/ao/package.json":"# Ao Skill\n\nPath: `packages/ao/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao/package.json)","packages/cloud-client/README.md":"# cloud-client Documentation\n\nPath: `packages/cloud-client/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/README.md)","packages/cloud-client/package-lock.json":"# Cloud-client Skill\n\nPath: `packages/cloud-client/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/package-lock.json)","packages/cloud-client/package.json":"# Cloud-client Skill\n\nPath: `packages/cloud-client/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/package.json)","packages/cloud-client/tsconfig.json":"# Cloud-client Skill\n\nPath: `packages/cloud-client/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/tsconfig.json)","packages/cloud-client/tsconfig.test.json":"# Cloud-client Skill\n\nPath: `packages/cloud-client/tsconfig.test.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/tsconfig.test.json)","packages/mobile/README.md":"# mobile Documentation\n\nPath: `packages/mobile/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/README.md)","packages/mobile/app.json":"# Mobile Skill\n\nPath: `packages/mobile/app.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/app.json)","packages/mobile/eas.json":"# Mobile Skill\n\nPath: `packages/mobile/eas.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/eas.json)","packages/mobile/package-lock.json":"# Mobile Skill\n\nPath: `packages/mobile/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/package-lock.json)","packages/mobile/package.json":"# Mobile Skill\n\nPath: `packages/mobile/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/package.json)","packages/mobile/tsconfig.json":"# Mobile Skill\n\nPath: `packages/mobile/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/tsconfig.json)","packages/product-ui/README.md":"# product-ui Documentation\n\nPath: `packages/product-ui/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/README.md)","packages/product-ui/package-lock.json":"# Product-ui Skill\n\nPath: `packages/product-ui/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/package-lock.json)","packages/product-ui/package.json":"# Product-ui Skill\n\nPath: `packages/product-ui/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/package.json)","packages/product-ui/tsconfig.build.json":"# Product-ui Skill\n\nPath: `packages/product-ui/tsconfig.build.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/tsconfig.build.json)","packages/product-ui/tsconfig.json":"# Product-ui Skill\n\nPath: `packages/product-ui/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/tsconfig.json)","packages/mobile/scripts/README.md":"# scripts Documentation\n\nPath: `packages/mobile/scripts/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/scripts/README.md)",".agents/skills/ao-desktop-dev/agents/openai.yaml":"# Agents Skill\n\nPath: `.agents/skills/ao-desktop-dev/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.agents/skills/ao-desktop-dev/agents/openai.yaml)",".claude/skills/bug-triage/scripts/push_fix_to_github.py":"# Claude Directive: push_fix_to_github.py\n\nPath: `.claude/skills/bug-triage/scripts/push_fix_to_github.py`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.claude/skills/bug-triage/scripts/push_fix_to_github.py)","packages/mobile/assets/AO.icon/icon.json":"# AO.icon Skill\n\nPath: `packages/mobile/assets/AO.icon/icon.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/assets/AO.icon/icon.json)","packages/mobile/native/image-paste/package.json":"# Image-paste Skill\n\nPath: `packages/mobile/native/image-paste/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/native/image-paste/package.json)","packages/mobile/native/response-selection/package.json":"# Response-selection Skill\n\nPath: `packages/mobile/native/response-selection/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/native/response-selection/package.json)","backend/internal/skillassets/using-ao/commands/automation.md":"# Command: /automation\n\nPath: `backend/internal/skillassets/using-ao/commands/automation.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/automation.md)","backend/internal/skillassets/using-ao/commands/browser-remote.md":"# Command: /browser-remote\n\nPath: `backend/internal/skillassets/using-ao/commands/browser-remote.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/browser-remote.md)","backend/internal/skillassets/using-ao/commands/browser.md":"# Command: /browser\n\nPath: `backend/internal/skillassets/using-ao/commands/browser.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/browser.md)","backend/internal/skillassets/using-ao/commands/cua.md":"# Command: /cua\n\nPath: `backend/internal/skillassets/using-ao/commands/cua.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/cua.md)","backend/internal/skillassets/using-ao/commands/cue.md":"# Command: /cue\n\nPath: `backend/internal/skillassets/using-ao/commands/cue.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/cue.md)","backend/internal/skillassets/using-ao/commands/doctor.md":"# Command: /doctor\n\nPath: `backend/internal/skillassets/using-ao/commands/doctor.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/doctor.md)","backend/internal/skillassets/using-ao/commands/import.md":"# Command: /import\n\nPath: `backend/internal/skillassets/using-ao/commands/import.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/import.md)","backend/internal/skillassets/using-ao/commands/orchestrator.md":"# Command: /orchestrator\n\nPath: `backend/internal/skillassets/using-ao/commands/orchestrator.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/orchestrator.md)","backend/internal/skillassets/using-ao/commands/preview.md":"# Command: /preview\n\nPath: `backend/internal/skillassets/using-ao/commands/preview.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/preview.md)","backend/internal/skillassets/using-ao/commands/project.md":"# Command: /project\n\nPath: `backend/internal/skillassets/using-ao/commands/project.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/project.md)","backend/internal/skillassets/using-ao/commands/remote-host.md":"# Command: /remote-host\n\nPath: `backend/internal/skillassets/using-ao/commands/remote-host.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/remote-host.md)","backend/internal/skillassets/using-ao/commands/render.md":"# Command: /render\n\nPath: `backend/internal/skillassets/using-ao/commands/render.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/render.md)","backend/internal/skillassets/using-ao/commands/report.md":"# Command: /report\n\nPath: `backend/internal/skillassets/using-ao/commands/report.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/report.md)","backend/internal/skillassets/using-ao/commands/review.md":"# Command: /review\n\nPath: `backend/internal/skillassets/using-ao/commands/review.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/review.md)","backend/internal/skillassets/using-ao/commands/send.md":"# Command: /send\n\nPath: `backend/internal/skillassets/using-ao/commands/send.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/send.md)","backend/internal/skillassets/using-ao/commands/session.md":"# Command: /session\n\nPath: `backend/internal/skillassets/using-ao/commands/session.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/session.md)","backend/internal/skillassets/using-ao/commands/spawn.md":"# Command: /spawn\n\nPath: `backend/internal/skillassets/using-ao/commands/spawn.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/spawn.md)","backend/internal/skillassets/using-ao/commands/start.md":"# Command: /start\n\nPath: `backend/internal/skillassets/using-ao/commands/start.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/start.md)","backend/internal/skillassets/using-ao/commands/status.md":"# Command: /status\n\nPath: `backend/internal/skillassets/using-ao/commands/status.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/status.md)","backend/internal/skillassets/using-ao/commands/stop.md":"# Command: /stop\n\nPath: `backend/internal/skillassets/using-ao/commands/stop.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/stop.md)","frontend/src/docs/content/plugins/meta.json":"# Plugins Skill\n\nPath: `frontend/src/docs/content/plugins/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/meta.json)","packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json":"# CircleDashedCheck.imageset Skill\n\nPath: `packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json)","frontend/src/docs/content/plugins/agents/meta.json":"# Agents Skill\n\nPath: `frontend/src/docs/content/plugins/agents/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/agents/meta.json)","frontend/src/docs/content/plugins/notifiers/meta.json":"# Notifiers Skill\n\nPath: `frontend/src/docs/content/plugins/notifiers/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/notifiers/meta.json)","frontend/src/docs/content/plugins/runtimes/meta.json":"# Runtimes Skill\n\nPath: `frontend/src/docs/content/plugins/runtimes/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/runtimes/meta.json)","frontend/src/docs/content/plugins/scm/meta.json":"# Scm Skill\n\nPath: `frontend/src/docs/content/plugins/scm/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/scm/meta.json)","frontend/src/docs/content/plugins/terminals/meta.json":"# Terminals Skill\n\nPath: `frontend/src/docs/content/plugins/terminals/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/terminals/meta.json)","frontend/src/docs/content/plugins/trackers/meta.json":"# Trackers Skill\n\nPath: `frontend/src/docs/content/plugins/trackers/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/trackers/meta.json)","frontend/src/docs/content/plugins/workspaces/meta.json":"# Workspaces Skill\n\nPath: `frontend/src/docs/content/plugins/workspaces/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/workspaces/meta.json)"},"files":{"backend/internal/skillassets/using-ao/SKILL.md":"---\nname: using-ao\ndescription: \"Catalog of the AO (Agent Orchestrator) `ao` CLI: spawning workers, managing sessions and projects, creating reusable Cues, sending messages, controlling the shared browser, previewing pages, and daemon control. Use when using the ao CLI, creating Cues, spawning workers, or managing AO sessions in an AO workspace.\"\ntrigger: \"Using the ao CLI in an AO workspace: creating Cues, spawning workers, managing sessions/projects, sending messages, controlling or previewing pages.\"\n---\n\n# AO CLI Catalog\n\n`ao` is a thin CLI over the local AO daemon. Every command is `ao <command> --help` for the authoritative flag list.\n\n| Command | What it does | When to use | Details |\n|---|---|---|---|\n| `spawn` | Spawn a project worker, orchestrator, or projectless standalone worker | Starting a new task or issue | [commands/spawn.md](commands/spawn.md) |\n| `session` | Manage agent sessions (list, kill, rename, restore, history, etc.) | Inspecting or controlling running/terminated sessions, or reading the full conversation after taking over from another agent | [commands/session.md](commands/session.md) |\n| `agent` | Inspect installed harnesses and launch readiness | Choosing or diagnosing an agent harness | `ao agent ls --refresh` |\n| `pr` | Merge a PR or resolve its review threads | Completing a reviewed change | `ao pr merge` / `ao pr resolve-comments` |\n| `project` | Register, inspect, configure, or remove projects | Setting up or managing repos AO knows about | [commands/project.md](commands/project.md) |\n| `automation` | Manage durable recurring session automations | Creating, editing, disabling, deleting, and inspecting scheduled runs | [commands/automation.md](commands/automation.md) |\n| `cue` | Create or list reusable project Cues | Saving a repetitive command or agent task at the user's request | [commands/cue.md](commands/cue.md) |\n| `orchestrator` | List orchestrator sessions | Viewing which sessions are orchestrators | [commands/orchestrator.md](commands/orchestrator.md) |\n| `review` | Start, list, cancel, or submit AO's native reviewer for a worker's PR (default: this session) | Reviewing implementation PRs owned by AO workers. Use a normal review-only worker for someone else's PR | [commands/review.md](commands/review.md) |\n| `send` | Send a message to a running agent session | Messaging a live agent; use `--steer` to correct it mid-turn | [commands/send.md](commands/send.md) |\n| `report` | Persist a meaningful worker report | Checkpoints, blockers, decisions, outputs, and completion | [commands/report.md](commands/report.md) |\n| `preview` | Start a session-owned app or open an exact URL/file | Running and showing the worker's relevant app, Markdown, HTML, PDF, or image | [commands/preview.md](commands/preview.md) |\n| `render` | Show a self-contained HTML page inline in a chat thread | Answering with a chart, table, diagram, or mockup | [commands/render.md](commands/render.md) |\n| `browser` | Inspect and control the session's shared live browser | Verifying a web app through snapshots, interactions, waits, screenshots, console, and errors | [commands/browser.md](commands/browser.md) |\n| `browser` (remote host) | Drive the host's shared remote Chromium, used when `AO_AGENT_BROWSER_URL` is set | Same browser verification on a self-hosted remote host; one browser is shared across sessions | [commands/browser-remote.md](commands/browser-remote.md) |\n| `remote-host` | Link this machine to the user's AO account, or turn its remote access on or off | Setting up a VM or other headless machine so the user's desktops and phones can use it | [commands/remote-host.md](commands/remote-host.md) |\n| `start` | Fetch (if needed) and open the AO desktop app | Launching the app | [commands/start.md](commands/start.md) |\n| `stop` | Stop the AO daemon | Shutting down AO | [commands/stop.md](commands/stop.md) |\n| `status` | Show daemon status | Verifying the daemon is up and healthy | [commands/status.md](commands/status.md) |\n| `doctor` | Run local health checks | Diagnosing AO setup problems | [commands/doctor.md](commands/doctor.md) |\n| `import` | Import projects from a legacy AO install | Migrating from the old flat-file store | [commands/import.md](commands/import.md) |\n| `version` | Print version information | Checking installed version | - |\n| `completion` | Generate shell completion scripts | Setting up tab completion | - |\n\n## Conventions\n\n- Most read commands accept `--json` for machine-readable output.\n- `-p / --project` scopes session subcommand lookups to one project.\n- Session and project ids are shown by `ao session ls` and `ao project ls`.\n- To refer to a session in AO Chat or the AO terminal, use the canonical in-app\n  link `ao://sessions/{project-id}/{session-id}`. Read\n  [commands/session.md](commands/session.md) for identity, encoding, and safety\n  rules before constructing one.\n- When the user asks to save a repeatable task as a Cue, use `ao cue list --json` to check existing definitions, then `ao cue create`. An agent Cue stores a reusable instruction; a command Cue stores an exact shell command. This agent-facing command can create and read Cues, but cannot edit or delete them. Direct the user to project settings for changes to existing Cues.\n- `--agent` is an alias for `--harness` on `ao spawn`.\n- Every command accepts `-h / --help` for the full flag list.\n- For frontend launch, preview selection, or artifact handoff, read\n  [commands/preview.md](commands/preview.md) before acting. Its static-file,\n  project-runtime, and automatic-handoff rules are load-bearing.\n- For page inspection, interaction, or request diagnosis, read\n  [commands/browser.md](commands/browser.md). It defines shared-tab behavior\n  and the opt-in network policy.\n\nUse [references.md](references.md) only when a natural-language request does\nnot map clearly to a command above.\n",".agents/skills/pr-description/SKILL.md":"---\nname: pr-description\ndescription: Write and maintain pull request descriptions in this repository, including the required change-count header, the before-and-after section, and screenshots or recordings for visible changes.\n---\n\n# PR description\n\nUse the section order in `.github/pull_request_template.md`: change-count header,\nWhat, Why, Before / After, How, Testing, Checklist. Preserve the rest of an existing\nPR description when updating it.\n\n## Change-count header\n\nBegin every PR description with these three lines, using Markdown hard line breaks\nso each renders separately:\n\n```text\nCode changes: +<added> -<deleted>\nTests: +<added> -<deleted>\nOthers: +<added> -<deleted>\n```\n\nCalculate the numbers from the net diff against the PR's actual base. For a local\nbranch, use `git diff --numstat <base>...<head>`. After pushing, prefer GitHub's\nper-file additions and deletions. Recalculate after the final push rather than\nsumming commit churn or estimating counts.\n\nCount every changed file exactly once:\n\n- **Code changes:** handwritten implementation, including SQL, migrations, styles,\n  and executable scripts.\n- **Tests:** test code, fixtures, snapshots, and test-only helpers.\n- **Others:** generated or vendored files, lockfiles, documentation, configuration,\n  and assets. Generated output belongs here even when it contains source code.\n\nShow `+0 -0` for empty categories. Binary files have no line count; mention their\ncount separately when present. Add a brief qualifier when useful, such as\n`Others: +11 -0 (generated sqlc)`.\n\n## Before / After\n\nEvery PR has a `## Before / After` section with a two-column table, one row per\nbehavior that changed:\n\n```markdown\n| Before | After |\n| --- | --- |\n| ![Before: empty model list](before.png) | ![After: list filtered to six models](after.png) |\n| `ao session ls` exits 1 when a project has no sessions | Prints `No sessions` and exits 0 |\n```\n\n- **UI changes** need a screenshot of each changed state, before and after. Use a\n  short recording for flows, animations, focus or keyboard behavior, and timing.\n- **Non-visual changes** compare observable behavior: command output, API\n  responses, errors, logs, or measured numbers with their units.\n- **No user-visible change:** write `No user-visible change` and one line saying why,\n  such as an internal refactor or a test-only change.\n\nCapture both sides from the real app with the same screen, window size, and data,\nso they compare directly. Take the before capture from the PR's base branch. The\n`ao-desktop-dev` skill launches the desktop app from a checkout.\n\nScreenshots and GIFs go in the table. GitHub renders a video player only for a\nbare attachment URL on its own line, so put MP4 or MOV recordings on their own\nline below the table, with one line saying what they show.\n\nNever commit screenshots or recordings to the repository. Attach them in the PR\ndescription, or in a PR comment when the description gets long. If you cannot\nupload, give the capture file paths to the person who will attach them. Remove\nsecrets, tokens, and personal data from every capture.\n\n## Verify\n\nAfter creating or updating the PR, read the published description and verify that:\n\n- its opening lines match the current GitHub diff counts and required order;\n- every image and recording in Before / After, or in a PR comment, loads.\n",".claude/skills/ao-desktop-dev/SKILL.md":"---\nname: ao-desktop-dev\ndescription: Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data.\n---\n\n# AO Desktop Dev\n\nRead and follow [`../../../.agents/skills/ao-desktop-dev/SKILL.md`](../../../.agents/skills/ao-desktop-dev/SKILL.md) completely before launching or troubleshooting the desktop app. That file is the canonical cross-agent workflow for this repository.\n",".claude/skills/bug-triage/SKILL.md":"---\nname: bug-triage\ndescription: Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft.\n---\n\n# Bug triage\n\nRead and follow [`../../../.agents/skills/bug-triage/SKILL.md`](../../../.agents/skills/bug-triage/SKILL.md) completely before clarifying, drafting, or filing anything. That file is the canonical cross-agent workflow for this repository.\n","integrations/grok-bot/skills/ao-actions/SKILL.md":"---\nname: ao-actions\ndescription: >-\n  Direct actions on one AO session or PR: stop or interrupt, resume, merge a PR,\n  start a review, screenshot a session's browser, send a session's files, keep\n  a host awake, and recurring AO automations. Use for \"stop <session>\",\n  \"merge <PR>\", \"review <session>'s PR\", \"show me what <session> built\",\n  \"keep the Mac awake tonight\", \"every night, ...\".\n---\nFollow the ao-rules skill. Find the session first (ao-rules \"AO hosts\": `<host>/<session id>`). Run each action on the owner host from its `via` computer. \"Yes\" means the user's yes for that exact action in this chat.\n\n| Ask | Do | Yes needed | Hosts |\n|---|---|---|---|\n| Stop what it's doing now | `aoapi POST \"sessions/<id>/conversation/interrupt\"` | No | All |\n| End the session | `aoapi POST \"sessions/<id>/kill\" '{}'` | Yes | All |\n| Resume an exited agent | `aoapi POST \"sessions/<id>/resume-agent\" '{}'` | No | All |\n| Restore an ended session | `aoapi POST \"sessions/<id>/restore\" '{}'` (an ended orchestrator can't come back while its project has another live one) | Yes | All |\n| Merge a PR | see \"Merge\" | Yes, per PR | All |\n| Start AO's reviewer on a session's PR | `ao review trigger <id>` | Yes | Local |\n| Screenshot a session's browser | see \"Screenshot\" | No | Local |\n| A session's files | see \"Files\" | No | Local |\n| Keep the host awake | see \"Keep awake\" | Yes | Local |\n| Recurring agent work | see \"Automations\" | Yes | Local |\n| Start one worker directly | `aoapi POST sessions '<json>'` with `projectId`, `displayName`, `prompt` | Yes | All |\n\nFor an action marked Local on a remote host, ask that host's orchestrator to do it (ao-orchestrator).\n\nStart a worker directly only when the project has no orchestrator and the user doesn't want one (ao-rules \"orchestrator first\").\n\n## Merge\nFirst show the PR and ask:\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions/<session id>/pr\" | python3 -c '\nimport json,sys\nfor p in json.load(sys.stdin).get(\"prs\") or []:\n    if str(p.get(\"number\"))==sys.argv[1]: print(json.dumps({\"url\":p.get(\"url\"),\"headSha\":p.get(\"headSha\"),\"state\":p.get(\"state\"),\n        \"ci\":(p.get(\"ci\") or {}).get(\"state\"),\"review\":(p.get(\"review\") or {}).get(\"decision\"),\"mergeability\":(p.get(\"mergeability\") or {}).get(\"state\")}))' '<pr number>'; }; f\n```\nTell the user the link, checks (`ci`), review decision and whether it can merge (`mergeability`). Never merge on failing checks or `conflicting` without the user saying so for that PR. On yes, merge exactly the commit you showed:\n```sh\nf(){ <aoapi helper>; aoapi POST \"prs/<pr number>/merge\" \"$(python3 -c 'import json,sys; print(json.dumps({\"prUrl\":sys.argv[1],\"expectedHeadSha\":sys.argv[2]}))' '<url>' '<headSha>')\"; }; f\n```\nIf the PR got new commits since you showed it, AO refuses the merge. Show it again and ask again.\n\n## Screenshot\nThe session must have a browser page open. `BROWSER_CAPABILITY_INVALID` means it has none: say so.\n```sh\nf(){ mkdir -p ~/.ao-grok/out && AO_SESSION_ID='<id>' ao browser screenshot ~/.ao-grok/out/<id>-$(date +%H%M%S).png; }; f\n```\nThen CopyToBox and SendToUser.\n\n## Files\nA session's deliverables are in its artifact folder:\n```sh\nf(){ ls -la \"${AO_DATA_DIR:-$HOME/.ao/data}/artifacts/<id>/\"; }; f\n```\nSend the file the user asks for with CopyToBox and SendToUser. HTML reports render best opened on the phone as a file.\n\n## Keep awake\nFor a run that must last overnight, after a yes:\n```sh\nf(){ <aoapi helper>; aoapi POST awake/sessions \"$(python3 -c 'import json,sys; print(json.dumps({\"mode\":\"duration\",\"durationSeconds\":int(sys.argv[1]),\"scope\":\"ao\"}))' '<seconds>')\"; }; f\n```\nSay when it ends. The user can stop it in AO. An `AWAKE` error that mentions a safety stop means AO stopped keep-awake on purpose (for example on battery): tell the user to resume it in AO. Don't resume it yourself.\n\n## Automations\nFor recurring agent work that should run on the host even when the bot is off (for example \"every night, update dependencies in <project>\"), create an AO automation after a yes:\n```sh\nao automation create --project '<project>' --name '<name>' --cron '<m h dom mon dow>' --timezone '<IANA zone>' --prompt '<task>'\n```\n`ao automation list` shows them. To remove one after a yes: `ao automation delete --yes <id>`. Use a Grok routine instead when the job is to tell the user something (ao-status \"Digest\", ao-answer waiting check).\n",".agents/skills/ao-desktop-dev/SKILL.md":"---\nname: ao-desktop-dev\ndescription: Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data.\n---\n\n# AO Desktop Dev\n\nRun the Electron application from the current checkout and verify it in the native window. Keep the dev daemon, renderer, Electron preload, and selected data mode explicit so the user never reviews a mock or stale build by accident.\n\n## Choose the data mode\n\nAsk only when the request does not make the desired data source clear.\n\n- Use **isolated mode** by default for implementation and destructive testing. Electron uses port `3002`, `~/.ao/dev/running.json`, `~/.ao/dev/data`, and `~/.ao/dev/electron`.\n- Use **real-data mode** only when the user explicitly asks to see this machine's actual AO projects or sessions. Start the checkout's dev daemon on the isolated dev port/run file while pointing `AO_DATA_DIR` at the real AO data directory. This is a separate daemon process using real data; do not describe it as the installed app's daemon.\n- Never try to attach an unpackaged Electron app directly to a packaged daemon from another checkout. The supervisor intentionally rejects daemon identity mismatches.\n- Warn before actions in real-data mode that create, terminate, rename, or otherwise mutate sessions. Merely opening and inspecting the UI is expected.\n- Real-data mode reads the same database as the installed app, and only one daemon can own a data directory. Quit the packaged app first: while its daemon runs, the dev daemon waits for the data-dir lock (9 x `AO_SHUTDOWN_TIMEOUT` + 18s, 108s by default) and then exits with code 75. The dev window is marked with an `Agent Orchestrator (dev)` title, an orange-badged `DEV` dock icon, and an in-app `dev` badge — verify those markers before acting.\n\n## Preflight\n\n1. Work from the repository root and inspect `git status --short --branch`.\n2. Read `frontend/package.json`, `frontend/src/main.ts`, and `frontend/forge.config.ts` when the launch behavior may have changed. Treat source as authoritative over this skill.\n3. Confirm Node/npm and the Go version required by `backend/go.mod` are available. Run `npm ci` in `frontend/` only when dependencies are absent or inconsistent; do not reinstall on every launch.\n4. Check for an existing dev instance from this exact checkout before starting another. Do not kill by process name alone, and never terminate every Electron process.\n\nOn macOS/Linux, inspect checkout-scoped processes and listeners with finite commands:\n\n```bash\nps -axo pid=,ppid=,pgid=,lstart=,command= | rg 'frontend/(node_modules/.bin/electron-forge|node_modules/electron/dist/Electron)'\nlsof -nP -iTCP:3002 -sTCP:LISTEN\n```\n\nUse the full command paths and start times to distinguish this checkout from other AO worktrees. On Windows, use `Get-CimInstance Win32_Process` and `Get-NetTCPConnection`; preserve the same exact-target rule.\n\n## Launch the app\n\nRun Electron Forge in a foreground interactive process so its output and restart input remain available. Do not append `&`, use a detached shell, or start a browser preview instead.\n\n### Isolated mode\n\nOn macOS/Linux:\n\n```bash\ncd frontend\nenv -u AO_DATA_DIR -u AO_RUN_FILE -u AO_PORT npm run dev\n```\n\nOn PowerShell:\n\n```powershell\nSet-Location frontend\nRemove-Item Env:AO_DATA_DIR, Env:AO_RUN_FILE, Env:AO_PORT -ErrorAction SilentlyContinue\nnpm run dev\n```\n\n### Real-data mode\n\nFirst resolve and report the actual data directory. In an AO worker session, `AO_DATA_DIR` normally already identifies it. Otherwise the repository default is the absolute path corresponding to `~/.ao/data`.\n\nKeep the real data directory but remove inherited port/run-file overrides so the dev app retains its own daemon handshake and port:\n\n```bash\ncd frontend\nenv -u AO_RUN_FILE -u AO_PORT AO_DATA_DIR=\"${AO_DATA_DIR:-$HOME/.ao/data}\" npm run dev\n```\n\nPowerShell equivalent:\n\n```powershell\nSet-Location frontend\n$realAoData = if ($env:AO_DATA_DIR) { $env:AO_DATA_DIR } else { Join-Path $HOME \".ao/data\" }\nRemove-Item Env:AO_RUN_FILE, Env:AO_PORT -ErrorAction SilentlyContinue\n$env:AO_DATA_DIR = $realAoData\nnpm run dev\n```\n\nDo not print unrelated environment variables: AO sessions may carry credentials. It is safe to report only `AO_DATA_DIR`, `AO_RUN_FILE`, and `AO_PORT`.\n\n## Confirm the correct app is ready\n\nWait for all of these signals:\n\n- Electron Forge reports `Launched Electron app`.\n- The daemon reports `daemon listening`, normally on `127.0.0.1:3002` unless it explicitly reports another bound port.\n- The renderer makes successful requests such as `/api/v1/projects` and `/api/v1/sessions`.\n- The native Electron window shows the checkout's UI. A Vite URL opened in a normal browser is not equivalent because it lacks the Electron preload bridge.\n\nIf several AO windows exist, identify the newest Electron main process belonging to this checkout. On macOS, foreground that exact PID only when needed:\n\n```bash\nosascript -e 'tell application \"System Events\" to set frontmost of first process whose unix id is <verified-pid> to true'\n```\n\nDo not claim real data from appearance alone. Verify the selected data directory and successful API responses. Do not claim visual success from compilation alone; interact with the requested flow in Electron or ask the user for a screenshot when screen capture is unavailable.\n\n## Reload changes correctly\n\n- Renderer-only React/CSS changes normally hot reload.\n- Changes to `frontend/src/main.ts`, preload files, Forge configuration, shared bridge types, or IPC registration require an Electron main-process restart. Type `rs` into the active Forge terminal or fully stop and relaunch the dev process.\n- A renderer error such as `aoBridge.<method> is not a function` almost always means the renderer hot-reloaded against a stale preload. Restart Electron before changing code to add guards around a bridge method that should exist.\n- Backend changes require restarting the managed dev daemon or the Electron process; renderer hot reload cannot apply Go changes.\n\nAfter a restart, confirm the new Electron PID/start time and re-check the logs for the original error.\n\n## Preview multiple PRs locally\n\nWhen the user wants to see multiple unmerged PRs together:\n\n1. Require a clean worktree and fetch each PR head.\n2. Create a clearly named local-only integration branch using the session/repository branch convention.\n3. Merge or cherry-pick the requested PR heads without rewriting or pushing either source branch.\n4. Resolve overlaps according to the requested combined behavior and run focused typechecks/tests.\n5. Let renderer changes hot reload; restart Electron if either PR changes main/preload/IPC code.\n6. State that the integration branch is local-only. Do not push it unless the user explicitly requests a combined PR.\n\nOnce one PR merges, prefer rebasing the remaining PR onto current `main`; the normal PR branch then contains both views without a local integration merge.\n\n## Stop without collateral damage\n\n1. Send Ctrl+C to the foreground dev process and wait briefly for Electron and its managed daemon to exit.\n2. Re-run the checkout-scoped process query. If the exact process group remains, identify the group created by this launch before sending `TERM` to that group.\n3. On Windows, terminate the verified parent tree only. Never use a broad Electron, Node, Go, or port-based kill.\n4. Confirm the captured Electron PID and dev daemon listener are gone. Leave installed AO and other worktrees untouched.\n\n## Common mistakes\n\n- `ao preview` controls the AO Browser panel; it does not launch the desktop shell.\n- `npm run dev:web` is useful for browser-only renderer work but does not provide Electron APIs or native chrome.\n- Renderer URLs can move from `5173` when a port is occupied. Trust Forge's printed URL rather than assuming one.\n- Multiple dev instances share `~/.ao/dev/electron` by default, and Chromium's\n  singleton lock lives in the profile, so a second checkout's `npm run dev`\n  loses `requestSingleInstanceLock()` and exits immediately with code 0. To run\n  two worktrees at once, give each its own profile, run file, and data dir:\n\n  ```bash\n  env -u AO_PORT \\\n    AO_DEV_ELECTRON_DIR=\"$HOME/.ao/dev/<name>/electron\" \\\n    AO_RUN_FILE=\"$HOME/.ao/dev/<name>/running.json\" \\\n    AO_DATA_DIR=\"$HOME/.ao/dev/<name>/data\" \\\n    npm run dev\n  ```\n\n  Without all three the instances still collide, on the profile lock, the run\n  file, or the daemon's SQLite data.\n- An inherited `AO_DATA_DIR` changes dev mode from isolated data to real data. Always choose and report the mode instead of inheriting it accidentally.\n- Repeated `/healthz/` 404 entries from external probes can be noisy; readiness is determined by Electron's daemon status and successful API traffic, not by log volume.\n\n## Completion report\n\nReport:\n\n- checkout and branch being displayed;\n- isolated or real-data mode and the non-sensitive data/run-file paths;\n- renderer and daemon addresses actually reported;\n- whether Electron was restarted for main/preload changes;\n- user flows exercised in the native window;\n- any remaining stale process, port, or visual-verification limitation.\n",".agents/skills/bug-triage/SKILL.md":"---\nname: bug-triage\ndescription: Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft.\n---\n\n# Bug triage\n\nHelp the reporter describe what they observed and add useful evidence. A short human\nobservation is enough to report a bug; reproduction, logs, and a diagnosis are optional.\nUse this skill for reports from chat, an existing issue, or a local user.\n\n## Clarify the observation\n\nRead the available report, screenshots, and follow-ups first. Preserve the original\nreporter's words and attribution, including when someone else relays their report.\nDon't infer a GitHub username from a chat display name.\n\nAsk only questions that would materially clarify the symptom, a few at a time. Don't\nrepeat questions already answered or turn these suggestions into required fields:\n\n- What did you do, and what happened instead of what you expected?\n- Where did it happen, and does it happen every time or only sometimes?\n- For a visual problem, can you share a screenshot or short recording showing it?\n- If relevant, which AO version and OS were you using, and did it start after a change?\n\nIf a screenshot is unavailable, accept a description. If the reporter cannot remember\nsteps or reproduce the problem, preserve that uncertainty and proceed with what is\nknown. Never invent steps or make the reporter diagnose the bug before accepting it.\n\n## Keep the report and investigation separate\n\nDraft a specific symptom-based title and a short body, normally one paragraph or a few\nbullets. Include only details supplied directly by the human: their observation,\nexpected behavior, steps, frequency, environment, and impact when they provided them.\nLight editing for clarity is fine; preserve meaning and uncertainty. Omit empty\nsections and unnecessary background. Do not add agent-inferred impact, root cause,\nconfidence scores, or proposed fixes to the report.\n\nExample human report:\n\n> After I switched projects, the terminal stayed blank. I expected to see the session\n> prompt. It happened twice today on macOS; I don't know how to reproduce it reliably.\n\nKeep agent-discovered information separate from the human report and label it\n**Agent-collected evidence**, even when it confirms the report. Include only relevant\nexcerpts and:\n\n- The command or read-only query used, collection time, and relevant AO version or\n  checkout commit, so another person can interpret the result.\n- Observed output, screenshots, or reproduction results, with enough context to verify\n  the finding. Distinguish the reporter's environment from a separate test build.\n- A brief explanation of what the evidence supports and its limits. Label hypotheses\n  explicitly; don't present a code-path guess as a confirmed cause.\n\nIf no useful evidence is available, deliver the human report alone. Never pad it with\nspeculation or claim a reproduction succeeded when it didn't.\n\n## Gather relevant evidence\n\nUse diagnostics that fit the symptom, within the user's requested scope. Prefer\nread-only checks against the affected installation. Don't restart sessions, upgrade\nAO, change live data, or alter the user's checkout just to collect evidence.\n\nAO uses a Go daemon and an Electron/React frontend. Read `docs/architecture.md` for\ncurrent boundaries and locate actual files with `rg` before citing code. Do not rely\non the old TypeScript implementation or assume which runtime backs a session.\n\nBefore trusting diagnostics, identify the AO executable and affected daemon. A PATH\nlookup may resolve to a legacy install. Check the executable's version and status,\nand the configured run file/data directory (`AO_RUN_FILE` / `AO_DATA_DIR` when set).\nThe primary daemon normally uses loopback port 3001; port alone does not establish\nwhich version or installation is affected. Consult the installed CLI help for commands.\n\nFor local-daemon evidence, use the affected binary's `--version` and `status --json`;\nstatus reads existing state without starting the daemon. For a known affected session,\nuse `session get <id> --json` and keep only fields relevant to the symptom. If the\ndaemon is unavailable, record its status or error and mark session evidence unavailable.\n\nRecord app and CLI versions separately from daemon identity. Health probes provide no\ndaemon release version; `dev` alone or missing build metadata does not identify the\nsource. Label source findings approximate when the affected build cannot be matched.\n\nDo not run `doctor` or `agent ls` as routine evidence collectors: doctor writes files\nand checks remote authentication; agent listing triggers readiness checks.\n`remote-host status` can print the pairing password. Desktop status refresh may start\na replacement daemon; prefer the CLI status check or already available evidence.\n\nCollect only what helps explain this symptom:\n\n| Symptom | Potential evidence |\n| --- | --- |\n| UI rendering or interaction | Screenshot/recording, relevant console errors, affected view |\n| Session or terminal state | Affected session's daemon state, relevant log excerpt, runtime details |\n| Daemon or CLI failure | Version/status, exact command and error, relevant daemon logs |\n| Persisted state mismatch | Relevant rows and schema from a read-only SQLite query |\n\nLocate logs for the affected process rather than assuming `~/.ao/daemon.log` is current.\nDaemon output goes to stderr and may not persist; that file mostly covers keep-alive\nlaunches. Record missing evidence instead of enabling logging just to create it.\n\nUse the daemon API/CLI for state first. If database evidence is needed, discover the\nactual database location and schema, open it read-only, and select only relevant rows\nand columns. Never attach an entire database, broad log dump, or Electron profile\nfolder, which also holds browser cookies and storage. Redact tokens,\ncredentials, private prompts, and unrelated personal or repository data from every\nartifact, including screenshots. Keep diagnostic artifacts under `~/.ao` and out of\nGit commits. Preserve evidentiary content when redacting, and verify that unrelated\ncontent did not change. Share a useful excerpt rather than a wall of output.\n\nThe report form's sanitizer masks known patterns only; review the exact draft and\nartifacts before sharing.\n\nTry a safe reproduction when practical, recording the build actually tested. Failure\nto reproduce does not invalidate the human report. Code tracing or dependency research\nis optional when it can add concrete evidence. Keep findings in the separate evidence.\n\n## Check for duplicates\n\nResolve AO's canonical repository name before searching. GitHub issue and PR searches\ncan return empty results for a former owner even when repository API requests redirect.\nUse the resolved name, not the reporter's project repository. Search open and closed\nissues and related PRs using the symptom or exact error:\n\n```bash\nif ao_triage_repo=$(gh api repos/OrchestratorInc/agent-orchestrator --jq .full_name) && [ -n \"$ao_triage_repo\" ]; then\n  gh issue list --repo \"$ao_triage_repo\" --state all --search '<symptom or error>' --limit 100\n  gh pr list --repo \"$ao_triage_repo\" --state all --search '<symptom or error>' --limit 100\nelse\n  printf '%s\\n' 'Repository lookup failed; duplicate search skipped.' >&2\nfi\n```\n\nInclude the searched repository and candidates considered in the separate evidence.\nTry useful symptom synonyms or a shorter error fragment when needed.\n\nRead likely matches before calling a report a duplicate. If one matches, give the\nreporter its link and draft only their new observation for a comment, with evidence\nattached separately. If a closed issue appears to have regressed, explain that to the\nreporter rather than silently treating it as resolved. If repository lookup or either\nsearch fails or is unavailable, say which part could not be checked. Empty, truncated,\nor failed searches do not prove there is no duplicate; continue preparing the report.\n\n## Preserve attribution and submission scope\n\nA local coding agent may help draft and gather attachments. Existing authorization\nstill applies; triage alone is not permission to publish.\n\nFor an existing issue, preserve its human body and attribution. Add evidence separately\nwhen authorized. Don't rewrite the report into an investigation narrative.\n\nWhen authorized to publish, include useful collected evidence before finishing. Use a\nclearly labeled comment or attachment, whichever fits the evidence. If evidence cannot\nbe published, state the exact blocker and provide its local path. Never invent\nattachment URLs or create asset branches to host diagnostics. Keep the report body\nlimited to human details. Apply only existing, relevant labels; don't add\npriority/confidence prose just to fill a template.\n\nFinish with the concise draft (or issue link if submitted), any duplicate link, and\nattachment paths/links. Do not automatically file an issue, implement a fix, push a\nPR, or spawn a worker. Follow the user's requested scope and the repository's normal\ncontribution workflow if they separately ask for implementation.\n\nThe bundled `scripts/push_fix_to_github.py` is a legacy fix publisher, not a triage step.\n","integrations/grok-bot/skills/ao-setup/SKILL.md":"---\nname: ao-setup\ndescription: >-\n  First run of Orchestrator Bot: find every computer that runs AO, save them as\n  AO hosts, add a remote AO host that has no Grok Bot desktop app, and turn on\n  optional routines. On a computer without Orchestrator.inc it helps install it\n  and get it ready: a coding agent, a first project and the first orchestrator.\n  Use on the first chat, when memory has no \"AO hosts\" note, or when the user\n  says \"set up AO\", \"add a host\", \"add remote host\", \"check my AO setup\" or\n  \"install Orchestrator\".\n---\nFollow the ao-rules skill. Detection is read-only. Nothing is written until the user says yes.\n\nOpen with one line: \"Give me a few seconds to look for AO on your computers.\"\n\n## 1. Detect\n1. ListMachines. Use desktops only. If none is connected, say: \"Install the Grok Bot desktop app on the computer where you run Orchestrator.inc (or want to), sign in, and tell me when it shows up,\" then stop.\n2. On each connected desktop, in parallel, run this read-only probe with the `aoapi` helper from ao-rules: run \"Probe\" below.\n3. Each desktop where the probe prints a `projects=` line is a **local** AO host; an empty list means it still needs \"First run\". For any other result, see \"Missing pieces\". On a Windows desktop, don't run the probe: say once \"These skills need macOS or Linux; Windows isn't supported yet,\" and skip it.\n\n### Probe\n```sh\nf(){ <aoapi helper>; echo \"ao=$(command -v ao >/dev/null && ao version 2>/dev/null | head -1 || echo missing)\"\n  if [ \"$(uname -s)\" = Darwin ] && [ \"$(command -v python3)\" = /usr/bin/python3 ] && ! xcode-select -p >/dev/null 2>&1; then echo \"python=missing\"\n  else echo \"python=$(command -v python3 >/dev/null && python3 -c 'import sys;print(\"%d.%d\"%sys.version_info[:2])' || echo missing)\"; fi\n  [ \"$(uname -s)\" = Darwin ] && A=$(find /Applications \"$HOME/Applications\" -maxdepth 1 -name '*Orchestrator*.app' 2>/dev/null | head -1) && echo \"app=${A:-missing}\"\n  if P=$(aoapi GET projects 2>/dev/null); then\n    echo \"$P\" | python3 -c 'import json,sys; d=json.load(sys.stdin); p=d.get(\"projects\",d) if isinstance(d,dict) else d; print(\"projects=\" + \", \".join(x.get(\"id\",\"?\") for x in p))'\n    aoapi GET 'sessions?active=true' | python3 -c 'import json,sys; print(\"live_sessions=%d\" % len(json.load(sys.stdin)[\"sessions\"]))'\n  else echo \"daemon=not running\"; fi; }; f\n```\n\n## Missing pieces\nUse the probe result for each computer. Install or open anything only after the user's yes.\n\n| Probe shows | Next step |\n|---|---|\n| `python=missing` | Fix this first: every step needs it. macOS: `xcode-select --install` (the user confirms the system dialog). Linux: give the package manager line for python3 |\n| `daemon=not running` and `app=missing` (macOS) | Say: \"Orchestrator.inc isn't installed on <computer>. Want me to install it? It's about a 300 MB download.\" On yes, run \"Install on a Mac\" |\n| `daemon=not running` and `app=<path>` | On yes, open it with `open \"<path>\"`, then \"Wait for the app\" |\n| `daemon=not running` on Linux | If Orchestrator.inc is installed, ask the user to open it and say **check again**. Otherwise give the download for the user's distribution: [AppImage](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.AppImage), [.deb](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.deb) or [.rpm](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.rpm). The user installs and opens it, then says **check again** |\n| `projects=` with nothing after it | Run \"First run\" |\n| `ao=missing` with projects listed | Everything works except starting a review, screenshots and automations, which use the `ao` CLI. Say so once |\n\n**check again** runs the probe on that computer again and goes on from its result.\n\n**Wait for the app:** run the probe every 15 seconds, for up to 2 minutes, until it prints a `projects=` line. Still `daemon=not running` after that: ask the user to look at the Orchestrator.inc window and say **check again** when it's open.\n\n### Install on a Mac\nAfter a yes, on that computer. The download takes a few minutes, so the install runs in the background, in its own session so it keeps going after this command returns, and writes its progress to `~/.ao-grok/install.log`. It picks the build for the Mac's chip, checks the app's code signature (Orchestrator.inc's Developer ID team `X9LNSP8MC2`), copies it to Applications (or `~/Applications` if that isn't writable) and opens it:\n```sh\nf(){ mkdir -p ~/.ao-grok && cat > ~/.ao-grok/install-orchestrator.sh <<'EOF'\na=$([ \"$(sysctl -n hw.optional.arm64 2>/dev/null)\" = 1 ] && echo arm64 || echo x64); d=$(mktemp -d)\necho \"downloading the $a build\"\ncurl -fsSL -o \"$d/o.dmg\" \"https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/Orchestrator-darwin-$a.dmg\" || { echo DOWNLOAD_FAILED; rm -rf \"$d\"; exit 1; }\nm=$(hdiutil attach -nobrowse -readonly \"$d/o.dmg\" | awk -F'\\t' '/\\/Volumes\\//{print $NF}' | tail -1)\n[ -n \"$m\" ] || { echo INSTALL_FAILED; rm -rf \"$d\"; exit 1; }\napp=$(find \"$m\" -maxdepth 1 -name '*.app' 2>/dev/null | head -1)\ndone_(){ [ -n \"$m\" ] && hdiutil detach -quiet \"$m\"; rm -rf \"$d\"; }\nif [ -z \"$app\" ] || ! codesign --verify --deep --strict \"$app\" 2>/dev/null || ! codesign -dv \"$app\" 2>&1 | grep -q 'TeamIdentifier=X9LNSP8MC2'; then echo BAD_SIGNATURE; done_; exit 1; fi\ndest=/Applications\ncp -R \"$app\" \"$dest/\" 2>/dev/null || { dest=\"$HOME/Applications\"; mkdir -p \"$dest\" && cp -R \"$app\" \"$dest/\"; } || { echo INSTALL_FAILED; done_; exit 1; }\ndone_\nopen \"$dest/${app##*/}\" && echo \"INSTALLED $dest/${app##*/}\" || echo \"INSTALLED_NOT_OPENED $dest/${app##*/}\"\nEOF\nnohup python3 -c 'import os,sys; os.setsid(); os.execvp(\"sh\", [\"sh\", sys.argv[1]])' ~/.ao-grok/install-orchestrator.sh > ~/.ao-grok/install.log 2>&1 & echo STARTED; }; f\n```\nTell the user it has started. Then check `tail -1 ~/.ao-grok/install.log` every 20 seconds, for up to 15 minutes:\n\n| Last line | Next step |\n|---|---|\n| `downloading …` | Still going |\n| `INSTALLED <path>` | Say \"Orchestrator.inc is open on <computer>. I'll get it ready: a coding agent and your first project.\" Then \"Wait for the app\" and run \"First run\" |\n| `INSTALLED_NOT_OPENED <path>` | Open it with `open \"<path>\"`, then as above |\n| `DOWNLOAD_FAILED`, `BAD_SIGNATURE`, `INSTALL_FAILED`, or no change after 15 minutes | Say what happened and give the user the [download page](https://orchestrator.inc/download/) instead. Never retry `BAD_SIGNATURE` |\n\n## First run\nGets a computer ready for work once Orchestrator.inc is running there: a coding agent, a project, and the first orchestrator. Every change needs the user's yes. If Orchestrator.inc shows its own welcome steps and the user prefers them, let them finish there and say **check again**.\n\n### 1. A coding agent\n```sh\nf(){ <aoapi helper>; aoapi POST agents/refresh '{}' >/dev/null; aoapi GET agents/readiness | python3 -c '\nimport json,sys\nfor a in json.load(sys.stdin).get(\"agents\") or []:\n    inst=(a.get(\"installation\") or {}).get(\"state\",\"\"); auth=(a.get(\"authentication\") or {}).get(\"state\",\"\")\n    if inst!=\"not_installed\" or a.get(\"id\") in (\"claude-code\",\"codex\"):\n        print(\"\\t\".join([a.get(\"id\",\"\"), a.get(\"label\",\"\"), a.get(\"effectiveReadiness\",\"\"), inst, auth]))'; }; f\n```\nColumns: id, name, readiness, installed, signed in.\n- **Some agent is `ready`:** use it. If more than one is ready, ask which one should do the work. Don't pick for the user.\n- **Installed but not signed in:** on yes, `aoapi POST \"agents/<id>/auth\" '{}'` and relay its `guidance`. The sign-in runs in a terminal inside Orchestrator.inc; the user finishes it there (it may open their browser). When they say done, run this step again: it refreshes the checks.\n- **None installed:** ask \"Which coding agent do you want to use: Claude Code or Codex?\" On the pick and a yes, `aoapi POST \"agents/<id>/install\" '{}'`, then check `aoapi GET \"agents/<id>/install\"` every 15 seconds. `status` `succeeded`: sign in as above. `failed`, `unsupported` or `interrupted`: relay it, and point the user to the agent settings in Orchestrator.inc.\n\n### 2. A project\nSuggest the git clones the user worked in most recently (read-only; worktrees are left out):\n```sh\npython3 -c '\nimport glob,os\nhome=os.path.expanduser(\"~\"); found=set()\nfor r in (\"Development\",\"Projects\",\"projects\",\"code\",\"Code\",\"src\",\"dev\",\"GitHub\",\"Documents/GitHub\"):\n    for pat in (\"*/.git\",\"*/*/.git\",\"*/*/*/.git\"): found.update(os.path.dirname(g) for g in glob.glob(os.path.join(home,r,pat)) if os.path.isdir(g))\nfor p in sorted(found,key=lambda p:-os.path.getmtime(os.path.join(p,\".git\")))[:10]: print(p.replace(home,\"~\",1))'\n```\nShow them as one card, plus a typed option for another folder. On the pick, register it with the agent from step 1:\n```sh\nf(){ <aoapi helper>; aoapi POST projects \"$(python3 -c 'import json,os,sys; print(json.dumps({\"path\":os.path.expanduser(sys.argv[1]),\"config\":{\"worker\":{\"agent\":sys.argv[2]},\"orchestrator\":{\"agent\":sys.argv[2]}}}))' '<repo path>' '<agent id>')\" 2>/dev/null | python3 -c '\nimport json,sys\nd=json.load(sys.stdin); p=d.get(\"project\",d)\nif p.get(\"id\"): print(\"added\", p[\"id\"])\nelse: print(d.get(\"code\",\"ERROR\"), d.get(\"message\",\"\"), (d.get(\"details\") or {}).get(\"existingProjectId\",\"\"))'; }; f\n```\n- `added <id>`: done.\n- `NOT_A_GIT_REPO`: the folder needs to be a git repository with at least one commit. Ask for another folder.\n- `PATH_ALREADY_REGISTERED <id>`: it is already a project; use that id.\n\n### 3. The first orchestrator\nAsk: \"Want me to start the orchestrator for <project>? Tell me what you'd like done first, or I'll ask it to look around the repo and suggest a first task.\" On yes, run ao-orchestrator \"Start an orchestrator\" with that request.\n\nThen continue with section 2.\n\n## 2. Report and ask once\nOne message, at most 6 lines: per computer, AO found or not, its projects, and how many sessions are live. For a computer without a working AO, add the one next step from \"Missing pieces\". Then:\n\"Reply **yes** and I'll save these as your AO hosts. Is AO also running on a computer without the Grok Bot desktop app? Say **add remote host** and I'll connect to it from one of these.\"\n\nOn yes, save the **AO hosts** note (ao-rules \"AO hosts\") with `reach: local` and `via` = the same computer. Name each host with its short name (ao-rules `name`) and say the names in one line: \"I'll call them Pro and Air. Say if you want other names.\"\n\n## 3. Remote host (optional)\nUse this when AO runs on a computer that has no Grok Bot desktop app, for example a Mac mini host that a laptop's AO app already connects to.\n\n1. Ask for a short host name (letters, digits, `-`) and which connected computer to use as `via`. Default: the one the user's message came from.\n2. Tell the user, in one message:\n   \"On the host, open AO, go to remote access (Connect Mobile) and turn on network access. It shows an address and a password. Send me the **address** here. You'll type the password on <via> in a window I open, so it never passes through this chat.\"\n   On the host's own terminal, `ao remote-host enable` turns on the same network access, and `ao remote-host status` shows the address and the password.\n3. When the address arrives, check it looks like `http://<ip or name>:<port>`. Then, on `via`, write a one-time password window and open it. Replace `<name>` with the host name you checked: run \"Password window\" below.\n   Tell the user: \"A Terminal window opened on <via>. Type the password there and press Return.\"\n   On Linux, `open` doesn't run `.command` files: write the same lines to `~/.ao-grok/add-<name>.sh` and ask the user to run `zsh ~/.ao-grok/add-<name>.sh` in a terminal on `via`.\n4. When they say done, test it from `via`: run \"Connection test\" below.\n   HTTP 401 means a wrong password: open the window again. A timeout means the host is not reachable from `via` (another network, asleep, or access off).\n5. Add the host to the **AO hosts** note with `reach: remote`, `via`, `base` and `header`.\n\n### Password window\n```sh\nf(){ mkdir -p ~/.ao-grok/out && cat > ~/.ao-grok/add-<name>.command <<'EOF'\n#!/bin/zsh\numask 077\nread -rs \"p?AO password for <name>: \"; echo\nprintf 'Authorization: Bearer %s\\n' \"$p\" > ~/.ao-grok/<name>.header\necho \"Saved. You can close this window.\"; rm -- \"$0\"\nEOF\nchmod +x ~/.ao-grok/add-<name>.command && open ~/.ao-grok/add-<name>.command; }; f\n```\n\n### Connection test\n```sh\nf(){ <aoapi helper>; AO_REMOTE_BASE='<address>' AO_REMOTE_HEADER=\"$HOME/.ao-grok/<name>.header\" aoapi GET 'sessions?active=true' | python3 -c 'import json,sys; print(\"live_sessions=%d\" % len(json.load(sys.stdin)[\"sessions\"]))'; }; f\n```\n\nLimits of a remote host, said once: keep-awake, browser screenshots and starting a review work only on local hosts. For those, ask the host's orchestrator (ao-orchestrator). Quick-tunnel addresses change when the tunnel restarts, so prefer the LAN address or a named tunnel. If the user presses Regenerate in AO, run this section again.\n\n## 4. Mode and routines\n1. Save **Mode: default** in memory (ao-rules \"Decisions\"). Say in one line that away mode exists: \"Say 'I'm away till 6' and I'll keep routine work moving.\"\n2. Offer the routines in one multi-select card, nothing pre-selected, plus **none**:\n   - **AO waiting check**: every 30 minutes, 9:00 to 19:00 on weekdays. Runs ao-answer \"Find what's waiting\" and messages only when something new is waiting.\n   - **AO daily digest**: weekdays at 9:00. Runs ao-status \"Digest\".\n   Create the picked routines, then save \"Routines on: <names>\" in memory. Never create a second copy.\n3. Say once: \"AO's mobile app pushes questions to your phone the moment they happen. These routines check on a schedule.\"\n\n## 5. Finish\nOne line: the hosts saved (local and remote), the mode and the routines on. Then run ao-status as a first look, then:\n\nThings to try:\n- what's waiting on me\n- catch me up on <project>\n- in <project>: <what you want done>\n- I'm away till 6, keep things moving\n- what's ready to merge\n- show me what <session> built\n","integrations/grok-bot/skills/ao-answer/SKILL.md":"---\nname: ao-answer\ndescription: >-\n  Find AO sessions that wait on the user, show each question or approval as\n  tap-to-answer options, and send the answer back to that session, following\n  ao-rules \"Decisions\" (default, away mode, standing approvals). Use for\n  \"what's waiting on me\", \"answer <session>\", \"approve it\", the AO waiting\n  check routine, and away mode.\n---\nFollow the ao-rules skill. Its \"Decisions\" section says who may answer. Answers go straight to the worker, not through the orchestrator: the user's pick must arrive exactly as given.\n\n## 1. Find what's waiting\nOn every host, in parallel:\n```sh\nf(){ <aoapi helper>\n  aoapi GET 'sessions?active=true' | python3 -c '\nimport json,sys,time,calendar\nnow=time.time()\nfor s in json.load(sys.stdin)[\"sessions\"]:\n    st=(s.get(\"activity\") or {}).get(\"state\"); t=(s.get(\"lastEventAt\") or \"\")[:19]\n    if st in (\"waiting_input\",\"blocked\"): print(\"W\", s[\"id\"])\n    elif st==\"idle\" and t and now-calendar.timegm(time.strptime(t,\"%Y-%m-%dT%H:%M:%S\"))<86400: print(\"I\", s[\"id\"], s.get(\"lastEventAt\"))' |\n  while read -r k id at; do\n    if [ \"$k\" = W ]; then\n      aoapi GET \"sessions/$id/conversation\" | python3 -c '\nimport json,sys\nd=json.load(sys.stdin); found=False\nfor a in d.get(\"activities\") or []:\n    if a.get(\"activityKind\") in (\"approval\",\"user_input\") and a.get(\"status\")==\"pending\":\n        found=True; print(json.dumps({\"session\":sys.argv[1],\"kind\":a[\"activityKind\"],\"requestId\":a.get(\"requestId\"),\n            \"summary\":a.get(\"summary\"),\"decisions\":a.get(\"decisions\") or (a.get(\"detail\") or {}).get(\"decisions\"),\"detail\":a.get(\"detail\")}))\nif not found: print(json.dumps({\"session\":sys.argv[1],\"kind\":\"reply\"}))' \"$id\" 2>/dev/null\n    else\n      aoapi GET \"sessions/$id/history?offset=0&limit=1\" | python3 -c '\nimport json,sys,re\nt=(json.load(sys.stdin).get(\"turns\") or [{}])[0]; r=(t.get(\"agentResponse\") or \"\").strip()\nif re.search(r\"\\?[\\s*_`)\\]]*$\", r): print(json.dumps({\"session\":sys.argv[1],\"kind\":\"reply\",\"lastEventAt\":sys.argv[2],\"asked\":r[-300:]}))' \"$id\" \"$at\" 2>/dev/null\n    fi\n  done; }; f\n```\nEach line is one thing waiting:\n\n| `kind` | What it is |\n|---|---|\n| `approval` | Permission to run a command or change files. `summary` and `detail.input` say what; `decisions` are the options `[{id, kind, label}]` |\n| `user_input` | A question. `detail.message` asks it; `detail.schema.properties` are the fields, with choices in `enum` or `oneOf` |\n| `reply` | The agent asked in plain text: a session that waits with no request (or a terminal session), or an idle session from the last 24 hours whose last reply ends with a question (`asked` holds its end). Read its last reply (ao-status \"One session in detail\") |\n\nIn the **AO waiting check** routine: keep what you already showed in `~/.ao-grok/shown.txt` on `via`, one line per item (`<host> <session> <requestId>`, or `<host> <session> reply <lastEventAt>` for a `reply`), and message only about new items. Send nothing when nothing new is waiting.\n\n## 2. Show it\nPer session, one short briefing first: `<host>/<session>` and its name, what it is doing, and what it asks, in one or two sentences. Don't recommend anything. Then:\n- `approval`: the command or change verbatim, the risk you judge (ao-rules), and the `decisions` labels exactly as options in one card. Mark a decision whose `kind` is `allow_always` as \"changes this agent's permissions for good\".\n- `user_input`: one card with every question in it, in order (the card pages through them). A field with `oneOf` or `enum` is a question: use the `oneOf` titles or `enum` values as its options, exactly. A field whose `_meta._askUserQuestionCustomAnswer.questionId` names another field is that question's \"Other\" box: show it as a typed-answer option on that question, not as its own question. Any other free-text field is a question with a typed answer. `detail.inputMode` `url` can't be answered from chat: tell the user to open AO.\n- `reply`: the agent's question from its last reply, with options if it gave clear ones, else ask for a typed answer.\n\nSeveral sessions at once: explain them together, then cards per session.\n\n## 3. Answer\nOn the owner host, from its `via` computer:\n- **Approval**:\n  `aoapi POST \"sessions/<id>/conversation/approvals/<requestId>/resolve\" \"$(python3 -c 'import json,sys; print(json.dumps({\"decisionId\":sys.argv[1]}))' '<decision id>')\"`\n- **Question**: `content` maps each field name to the pick. For a picked option use its `oneOf` `const` (or the `enum` value), not the title. For a typed \"Other\" answer, put the text under the \"Other\" field (for example `question_0_custom`) and leave its question out:\n  `aoapi POST \"sessions/<id>/conversation/inputs/<requestId>/resolve\" \"$(python3 -c 'import json,sys; print(json.dumps({\"action\":\"accept\",\"content\":json.loads(sys.argv[1])}))' '{\"<field>\":\"<pick>\"}')\"`\n  The user says no or skip: `{\"action\":\"decline\"}`.\n- **reply**: send the answer as a message (ao-rules \"Messages to agents\"):\n  `aoapi POST \"sessions/<id>/send\" \"$(python3 -c 'import json,sys; print(json.dumps({\"message\":\"[via Grok Bot] \"+sys.argv[1],\"userAuthored\":True}))' '<answer>')\"`\n\nConfirm in one line. An error that says the request is not pending or not found means it was already answered or closed: say so. Then run step 1 for that session again, and deal with anything still open.\n\n## Away mode\nWhen memory says away mode is on and its end time hasn't passed, answer as ao-rules \"Decisions\" allows instead of showing cards, and log each one. Tell the user afterwards in one line per answer: session, what it asked, what you picked, why. Anything you may not decide: show it as in step 2, and say away mode left it for them.\n","integrations/grok-bot/skills/ao-orchestrator/SKILL.md":"---\nname: ao-orchestrator\ndescription: >-\n  Talk to a project's AO orchestrator: pass the user's request to it, wait for\n  its reply and relay it. The default route for starting or changing work,\n  \"catch me up\", \"why\", \"what next\" and plans. Use for \"in <project>: <ask>\",\n  \"tell the orchestrator ...\", \"catch me up on <project>\", \"start work on ...\".\n---\nFollow the ao-rules skill (\"Who does what: orchestrator first\"). Sending a message is a write: do it only for what the user asked in this turn.\n\n## 1. Pick the host and project\nMatch the user's words against project ids on every host (`aoapi GET projects`). One match: use it. The same project id on two hosts (two separate projects that share a folder name): ask which host, unless the user named one or memory has a default for that project. No match: list the projects and ask.\n\n## 2. Find the orchestrator\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions?orchestratorOnly=true&active=true&project=<project>\" | python3 -c '\nimport json,sys\nfor s in json.load(sys.stdin)[\"sessions\"]: print(s[\"id\"], (s.get(\"activity\") or {}).get(\"state\",\"\"), s.get(\"provisionState\",\"\"))'; }; f\n```\n- One line: that is the orchestrator. Its state tells you if it is busy (`active`).\n- `exited`: resume it first with `aoapi POST \"sessions/<id>/resume-agent\" '{}'`, then go on.\n- Provision state `failed`: AO could not create its workspace, and messages to it fail. Read the reason with `aoapi GET \"sessions/<id>\"` (field `provisionError`), tell the user in plain words, and ask them to fix it in AO. Stop here.\n- No line: ask \"There's no orchestrator in <project> on <host>. Start one with your request?\" On yes, start it with the request as its first message (step 3's file and tag), then go to step 4. Its reply is its first turn:\n\n### Start an orchestrator\n```sh\nf(){ <aoapi helper>; P='<project>'; TAG=\"[via Grok Bot #$(date +%H%M%S)]\"; F=~/.ao-grok/out/$(date +%F)-<short name>.md\n  mkdir -p ~/.ao-grok/out; { printf '%s ' \"$TAG\"; cat <<'EOF'\n<message>\nEOF\n  } > \"$F\"\n  H=$(aoapi GET \"projects/$P\" | python3 -c 'import json,sys; d=json.load(sys.stdin); c=(d.get(\"project\",d).get(\"config\") or {}); print((c.get(\"orchestrator\") or {}).get(\"agent\") or (c.get(\"worker\") or {}).get(\"agent\") or \"\")')\n  aoapi POST sessions \"$(python3 -c 'import json,sys; b={\"projectId\":sys.argv[1],\"kind\":\"orchestrator\",\"mode\":\"chat\",\"displayName\":\"Orchestrator\",\"prompt\":open(sys.argv[2]).read()}; b.update({\"harness\":sys.argv[3]} if sys.argv[3] else {}); print(json.dumps(b))' \"$P\" \"$F\" \"$H\")\" | python3 -c 'import json,sys; d=json.load(sys.stdin); d=d.get(\"session\",d); print(\"started\", d[\"id\"])' && echo \"TAG=$TAG\"; }; f\n```\nAfter about 10 seconds, check `provisionState` with `aoapi GET \"sessions/<new id>\"`. If it is `failed`, handle it as above.\n\n## 3. Send\nWrite the message to a file on `via`, then send it. The message is the user's request in their words, plus only the context from this chat the orchestrator needs. Don't add your own design choices. Start it with a tag so you can find the reply:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; TAG=\"[via Grok Bot #$(date +%H%M%S)]\"; F=~/.ao-grok/out/$(date +%F)-<short name>.md\n  mkdir -p ~/.ao-grok/out; { printf '%s ' \"$TAG\"; cat <<'EOF'\n<message>\nEOF\n  } > \"$F\"\n  B=$(python3 -c 'import json,sys; print(json.dumps({\"message\":open(sys.argv[1]).read(),\"userAuthored\":True}))' \"$F\")\n  if aoapi POST \"sessions/$O/send\" \"$B\" >/dev/null; then echo \"sent TAG=$TAG F=$F\"; return 0; fi\n  echo \"SEND_FAILED: resuming the agent and trying once more\"\n  aoapi POST \"sessions/$O/resume-agent\" '{}' >/dev/null; sleep 5\n  aoapi POST \"sessions/$O/send\" \"$B\" >/dev/null && echo \"sent TAG=$TAG F=$F\"; }; f\n```\nA failed send prints AO's error. If it still fails after the retry, tell the user the orchestrator isn't accepting messages and to open it in AO.\n\nIf the orchestrator was `active` in step 2, the message waits and runs as its own turn after the current one. Tell the user right away, in one line: \"The orchestrator is busy with <what its last turn is about>. Your question is queued and runs next.\" Then go on to step 4.\n\nIf the user wants to change what it is doing right now (\"stop that\", \"use X instead\"), steer instead. Write the file and tag as above, then:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; F='<message file>'\n  aoapi POST \"sessions/$O/conversation/steer-or-send\" \"$(python3 -c 'import json,sys,uuid; print(json.dumps({\"text\":open(sys.argv[1]).read(),\"clientMessageId\":str(uuid.uuid4())}))' \"$F\")\"; }; f\n```\n`\"outcome\":\"sent\"` means it arrived (in the running turn, or as a new turn if the orchestrator was idle). Then go to step 4.\n\n## 4. Wait for the reply\nCheck every 10 seconds for up to 5 minutes. Done when the orchestrator is no longer `active` and a turn that starts with your tag has a reply:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; TAG='<tag>'\n  for i in $(seq 30); do sleep 10\n    st=$(aoapi GET \"sessions/$O\" | python3 -c 'import json,sys; d=json.load(sys.stdin); d=d.get(\"session\",d); print((d.get(\"activity\") or {}).get(\"state\",\"\"))')\n    [ \"$st\" = active ] && continue\n    aoapi GET \"sessions/$O/history?offset=0&limit=5\" | python3 -c '\nimport json,sys\nfor t in json.load(sys.stdin).get(\"turns\") or []:\n    if (t.get(\"userRequest\") or \"\").startswith(sys.argv[1]) and t.get(\"agentResponse\"):\n        print(t[\"agentResponse\"]); raise SystemExit(0)\nraise SystemExit(1)' \"$TAG\" && return 0\n  done; echo STILL_WORKING; }; f\n```\n- A reply: relay it. Keep it faithful. Shorten only for a phone, and send a long reply as a file.\n- `STILL_WORKING`: tell the user the orchestrator is still on it, and offer: \"I'll message you when it replies.\" On yes, create a routine that runs step 4 once every 5 minutes for that tag, reports the reply, then deletes itself.\n- The orchestrator asks the user something back: show it as a card if it gives clear options, and send the pick as a new message (step 3).\n\n## 5. After\nIf the orchestrator started workers, list them in one line (ao-status \"Sessions\" for that project). Don't watch them unless the user asks. Their questions reach the user through ao-answer.\n","integrations/grok-bot/skills/ao-status/SKILL.md":"---\nname: ao-status\ndescription: >-\n  What AO is doing on every host: which sessions are running, waiting on the\n  user, idle or exited, which PRs are ready to merge or got a review, and a\n  daily digest. Read-only. Use for \"status\", \"what's running\", \"what's waiting\n  on me\", \"what's ready to merge\", \"anything stuck\", and the AO daily digest\n  routine.\n---\nFollow the ao-rules skill. Read-only in AO: it never marks anything read there. It keeps its own seen list in `~/.ao-grok/` on each `via` computer. Run on every host in the **AO hosts** note, in parallel, each from its `via` computer with the `aoapi` helper (set `AO_REMOTE_BASE` and `AO_REMOTE_HEADER` for remote hosts). If memory has no **AO hosts** note, run ao-setup first. Don't save hosts without the user's yes.\n\n## 1. Sessions\n```sh\nf(){ <aoapi helper>; aoapi GET 'sessions?active=true' | python3 -c '\nimport json,sys\nfor s in json.load(sys.stdin)[\"sessions\"]:\n    a=s.get(\"activity\") or {}\n    print(\"\\t\".join([s[\"id\"], s.get(\"kind\",\"\"), a.get(\"state\",\"\"), str(len(s.get(\"prs\") or [])), (s.get(\"displayName\") or \"\")[:60]]))'; }; f\n```\nColumns: id, kind (`orchestrator` or `worker`), state, PR count, name. States:\n\n| State | Say |\n|---|---|\n| `active` | running |\n| `waiting_input`, `blocked` | waiting on you |\n| `idle` | idle: finished its turn, or not started |\n| `exited` | the agent exited; it can be resumed (ao-actions) |\n\nFor what's waiting on the user, run ao-answer \"Find what's waiting\": it finds sessions in `waiting_input` or `blocked`, and idle sessions whose last reply asked the user a question. Never use notifications for it. Group by host, then by project (the session id starts with the project id).\n\nKeep the reply short enough for a phone, at most 6 lines: first what needs the user, then what's running, then one line per host with counts (for example \"MacBook Pro: 25 idle, 9 exited\"). Name a session only when it needs the user or is running. Leave out idle orchestrators, PR numbers and exited sessions unless asked. Report what you saw; don't guess why (a crash, a restart) unless the user asks.\n\n## 2. PRs and reviews\n```sh\nf(){ <aoapi helper>\n  aoapi GET 'notifications?status=unresolved' | python3 -c '\nimport json,sys\nfor n in json.load(sys.stdin)[\"notifications\"]:\n    if n.get(\"type\")==\"ready_to_merge\": print(\"\\t\".join([\"ready_to_merge\", n.get(\"sessionId\",\"\"), n.get(\"prUrl\",\"\"), (n.get(\"title\") or \"\")[:80]]))'\n  SEEN=\"$HOME/.ao-grok/<host name>.seen-news\"; mkdir -p ~/.ao-grok; touch \"$SEEN\"\n  aoapi GET 'notifications?status=unread' | python3 -c '\nimport json,sys\nseen=set(open(sys.argv[1]).read().split()); new=[]\nfor n in json.load(sys.stdin)[\"notifications\"]:\n    if n.get(\"type\") in (\"review_completed\",\"review_changes_requested\",\"pr_merged\",\"pr_closed_unmerged\") and not n.get(\"resolvedAt\") and n.get(\"id\") not in seen:\n        new.append(n[\"id\"]); print(\"\\t\".join([n[\"type\"], n.get(\"sessionId\",\"\"), n.get(\"prUrl\",\"\"), (n.get(\"title\") or \"\")[:80]]))\nopen(sys.argv[1],\"a\").writelines(i+\"\\n\" for i in new)' \"$SEEN\"\n  tail -n 500 \"$SEEN\" > \"$SEEN.tmp\" && mv \"$SEEN.tmp\" \"$SEEN\"; }; f\n```\n- `ready_to_merge` comes from the unresolved list, so a PR that was merged or changed since drops off. For \"what's ready to merge\", list these with the PR link, and offer the merge (ao-actions; needs the user's yes per PR).\n- `review_completed`, `review_changes_requested`, `pr_merged`, `pr_closed_unmerged` are news. The command prints only news this bot hasn't reported before, and records it as reported, so each item appears once, in a status reply or in the digest, whichever comes first. Mention each in one line. For \"what's new again\" or \"show all news\", run it without the seen list.\n- Never use `needs_input` notifications. They can outlive the wait (the session answered or exited); section 1 is the source for what's waiting.\n\n## 3. One session in detail\nFor \"what is <session> doing\": find it (ask which host if the id is on two hosts), then read its last turn:\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions/<id>/history?offset=0&limit=1\" | python3 -c '\nimport json,sys\nt=(json.load(sys.stdin).get(\"turns\") or [{}])[0]\nprint(\"asked:\", (t.get(\"userRequest\") or \"\")[:500]); print(\"replied:\", (t.get(\"agentResponse\") or \"\")[-1500:])'; }; f\n```\nSummarise in two or three lines. For \"catch me up on <project>\", ask the project's orchestrator instead (ao-orchestrator). It has the workers' reports.\n\n## Digest\nThe **AO daily digest** routine runs this skill. Per host: what finished since the last digest (idle sessions with `lastEventAt` since then), what's waiting on the user, what's ready to merge, and anything exited unexpectedly. Skip quiet projects. Send nothing if nothing happened and nothing is waiting. Write the time of this digest to `~/.ao-grok/<host name>.last-digest` on `via` and read it next time, instead of keeping it in memory.\n","integrations/grok-bot/skills/ao-rules/SKILL.md":"---\nname: ao-rules\ndescription: >-\n  Shared rules and the connection helper for every ao-* skill (run\n  Orchestrator from chat). Read before running any ao-* skill.\n---\n# AO rules\n\nEvery ao-* skill follows these rules. Other skills link here instead of repeating them.\n\n## AO hosts\nAn **AO host** is one computer that runs the AO daemon. Each host has its own projects, sessions and orchestrators, and AO never links them: a repo cloned on two hosts is two separate projects. AO names a project after its folder, so both can still get the same id, and then the same session id (for example `agent-orchestrator-1-12`) can exist on both. Always name a session as `<host>/<session id>`, and act only on the host that owns it.\n\nMemory keeps one note named **AO hosts**, with one line per host:\n\n| Field | Example | Meaning |\n|---|---|---|\n| `name` | `Pro` | A short name: the user's pick, else the model word of the ListMachines label (`Pro`, `Air`, `mini`). Never the network hostname such as `MacBookAir.lan` |\n| `reach` | `local` or `remote` | How you get to its AO |\n| `via` | `laptop` | The ListMachines label of the computer whose shell you use |\n| `base` | `http://192.168.1.20:7444` | Remote only. The host's LAN address from AO's remote access settings |\n| `header` | `~/.ao-grok/studio.header` | Remote only. File on `via` that holds the host's password |\n\n- **local**: the Grok Bot desktop app runs on the AO host. `via` is the host itself.\n- **remote**: the Grok Bot desktop app runs on another computer. You call the host's AO API over the network from `via`. The `ao` CLI on `via` talks only to `via`'s own AO, so never use it for a remote host.\n\nOne computer can be `via` for itself (local) and for other hosts (remote) at the same time.\n\nEvery run: call ListMachines, then use every host whose `via` computer is connected, in parallel, labelled by host name. Say once which hosts you could not reach. Never hard-code machine ids or home paths.\n\n## Calling AO\nStart every shell command that calls AO with this helper. It works in zsh and bash:\n\n```sh\naoapi(){ # aoapi METHOD PATH [JSON]\n  local base hdr=() data=() f=\"${AO_RUN_FILE:-$HOME/.ao/running.json}\"\n  if [ -n \"$AO_REMOTE_BASE\" ]; then base=\"$AO_REMOTE_BASE\"; hdr=(-H @\"$AO_REMOTE_HEADER\")\n  else [ -f \"$f\" ] || { echo \"AO_NOT_RUNNING\" >&2; return 3; }\n    base=\"http://127.0.0.1:$(grep -o '\"port\": *[0-9]*' \"$f\" | grep -o '[0-9]*$')\"; fi\n  [ -n \"$3\" ] && data=(--data \"$3\")\n  curl -sS --fail-with-body --max-time 30 -X \"$1\" \"${hdr[@]}\" -H 'Content-Type: application/json' \"${data[@]}\" \"$base/api/v1/$2\"\n}\n```\n\n- Local host: use `aoapi` as is.\n- Remote host: on the `via` computer, first set `AO_REMOTE_BASE='<base>' AO_REMOTE_HEADER=\"$HOME/.ao-grok/<name>.header\"`.\n- Build JSON bodies with `python3 -c 'import json,sys; print(json.dumps(...))' \"$ARG\"`, never by pasting text into quotes.\n- Anything longer than one line goes in a file first: `~/.ao-grok/out/<date>-<short name>.md` on `via`. The user can see what was sent.\n- Use the `ao` CLI only where a skill says \"local only\".\n\n### Errors\n| You see | Meaning and next step |\n|---|---|\n| `AO_NOT_RUNNING`, or connection refused on a local host | AO is not running there. Ask the user to open AO |\n| Connection refused or timeout on a remote host | The host is asleep, off this network, or remote access is off. Ask the user to check AO's remote access settings on the host |\n| HTTP 401 or 403 on a remote host | The host's password changed. Run ao-setup \"Remote host\" again |\n| HTTP 404 on a session path | No such session on that host. Check the host name |\n| Any other error | AO returns JSON with `message`. Relay it in plain words |\n\n## Who does what: orchestrator first\nEach project on a host has at most one live **orchestrator**: an agent that plans the project's work, starts and steers workers, and gets their reports. It has more context than you do. You are the user's phone line to it.\n\n- **Send to the orchestrator** (ao-orchestrator): starting or changing work, \"catch me up\", \"why\", \"what next\", plans, and anything that needs judgement about the code.\n- **Do directly**: status lists (ao-status), answering a pending request with the user's own pick (ao-answer), stop and interrupt, merges after the user's yes, files and screenshots (ao-actions).\n- Never start a worker yourself in a project that has a live orchestrator. Ask the orchestrator instead. With no orchestrator, ask the user whether to start one or to start the worker directly.\n- After you act directly on a worker (answer, stop, merge), the orchestrator sees it through AO. Don't send it a separate note.\n\n## Decisions\nA worker asks for two kinds of decision. A **question** (`user_input`) asks what to build. An **approval** asks permission to run a command or change files. Who decides depends on the mode, saved in memory:\n\n1. **Default mode**: show each question or approval to the user as a card with the exact options. Answer only with their pick for that request. Never reuse a pick for a new request.\n2. **Away mode** starts when the user says something like \"I'm away\", \"decide for me\" or \"keep it moving\". Save the scope and the end time in memory. Then:\n   - Answer routine questions yourself, and tell the user afterwards what you picked and why.\n   - Accept `low` and `normal` approvals with the one-time option (`kind` `allow_once`). Never pick an `allow_always` option: it changes the agent's permissions for good. Never accept a `high` approval without the user's yes for that request.\n   - Leave product direction, money, publishing and anything the user kept for themselves to the user.\n   - Away mode ends at the end time or when the user is back. Say when it ended.\n3. **Standing approvals**: the user may list kinds of approvals to always accept. Follow the list exactly.\n\nAO gives no risk level, so you judge it. Treat these as a floor. If a command looks riskier, call it high.\n\n| Risk | Examples |\n|---|---|\n| high | Deletes outside the session's worktree, `rm -rf`, `git push --force`, push to `main` or `master`, `git reset --hard`, history rewrites, deploy, publish, release, secrets, credentials, tokens, `sudo`, system installs, payments |\n| low | Reading or searching files, `git status`/`diff`/`log`, tests, lint, typecheck, builds |\n| normal | Everything else, such as edits and commits in the session's worktree, or pushing the session's own branch |\n\nNever invent the user's preferences. The worker decides how to do the work. The user decides what to build.\n\n## Writes\nChange nothing on the user's computers unless the user approved that exact change in chat, or away mode or a standing approval covers it. Approval for one change is not approval for the next. Never delete or archive sessions or projects, never change AO settings, and never merge, publish or deploy without the user's yes for that item.\n\n## Secrets\n- The `header` file holds a host's password. Pass it only to curl as `-H @<file>`. Never open, print, copy or paste it.\n- Never read AO's own credential files: `~/.ao/mobile/`, `~/.ao/data/agent-accounts/`, `~/.ao/electron/`, or any `*token*`, `*auth*`, `.env` or keychain item.\n- If session text contains a key, never repeat it.\n\n## Messages to agents\n- Before you send a follow-up, read the last turn (`aoapi GET \"sessions/<id>/history?offset=0&limit=1\"`) so you don't repeat or contradict it.\n- Keep messages short and concrete: what is right so far, then the next step. Leave out check-ins, your own process and these rules.\n- Start every message you send with `[via Grok Bot]`, so the user can tell it apart in AO.\n\n## Output\n- Answer first, in short plain words. Say what you could not check.\n- Write every session as `<host name>/<session id>`, every time, in every skill and every line, even when only one host has that id: `Air/agent-orchestrator-31`, `Pro/agent-orchestrator-1-249`. Add the display name when it helps.\n- Give times in the user's timezone.\n- One message per event. If two checks report the same thing, say it once. News (a merge, a finished review) is reported once: ao-status keeps a seen list.\n- Send files with SendToUser. Copy them to the box first with CopyToBox.\n\n## Memory\n- Save hosts, modes and preferences, not activity. A check where nothing changed is not worth a note.\n- When the user corrects you, save the correction.\n- A follow-up you promise for later (\"I'll tell you when it's done\") goes into a Routine, not only into memory.\n\n## Grok Bot only\nThese steps need tools only Grok Bot has. Any other agent (Claude Code, Codex, Cursor) runs on one computer and does this instead:\n\n| Grok Bot step | Other agents |\n|---|---|\n| ListMachines, every connected computer | Only the computer you run on, as a local host |\n| Routines | Run the check once when asked |\n| Cards | Plain text with numbered options |\n| Memory | Ask, or use the notes file the user names |\n| SendToUser, CopyToBox | Give the file path |\n","integrations/grok-bot/skills/ao-update/SKILL.md":"# ao-update\n\nPath: `integrations/grok-bot/skills/ao-update/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-update/SKILL.md)","AGENTS.md":"# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/AGENTS.md)","CLAUDE.md":"# Claude Agent Guidelines & System Prompt\n\nPath: `CLAUDE.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/CLAUDE.md)","DESIGN.md":"# UI Design System & Style Tokens\n\nPath: `DESIGN.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/DESIGN.md)","docs/architecture.md":"# docs - System Architecture & Module Boundaries\n\nPath: `docs/architecture.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/docs/architecture.md)","packages/ao-darwin-arm64/package.json":"# Ao-darwin-arm64 Skill\n\nPath: `packages/ao-darwin-arm64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-arm64/package.json)","packages/ao-darwin-x64/package.json":"# Ao-darwin-x64 Skill\n\nPath: `packages/ao-darwin-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-x64/package.json)","packages/ao-linux-x64/package.json":"# Ao-linux-x64 Skill\n\nPath: `packages/ao-linux-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-linux-x64/package.json)","packages/ao-win32-x64/package.json":"# Ao-win32-x64 Skill\n\nPath: `packages/ao-win32-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-win32-x64/package.json)","packages/ao/package.json":"# Ao Skill\n\nPath: `packages/ao/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao/package.json)","packages/cloud-client/README.md":"# cloud-client Documentation\n\nPath: `packages/cloud-client/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/README.md)","packages/cloud-client/package-lock.json":"# Cloud-client Skill\n\nPath: `packages/cloud-client/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/package-lock.json)","packages/cloud-client/package.json":"# Cloud-client Skill\n\nPath: `packages/cloud-client/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/package.json)","packages/cloud-client/tsconfig.json":"# Cloud-client Skill\n\nPath: `packages/cloud-client/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/tsconfig.json)","packages/cloud-client/tsconfig.test.json":"# Cloud-client Skill\n\nPath: `packages/cloud-client/tsconfig.test.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/tsconfig.test.json)","packages/mobile/README.md":"# mobile Documentation\n\nPath: `packages/mobile/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/README.md)","packages/mobile/app.json":"# Mobile Skill\n\nPath: `packages/mobile/app.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/app.json)","packages/mobile/eas.json":"# Mobile Skill\n\nPath: `packages/mobile/eas.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/eas.json)","packages/mobile/package-lock.json":"# Mobile Skill\n\nPath: `packages/mobile/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/package-lock.json)","packages/mobile/package.json":"# Mobile Skill\n\nPath: `packages/mobile/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/package.json)","packages/mobile/tsconfig.json":"# Mobile Skill\n\nPath: `packages/mobile/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/tsconfig.json)","packages/product-ui/README.md":"# product-ui Documentation\n\nPath: `packages/product-ui/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/README.md)","packages/product-ui/package-lock.json":"# Product-ui Skill\n\nPath: `packages/product-ui/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/package-lock.json)","packages/product-ui/package.json":"# Product-ui Skill\n\nPath: `packages/product-ui/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/package.json)","packages/product-ui/tsconfig.build.json":"# Product-ui Skill\n\nPath: `packages/product-ui/tsconfig.build.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/tsconfig.build.json)","packages/product-ui/tsconfig.json":"# Product-ui Skill\n\nPath: `packages/product-ui/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/tsconfig.json)","packages/mobile/scripts/README.md":"# scripts Documentation\n\nPath: `packages/mobile/scripts/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/scripts/README.md)",".agents/skills/ao-desktop-dev/agents/openai.yaml":"# Agents Skill\n\nPath: `.agents/skills/ao-desktop-dev/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.agents/skills/ao-desktop-dev/agents/openai.yaml)",".claude/skills/bug-triage/scripts/push_fix_to_github.py":"# Claude Directive: push_fix_to_github.py\n\nPath: `.claude/skills/bug-triage/scripts/push_fix_to_github.py`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.claude/skills/bug-triage/scripts/push_fix_to_github.py)","packages/mobile/assets/AO.icon/icon.json":"# AO.icon Skill\n\nPath: `packages/mobile/assets/AO.icon/icon.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/assets/AO.icon/icon.json)","packages/mobile/native/image-paste/package.json":"# Image-paste Skill\n\nPath: `packages/mobile/native/image-paste/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/native/image-paste/package.json)","packages/mobile/native/response-selection/package.json":"# Response-selection Skill\n\nPath: `packages/mobile/native/response-selection/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/native/response-selection/package.json)","backend/internal/skillassets/using-ao/commands/automation.md":"# Command: /automation\n\nPath: `backend/internal/skillassets/using-ao/commands/automation.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/automation.md)","backend/internal/skillassets/using-ao/commands/browser-remote.md":"# Command: /browser-remote\n\nPath: `backend/internal/skillassets/using-ao/commands/browser-remote.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/browser-remote.md)","backend/internal/skillassets/using-ao/commands/browser.md":"# Command: /browser\n\nPath: `backend/internal/skillassets/using-ao/commands/browser.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/browser.md)","backend/internal/skillassets/using-ao/commands/cua.md":"# Command: /cua\n\nPath: `backend/internal/skillassets/using-ao/commands/cua.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/cua.md)","backend/internal/skillassets/using-ao/commands/cue.md":"# Command: /cue\n\nPath: `backend/internal/skillassets/using-ao/commands/cue.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/cue.md)","backend/internal/skillassets/using-ao/commands/doctor.md":"# Command: /doctor\n\nPath: `backend/internal/skillassets/using-ao/commands/doctor.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/doctor.md)","backend/internal/skillassets/using-ao/commands/import.md":"# Command: /import\n\nPath: `backend/internal/skillassets/using-ao/commands/import.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/import.md)","backend/internal/skillassets/using-ao/commands/orchestrator.md":"# Command: /orchestrator\n\nPath: `backend/internal/skillassets/using-ao/commands/orchestrator.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/orchestrator.md)","backend/internal/skillassets/using-ao/commands/preview.md":"# Command: /preview\n\nPath: `backend/internal/skillassets/using-ao/commands/preview.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/preview.md)","backend/internal/skillassets/using-ao/commands/project.md":"# Command: /project\n\nPath: `backend/internal/skillassets/using-ao/commands/project.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/project.md)","backend/internal/skillassets/using-ao/commands/remote-host.md":"# Command: /remote-host\n\nPath: `backend/internal/skillassets/using-ao/commands/remote-host.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/remote-host.md)","backend/internal/skillassets/using-ao/commands/render.md":"# Command: /render\n\nPath: `backend/internal/skillassets/using-ao/commands/render.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/render.md)","backend/internal/skillassets/using-ao/commands/report.md":"# Command: /report\n\nPath: `backend/internal/skillassets/using-ao/commands/report.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/report.md)","backend/internal/skillassets/using-ao/commands/review.md":"# Command: /review\n\nPath: `backend/internal/skillassets/using-ao/commands/review.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/review.md)","backend/internal/skillassets/using-ao/commands/send.md":"# Command: /send\n\nPath: `backend/internal/skillassets/using-ao/commands/send.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/send.md)","backend/internal/skillassets/using-ao/commands/session.md":"# Command: /session\n\nPath: `backend/internal/skillassets/using-ao/commands/session.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/session.md)","backend/internal/skillassets/using-ao/commands/spawn.md":"# Command: /spawn\n\nPath: `backend/internal/skillassets/using-ao/commands/spawn.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/spawn.md)","backend/internal/skillassets/using-ao/commands/start.md":"# Command: /start\n\nPath: `backend/internal/skillassets/using-ao/commands/start.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/start.md)","backend/internal/skillassets/using-ao/commands/status.md":"# Command: /status\n\nPath: `backend/internal/skillassets/using-ao/commands/status.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/status.md)","backend/internal/skillassets/using-ao/commands/stop.md":"# Command: /stop\n\nPath: `backend/internal/skillassets/using-ao/commands/stop.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/stop.md)","frontend/src/docs/content/plugins/meta.json":"# Plugins Skill\n\nPath: `frontend/src/docs/content/plugins/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/meta.json)","packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json":"# CircleDashedCheck.imageset Skill\n\nPath: `packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json)","frontend/src/docs/content/plugins/agents/meta.json":"# Agents Skill\n\nPath: `frontend/src/docs/content/plugins/agents/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/agents/meta.json)","frontend/src/docs/content/plugins/notifiers/meta.json":"# Notifiers Skill\n\nPath: `frontend/src/docs/content/plugins/notifiers/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/notifiers/meta.json)","frontend/src/docs/content/plugins/runtimes/meta.json":"# Runtimes Skill\n\nPath: `frontend/src/docs/content/plugins/runtimes/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/runtimes/meta.json)","frontend/src/docs/content/plugins/scm/meta.json":"# Scm Skill\n\nPath: `frontend/src/docs/content/plugins/scm/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/scm/meta.json)","frontend/src/docs/content/plugins/terminals/meta.json":"# Terminals Skill\n\nPath: `frontend/src/docs/content/plugins/terminals/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/terminals/meta.json)","frontend/src/docs/content/plugins/trackers/meta.json":"# Trackers Skill\n\nPath: `frontend/src/docs/content/plugins/trackers/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/trackers/meta.json)","frontend/src/docs/content/plugins/workspaces/meta.json":"# Workspaces Skill\n\nPath: `frontend/src/docs/content/plugins/workspaces/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/workspaces/meta.json)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/AGENTS.md)","tokens":300,"sizeBytes":163},{"name":"DESIGN.md","path":"DESIGN.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/DESIGN.md","title":"UI Design System & Style Tokens","category":"project-spec","format":"markdown","content":"# UI Design System & Style Tokens\n\nPath: `DESIGN.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/DESIGN.md)","tokens":300,"sizeBytes":162},{"name":"architecture.md","path":"docs/architecture.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/docs/architecture.md","title":"docs - System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# docs - System Architecture & Module Boundaries\n\nPath: `docs/architecture.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/docs/architecture.md)","tokens":300,"sizeBytes":199},{"name":"openai.yaml","path":".agents/skills/ao-desktop-dev/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.agents/skills/ao-desktop-dev/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"# Agents Skill\n\nPath: `.agents/skills/ao-desktop-dev/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.agents/skills/ao-desktop-dev/agents/openai.yaml)","tokens":300,"sizeBytes":221},{"name":"SKILL.md","path":".agents/skills/ao-desktop-dev/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.agents/skills/ao-desktop-dev/SKILL.md","title":"ao-desktop-dev","category":"anthropic-skill","format":"markdown","content":"---\nname: ao-desktop-dev\ndescription: Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data.\n---\n\n# AO Desktop Dev\n\nRun the Electron application from the current checkout and verify it in the native window. Keep the dev daemon, renderer, Electron preload, and selected data mode explicit so the user never reviews a mock or stale build by accident.\n\n## Choose the data mode\n\nAsk only when the request does not make the desired data source clear.\n\n- Use **isolated mode** by default for implementation and destructive testing. Electron uses port `3002`, `~/.ao/dev/running.json`, `~/.ao/dev/data`, and `~/.ao/dev/electron`.\n- Use **real-data mode** only when the user explicitly asks to see this machine's actual AO projects or sessions. Start the checkout's dev daemon on the isolated dev port/run file while pointing `AO_DATA_DIR` at the real AO data directory. This is a separate daemon process using real data; do not describe it as the installed app's daemon.\n- Never try to attach an unpackaged Electron app directly to a packaged daemon from another checkout. The supervisor intentionally rejects daemon identity mismatches.\n- Warn before actions in real-data mode that create, terminate, rename, or otherwise mutate sessions. Merely opening and inspecting the UI is expected.\n- Real-data mode reads the same database as the installed app, and only one daemon can own a data directory. Quit the packaged app first: while its daemon runs, the dev daemon waits for the data-dir lock (9 x `AO_SHUTDOWN_TIMEOUT` + 18s, 108s by default) and then exits with code 75. The dev window is marked with an `Agent Orchestrator (dev)` title, an orange-badged `DEV` dock icon, and an in-app `dev` badge — verify those markers before acting.\n\n## Preflight\n\n1. Work from the repository root and inspect `git status --short --branch`.\n2. Read `frontend/package.json`, `frontend/src/main.ts`, and `frontend/forge.config.ts` when the launch behavior may have changed. Treat source as authoritative over this skill.\n3. Confirm Node/npm and the Go version required by `backend/go.mod` are available. Run `npm ci` in `frontend/` only when dependencies are absent or inconsistent; do not reinstall on every launch.\n4. Check for an existing dev instance from this exact checkout before starting another. Do not kill by process name alone, and never terminate every Electron process.\n\nOn macOS/Linux, inspect checkout-scoped processes and listeners with finite commands:\n\n```bash\nps -axo pid=,ppid=,pgid=,lstart=,command= | rg 'frontend/(node_modules/.bin/electron-forge|node_modules/electron/dist/Electron)'\nlsof -nP -iTCP:3002 -sTCP:LISTEN\n```\n\nUse the full command paths and start times to distinguish this checkout from other AO worktrees. On Windows, use `Get-CimInstance Win32_Process` and `Get-NetTCPConnection`; preserve the same exact-target rule.\n\n## Launch the app\n\nRun Electron Forge in a foreground interactive process so its output and restart input remain available. Do not append `&`, use a detached shell, or start a browser preview instead.\n\n### Isolated mode\n\nOn macOS/Linux:\n\n```bash\ncd frontend\nenv -u AO_DATA_DIR -u AO_RUN_FILE -u AO_PORT npm run dev\n```\n\nOn PowerShell:\n\n```powershell\nSet-Location frontend\nRemove-Item Env:AO_DATA_DIR, Env:AO_RUN_FILE, Env:AO_PORT -ErrorAction SilentlyContinue\nnpm run dev\n```\n\n### Real-data mode\n\nFirst resolve and report the actual data directory. In an AO worker session, `AO_DATA_DIR` normally already identifies it. Otherwise the repository default is the absolute path corresponding to `~/.ao/data`.\n\nKeep the real data directory but remove inherited port/run-file overrides so the dev app retains its own daemon handshake and port:\n\n```bash\ncd frontend\nenv -u AO_RUN_FILE -u AO_PORT AO_DATA_DIR=\"${AO_DATA_DIR:-$HOME/.ao/data}\" npm run dev\n```\n\nPowerShell equivalent:\n\n```powershell\nSet-Location frontend\n$realAoData = if ($env:AO_DATA_DIR) { $env:AO_DATA_DIR } else { Join-Path $HOME \".ao/data\" }\nRemove-Item Env:AO_RUN_FILE, Env:AO_PORT -ErrorAction SilentlyContinue\n$env:AO_DATA_DIR = $realAoData\nnpm run dev\n```\n\nDo not print unrelated environment variables: AO sessions may carry credentials. It is safe to report only `AO_DATA_DIR`, `AO_RUN_FILE`, and `AO_PORT`.\n\n## Confirm the correct app is ready\n\nWait for all of these signals:\n\n- Electron Forge reports `Launched Electron app`.\n- The daemon reports `daemon listening`, normally on `127.0.0.1:3002` unless it explicitly reports another bound port.\n- The renderer makes successful requests such as `/api/v1/projects` and `/api/v1/sessions`.\n- The native Electron window shows the checkout's UI. A Vite URL opened in a normal browser is not equivalent because it lacks the Electron preload bridge.\n\nIf several AO windows exist, identify the newest Electron main process belonging to this checkout. On macOS, foreground that exact PID only when needed:\n\n```bash\nosascript -e 'tell application \"System Events\" to set frontmost of first process whose unix id is <verified-pid> to true'\n```\n\nDo not claim real data from appearance alone. Verify the selected data directory and successful API responses. Do not claim visual success from compilation alone; interact with the requested flow in Electron or ask the user for a screenshot when screen capture is unavailable.\n\n## Reload changes correctly\n\n- Renderer-only React/CSS changes normally hot reload.\n- Changes to `frontend/src/main.ts`, preload files, Forge configuration, shared bridge types, or IPC registration require an Electron main-process restart. Type `rs` into the active Forge terminal or fully stop and relaunch the dev process.\n- A renderer error such as `aoBridge.<method> is not a function` almost always means the renderer hot-reloaded against a stale preload. Restart Electron before changing code to add guards around a bridge method that should exist.\n- Backend changes require restarting the managed dev daemon or the Electron process; renderer hot reload cannot apply Go changes.\n\nAfter a restart, confirm the new Electron PID/start time and re-check the logs for the original error.\n\n## Preview multiple PRs locally\n\nWhen the user wants to see multiple unmerged PRs together:\n\n1. Require a clean worktree and fetch each PR head.\n2. Create a clearly named local-only integration branch using the session/repository branch convention.\n3. Merge or cherry-pick the requested PR heads without rewriting or pushing either source branch.\n4. Resolve overlaps according to the requested combined behavior and run focused typechecks/tests.\n5. Let renderer changes hot reload; restart Electron if either PR changes main/preload/IPC code.\n6. State that the integration branch is local-only. Do not push it unless the user explicitly requests a combined PR.\n\nOnce one PR merges, prefer rebasing the remaining PR onto current `main`; the normal PR branch then contains both views without a local integration merge.\n\n## Stop without collateral damage\n\n1. Send Ctrl+C to the foreground dev process and wait briefly for Electron and its managed daemon to exit.\n2. Re-run the checkout-scoped process query. If the exact process group remains, identify the group created by this launch before sending `TERM` to that group.\n3. On Windows, terminate the verified parent tree only. Never use a broad Electron, Node, Go, or port-based kill.\n4. Confirm the captured Electron PID and dev daemon listener are gone. Leave installed AO and other worktrees untouched.\n\n## Common mistakes\n\n- `ao preview` controls the AO Browser panel; it does not launch the desktop shell.\n- `npm run dev:web` is useful for browser-only renderer work but does not provide Electron APIs or native chrome.\n- Renderer URLs can move from `5173` when a port is occupied. Trust Forge's printed URL rather than assuming one.\n- Multiple dev instances share `~/.ao/dev/electron` by default, and Chromium's\n  singleton lock lives in the profile, so a second checkout's `npm run dev`\n  loses `requestSingleInstanceLock()` and exits immediately with code 0. To run\n  two worktrees at once, give each its own profile, run file, and data dir:\n\n  ```bash\n  env -u AO_PORT \\\n    AO_DEV_ELECTRON_DIR=\"$HOME/.ao/dev/<name>/electron\" \\\n    AO_RUN_FILE=\"$HOME/.ao/dev/<name>/running.json\" \\\n    AO_DATA_DIR=\"$HOME/.ao/dev/<name>/data\" \\\n    npm run dev\n  ```\n\n  Without all three the instances still collide, on the profile lock, the run\n  file, or the daemon's SQLite data.\n- An inherited `AO_DATA_DIR` changes dev mode from isolated data to real data. Always choose and report the mode instead of inheriting it accidentally.\n- Repeated `/healthz/` 404 entries from external probes can be noisy; readiness is determined by Electron's daemon status and successful API traffic, not by log volume.\n\n## Completion report\n\nReport:\n\n- checkout and branch being displayed;\n- isolated or real-data mode and the non-sensitive data/run-file paths;\n- renderer and daemon addresses actually reported;\n- whether Electron was restarted for main/preload changes;\n- user flows exercised in the native window;\n- any remaining stale process, port, or visual-verification limitation.\n","frontmatter":{"name":"ao-desktop-dev","description":"Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data."},"isInternal":false,"tokens":2089,"sizeBytes":9441},{"name":"SKILL.md","path":".agents/skills/bug-triage/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.agents/skills/bug-triage/SKILL.md","title":"bug-triage","category":"anthropic-skill","format":"markdown","content":"---\nname: bug-triage\ndescription: Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft.\n---\n\n# Bug triage\n\nHelp the reporter describe what they observed and add useful evidence. A short human\nobservation is enough to report a bug; reproduction, logs, and a diagnosis are optional.\nUse this skill for reports from chat, an existing issue, or a local user.\n\n## Clarify the observation\n\nRead the available report, screenshots, and follow-ups first. Preserve the original\nreporter's words and attribution, including when someone else relays their report.\nDon't infer a GitHub username from a chat display name.\n\nAsk only questions that would materially clarify the symptom, a few at a time. Don't\nrepeat questions already answered or turn these suggestions into required fields:\n\n- What did you do, and what happened instead of what you expected?\n- Where did it happen, and does it happen every time or only sometimes?\n- For a visual problem, can you share a screenshot or short recording showing it?\n- If relevant, which AO version and OS were you using, and did it start after a change?\n\nIf a screenshot is unavailable, accept a description. If the reporter cannot remember\nsteps or reproduce the problem, preserve that uncertainty and proceed with what is\nknown. Never invent steps or make the reporter diagnose the bug before accepting it.\n\n## Keep the report and investigation separate\n\nDraft a specific symptom-based title and a short body, normally one paragraph or a few\nbullets. Include only details supplied directly by the human: their observation,\nexpected behavior, steps, frequency, environment, and impact when they provided them.\nLight editing for clarity is fine; preserve meaning and uncertainty. Omit empty\nsections and unnecessary background. Do not add agent-inferred impact, root cause,\nconfidence scores, or proposed fixes to the report.\n\nExample human report:\n\n> After I switched projects, the terminal stayed blank. I expected to see the session\n> prompt. It happened twice today on macOS; I don't know how to reproduce it reliably.\n\nKeep agent-discovered information separate from the human report and label it\n**Agent-collected evidence**, even when it confirms the report. Include only relevant\nexcerpts and:\n\n- The command or read-only query used, collection time, and relevant AO version or\n  checkout commit, so another person can interpret the result.\n- Observed output, screenshots, or reproduction results, with enough context to verify\n  the finding. Distinguish the reporter's environment from a separate test build.\n- A brief explanation of what the evidence supports and its limits. Label hypotheses\n  explicitly; don't present a code-path guess as a confirmed cause.\n\nIf no useful evidence is available, deliver the human report alone. Never pad it with\nspeculation or claim a reproduction succeeded when it didn't.\n\n## Gather relevant evidence\n\nUse diagnostics that fit the symptom, within the user's requested scope. Prefer\nread-only checks against the affected installation. Don't restart sessions, upgrade\nAO, change live data, or alter the user's checkout just to collect evidence.\n\nAO uses a Go daemon and an Electron/React frontend. Read `docs/architecture.md` for\ncurrent boundaries and locate actual files with `rg` before citing code. Do not rely\non the old TypeScript implementation or assume which runtime backs a session.\n\nBefore trusting diagnostics, identify the AO executable and affected daemon. A PATH\nlookup may resolve to a legacy install. Check the executable's version and status,\nand the configured run file/data directory (`AO_RUN_FILE` / `AO_DATA_DIR` when set).\nThe primary daemon normally uses loopback port 3001; port alone does not establish\nwhich version or installation is affected. Consult the installed CLI help for commands.\n\nFor local-daemon evidence, use the affected binary's `--version` and `status --json`;\nstatus reads existing state without starting the daemon. For a known affected session,\nuse `session get <id> --json` and keep only fields relevant to the symptom. If the\ndaemon is unavailable, record its status or error and mark session evidence unavailable.\n\nRecord app and CLI versions separately from daemon identity. Health probes provide no\ndaemon release version; `dev` alone or missing build metadata does not identify the\nsource. Label source findings approximate when the affected build cannot be matched.\n\nDo not run `doctor` or `agent ls` as routine evidence collectors: doctor writes files\nand checks remote authentication; agent listing triggers readiness checks.\n`remote-host status` can print the pairing password. Desktop status refresh may start\na replacement daemon; prefer the CLI status check or already available evidence.\n\nCollect only what helps explain this symptom:\n\n| Symptom | Potential evidence |\n| --- | --- |\n| UI rendering or interaction | Screenshot/recording, relevant console errors, affected view |\n| Session or terminal state | Affected session's daemon state, relevant log excerpt, runtime details |\n| Daemon or CLI failure | Version/status, exact command and error, relevant daemon logs |\n| Persisted state mismatch | Relevant rows and schema from a read-only SQLite query |\n\nLocate logs for the affected process rather than assuming `~/.ao/daemon.log` is current.\nDaemon output goes to stderr and may not persist; that file mostly covers keep-alive\nlaunches. Record missing evidence instead of enabling logging just to create it.\n\nUse the daemon API/CLI for state first. If database evidence is needed, discover the\nactual database location and schema, open it read-only, and select only relevant rows\nand columns. Never attach an entire database, broad log dump, or Electron profile\nfolder, which also holds browser cookies and storage. Redact tokens,\ncredentials, private prompts, and unrelated personal or repository data from every\nartifact, including screenshots. Keep diagnostic artifacts under `~/.ao` and out of\nGit commits. Preserve evidentiary content when redacting, and verify that unrelated\ncontent did not change. Share a useful excerpt rather than a wall of output.\n\nThe report form's sanitizer masks known patterns only; review the exact draft and\nartifacts before sharing.\n\nTry a safe reproduction when practical, recording the build actually tested. Failure\nto reproduce does not invalidate the human report. Code tracing or dependency research\nis optional when it can add concrete evidence. Keep findings in the separate evidence.\n\n## Check for duplicates\n\nResolve AO's canonical repository name before searching. GitHub issue and PR searches\ncan return empty results for a former owner even when repository API requests redirect.\nUse the resolved name, not the reporter's project repository. Search open and closed\nissues and related PRs using the symptom or exact error:\n\n```bash\nif ao_triage_repo=$(gh api repos/OrchestratorInc/agent-orchestrator --jq .full_name) && [ -n \"$ao_triage_repo\" ]; then\n  gh issue list --repo \"$ao_triage_repo\" --state all --search '<symptom or error>' --limit 100\n  gh pr list --repo \"$ao_triage_repo\" --state all --search '<symptom or error>' --limit 100\nelse\n  printf '%s\\n' 'Repository lookup failed; duplicate search skipped.' >&2\nfi\n```\n\nInclude the searched repository and candidates considered in the separate evidence.\nTry useful symptom synonyms or a shorter error fragment when needed.\n\nRead likely matches before calling a report a duplicate. If one matches, give the\nreporter its link and draft only their new observation for a comment, with evidence\nattached separately. If a closed issue appears to have regressed, explain that to the\nreporter rather than silently treating it as resolved. If repository lookup or either\nsearch fails or is unavailable, say which part could not be checked. Empty, truncated,\nor failed searches do not prove there is no duplicate; continue preparing the report.\n\n## Preserve attribution and submission scope\n\nA local coding agent may help draft and gather attachments. Existing authorization\nstill applies; triage alone is not permission to publish.\n\nFor an existing issue, preserve its human body and attribution. Add evidence separately\nwhen authorized. Don't rewrite the report into an investigation narrative.\n\nWhen authorized to publish, include useful collected evidence before finishing. Use a\nclearly labeled comment or attachment, whichever fits the evidence. If evidence cannot\nbe published, state the exact blocker and provide its local path. Never invent\nattachment URLs or create asset branches to host diagnostics. Keep the report body\nlimited to human details. Apply only existing, relevant labels; don't add\npriority/confidence prose just to fill a template.\n\nFinish with the concise draft (or issue link if submitted), any duplicate link, and\nattachment paths/links. Do not automatically file an issue, implement a fix, push a\nPR, or spawn a worker. Follow the user's requested scope and the repository's normal\ncontribution workflow if they separately ask for implementation.\n\nThe bundled `scripts/push_fix_to_github.py` is a legacy fix publisher, not a triage step.\n","frontmatter":{"name":"bug-triage","description":"Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft."},"isInternal":false,"tokens":1855,"sizeBytes":9173},{"name":"SKILL.md","path":".agents/skills/pr-description/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.agents/skills/pr-description/SKILL.md","title":"pr-description","category":"anthropic-skill","format":"markdown","content":"---\nname: pr-description\ndescription: Write and maintain pull request descriptions in this repository, including the required change-count header, the before-and-after section, and screenshots or recordings for visible changes.\n---\n\n# PR description\n\nUse the section order in `.github/pull_request_template.md`: change-count header,\nWhat, Why, Before / After, How, Testing, Checklist. Preserve the rest of an existing\nPR description when updating it.\n\n## Change-count header\n\nBegin every PR description with these three lines, using Markdown hard line breaks\nso each renders separately:\n\n```text\nCode changes: +<added> -<deleted>\nTests: +<added> -<deleted>\nOthers: +<added> -<deleted>\n```\n\nCalculate the numbers from the net diff against the PR's actual base. For a local\nbranch, use `git diff --numstat <base>...<head>`. After pushing, prefer GitHub's\nper-file additions and deletions. Recalculate after the final push rather than\nsumming commit churn or estimating counts.\n\nCount every changed file exactly once:\n\n- **Code changes:** handwritten implementation, including SQL, migrations, styles,\n  and executable scripts.\n- **Tests:** test code, fixtures, snapshots, and test-only helpers.\n- **Others:** generated or vendored files, lockfiles, documentation, configuration,\n  and assets. Generated output belongs here even when it contains source code.\n\nShow `+0 -0` for empty categories. Binary files have no line count; mention their\ncount separately when present. Add a brief qualifier when useful, such as\n`Others: +11 -0 (generated sqlc)`.\n\n## Before / After\n\nEvery PR has a `## Before / After` section with a two-column table, one row per\nbehavior that changed:\n\n```markdown\n| Before | After |\n| --- | --- |\n| ![Before: empty model list](before.png) | ![After: list filtered to six models](after.png) |\n| `ao session ls` exits 1 when a project has no sessions | Prints `No sessions` and exits 0 |\n```\n\n- **UI changes** need a screenshot of each changed state, before and after. Use a\n  short recording for flows, animations, focus or keyboard behavior, and timing.\n- **Non-visual changes** compare observable behavior: command output, API\n  responses, errors, logs, or measured numbers with their units.\n- **No user-visible change:** write `No user-visible change` and one line saying why,\n  such as an internal refactor or a test-only change.\n\nCapture both sides from the real app with the same screen, window size, and data,\nso they compare directly. Take the before capture from the PR's base branch. The\n`ao-desktop-dev` skill launches the desktop app from a checkout.\n\nScreenshots and GIFs go in the table. GitHub renders a video player only for a\nbare attachment URL on its own line, so put MP4 or MOV recordings on their own\nline below the table, with one line saying what they show.\n\nNever commit screenshots or recordings to the repository. Attach them in the PR\ndescription, or in a PR comment when the description gets long. If you cannot\nupload, give the capture file paths to the person who will attach them. Remove\nsecrets, tokens, and personal data from every capture.\n\n## Verify\n\nAfter creating or updating the PR, read the published description and verify that:\n\n- its opening lines match the current GitHub diff counts and required order;\n- every image and recording in Before / After, or in a PR comment, loads.\n","frontmatter":{"name":"pr-description","description":"Write and maintain pull request descriptions in this repository, including the required change-count header, the before-and-after section, and screenshots or recordings for visible changes."},"isInternal":false,"tokens":745,"sizeBytes":3340},{"name":"SKILL.md","path":".claude/skills/ao-desktop-dev/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.claude/skills/ao-desktop-dev/SKILL.md","title":"ao-desktop-dev","category":"anthropic-skill","format":"markdown","content":"---\nname: ao-desktop-dev\ndescription: Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data.\n---\n\n# AO Desktop Dev\n\nRead and follow [`../../../.agents/skills/ao-desktop-dev/SKILL.md`](../../../.agents/skills/ao-desktop-dev/SKILL.md) completely before launching or troubleshooting the desktop app. That file is the canonical cross-agent workflow for this repository.\n","frontmatter":{"name":"ao-desktop-dev","description":"Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data."},"isInternal":false,"tokens":153,"sizeBytes":731},{"name":"SKILL.md","path":".claude/skills/bug-triage/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.claude/skills/bug-triage/SKILL.md","title":"bug-triage","category":"anthropic-skill","format":"markdown","content":"---\nname: bug-triage\ndescription: Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft.\n---\n\n# Bug triage\n\nRead and follow [`../../../.agents/skills/bug-triage/SKILL.md`](../../../.agents/skills/bug-triage/SKILL.md) completely before clarifying, drafting, or filing anything. That file is the canonical cross-agent workflow for this repository.\n","frontmatter":{"name":"bug-triage","description":"Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft."},"isInternal":false,"tokens":91,"sizeBytes":416},{"name":"SKILL.md","path":"backend/internal/skillassets/using-ao/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/SKILL.md","title":"using-ao","category":"anthropic-skill","format":"markdown","content":"---\nname: using-ao\ndescription: \"Catalog of the AO (Agent Orchestrator) `ao` CLI: spawning workers, managing sessions and projects, creating reusable Cues, sending messages, controlling the shared browser, previewing pages, and daemon control. Use when using the ao CLI, creating Cues, spawning workers, or managing AO sessions in an AO workspace.\"\ntrigger: \"Using the ao CLI in an AO workspace: creating Cues, spawning workers, managing sessions/projects, sending messages, controlling or previewing pages.\"\n---\n\n# AO CLI Catalog\n\n`ao` is a thin CLI over the local AO daemon. Every command is `ao <command> --help` for the authoritative flag list.\n\n| Command | What it does | When to use | Details |\n|---|---|---|---|\n| `spawn` | Spawn a project worker, orchestrator, or projectless standalone worker | Starting a new task or issue | [commands/spawn.md](commands/spawn.md) |\n| `session` | Manage agent sessions (list, kill, rename, restore, history, etc.) | Inspecting or controlling running/terminated sessions, or reading the full conversation after taking over from another agent | [commands/session.md](commands/session.md) |\n| `agent` | Inspect installed harnesses and launch readiness | Choosing or diagnosing an agent harness | `ao agent ls --refresh` |\n| `pr` | Merge a PR or resolve its review threads | Completing a reviewed change | `ao pr merge` / `ao pr resolve-comments` |\n| `project` | Register, inspect, configure, or remove projects | Setting up or managing repos AO knows about | [commands/project.md](commands/project.md) |\n| `automation` | Manage durable recurring session automations | Creating, editing, disabling, deleting, and inspecting scheduled runs | [commands/automation.md](commands/automation.md) |\n| `cue` | Create or list reusable project Cues | Saving a repetitive command or agent task at the user's request | [commands/cue.md](commands/cue.md) |\n| `orchestrator` | List orchestrator sessions | Viewing which sessions are orchestrators | [commands/orchestrator.md](commands/orchestrator.md) |\n| `review` | Start, list, cancel, or submit AO's native reviewer for a worker's PR (default: this session) | Reviewing implementation PRs owned by AO workers. Use a normal review-only worker for someone else's PR | [commands/review.md](commands/review.md) |\n| `send` | Send a message to a running agent session | Messaging a live agent; use `--steer` to correct it mid-turn | [commands/send.md](commands/send.md) |\n| `report` | Persist a meaningful worker report | Checkpoints, blockers, decisions, outputs, and completion | [commands/report.md](commands/report.md) |\n| `preview` | Start a session-owned app or open an exact URL/file | Running and showing the worker's relevant app, Markdown, HTML, PDF, or image | [commands/preview.md](commands/preview.md) |\n| `render` | Show a self-contained HTML page inline in a chat thread | Answering with a chart, table, diagram, or mockup | [commands/render.md](commands/render.md) |\n| `browser` | Inspect and control the session's shared live browser | Verifying a web app through snapshots, interactions, waits, screenshots, console, and errors | [commands/browser.md](commands/browser.md) |\n| `browser` (remote host) | Drive the host's shared remote Chromium, used when `AO_AGENT_BROWSER_URL` is set | Same browser verification on a self-hosted remote host; one browser is shared across sessions | [commands/browser-remote.md](commands/browser-remote.md) |\n| `remote-host` | Link this machine to the user's AO account, or turn its remote access on or off | Setting up a VM or other headless machine so the user's desktops and phones can use it | [commands/remote-host.md](commands/remote-host.md) |\n| `start` | Fetch (if needed) and open the AO desktop app | Launching the app | [commands/start.md](commands/start.md) |\n| `stop` | Stop the AO daemon | Shutting down AO | [commands/stop.md](commands/stop.md) |\n| `status` | Show daemon status | Verifying the daemon is up and healthy | [commands/status.md](commands/status.md) |\n| `doctor` | Run local health checks | Diagnosing AO setup problems | [commands/doctor.md](commands/doctor.md) |\n| `import` | Import projects from a legacy AO install | Migrating from the old flat-file store | [commands/import.md](commands/import.md) |\n| `version` | Print version information | Checking installed version | - |\n| `completion` | Generate shell completion scripts | Setting up tab completion | - |\n\n## Conventions\n\n- Most read commands accept `--json` for machine-readable output.\n- `-p / --project` scopes session subcommand lookups to one project.\n- Session and project ids are shown by `ao session ls` and `ao project ls`.\n- To refer to a session in AO Chat or the AO terminal, use the canonical in-app\n  link `ao://sessions/{project-id}/{session-id}`. Read\n  [commands/session.md](commands/session.md) for identity, encoding, and safety\n  rules before constructing one.\n- When the user asks to save a repeatable task as a Cue, use `ao cue list --json` to check existing definitions, then `ao cue create`. An agent Cue stores a reusable instruction; a command Cue stores an exact shell command. This agent-facing command can create and read Cues, but cannot edit or delete them. Direct the user to project settings for changes to existing Cues.\n- `--agent` is an alias for `--harness` on `ao spawn`.\n- Every command accepts `-h / --help` for the full flag list.\n- For frontend launch, preview selection, or artifact handoff, read\n  [commands/preview.md](commands/preview.md) before acting. Its static-file,\n  project-runtime, and automatic-handoff rules are load-bearing.\n- For page inspection, interaction, or request diagnosis, read\n  [commands/browser.md](commands/browser.md). It defines shared-tab behavior\n  and the opt-in network policy.\n\nUse [references.md](references.md) only when a natural-language request does\nnot map clearly to a command above.\n","frontmatter":{"name":"using-ao","description":"Catalog of the AO (Agent Orchestrator) `ao` CLI: spawning workers, managing sessions and projects, creating reusable Cues, sending messages, controlling the shared browser, previewing pages, and daemon control. Use when using the ao CLI, creating Cues, spawning workers, or managing AO sessions in an AO workspace.","trigger":"Using the ao CLI in an AO workspace: creating Cues, spawning workers, managing sessions/projects, sending messages, controlling or previewing pages."},"isInternal":false,"tokens":1376,"sizeBytes":5879},{"name":"meta.json","path":"frontend/src/docs/content/plugins/agents/meta.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/agents/meta.json","title":"Agents Skill","category":"anthropic-skill","format":"json","content":"# Agents Skill\n\nPath: `frontend/src/docs/content/plugins/agents/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/agents/meta.json)","tokens":300,"sizeBytes":225},{"name":"meta.json","path":"frontend/src/docs/content/plugins/meta.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/meta.json","title":"Plugins Skill","category":"anthropic-skill","format":"json","content":"# Plugins Skill\n\nPath: `frontend/src/docs/content/plugins/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/meta.json)","tokens":300,"sizeBytes":212},{"name":"meta.json","path":"frontend/src/docs/content/plugins/notifiers/meta.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/notifiers/meta.json","title":"Notifiers Skill","category":"anthropic-skill","format":"json","content":"# Notifiers Skill\n\nPath: `frontend/src/docs/content/plugins/notifiers/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/notifiers/meta.json)","tokens":300,"sizeBytes":234},{"name":"meta.json","path":"frontend/src/docs/content/plugins/runtimes/meta.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/runtimes/meta.json","title":"Runtimes Skill","category":"anthropic-skill","format":"json","content":"# Runtimes Skill\n\nPath: `frontend/src/docs/content/plugins/runtimes/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/runtimes/meta.json)","tokens":300,"sizeBytes":231},{"name":"meta.json","path":"frontend/src/docs/content/plugins/scm/meta.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/scm/meta.json","title":"Scm Skill","category":"anthropic-skill","format":"json","content":"# Scm Skill\n\nPath: `frontend/src/docs/content/plugins/scm/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/scm/meta.json)","tokens":300,"sizeBytes":216},{"name":"meta.json","path":"frontend/src/docs/content/plugins/terminals/meta.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/terminals/meta.json","title":"Terminals Skill","category":"anthropic-skill","format":"json","content":"# Terminals Skill\n\nPath: `frontend/src/docs/content/plugins/terminals/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/terminals/meta.json)","tokens":300,"sizeBytes":234},{"name":"meta.json","path":"frontend/src/docs/content/plugins/trackers/meta.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/trackers/meta.json","title":"Trackers Skill","category":"anthropic-skill","format":"json","content":"# Trackers Skill\n\nPath: `frontend/src/docs/content/plugins/trackers/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/trackers/meta.json)","tokens":300,"sizeBytes":231},{"name":"meta.json","path":"frontend/src/docs/content/plugins/workspaces/meta.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/workspaces/meta.json","title":"Workspaces Skill","category":"anthropic-skill","format":"json","content":"# Workspaces Skill\n\nPath: `frontend/src/docs/content/plugins/workspaces/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/workspaces/meta.json)","tokens":300,"sizeBytes":237},{"name":"SKILL.md","path":"integrations/grok-bot/skills/ao-actions/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-actions/SKILL.md","title":"ao-actions","category":"anthropic-skill","format":"markdown","content":"---\nname: ao-actions\ndescription: >-\n  Direct actions on one AO session or PR: stop or interrupt, resume, merge a PR,\n  start a review, screenshot a session's browser, send a session's files, keep\n  a host awake, and recurring AO automations. Use for \"stop <session>\",\n  \"merge <PR>\", \"review <session>'s PR\", \"show me what <session> built\",\n  \"keep the Mac awake tonight\", \"every night, ...\".\n---\nFollow the ao-rules skill. Find the session first (ao-rules \"AO hosts\": `<host>/<session id>`). Run each action on the owner host from its `via` computer. \"Yes\" means the user's yes for that exact action in this chat.\n\n| Ask | Do | Yes needed | Hosts |\n|---|---|---|---|\n| Stop what it's doing now | `aoapi POST \"sessions/<id>/conversation/interrupt\"` | No | All |\n| End the session | `aoapi POST \"sessions/<id>/kill\" '{}'` | Yes | All |\n| Resume an exited agent | `aoapi POST \"sessions/<id>/resume-agent\" '{}'` | No | All |\n| Restore an ended session | `aoapi POST \"sessions/<id>/restore\" '{}'` (an ended orchestrator can't come back while its project has another live one) | Yes | All |\n| Merge a PR | see \"Merge\" | Yes, per PR | All |\n| Start AO's reviewer on a session's PR | `ao review trigger <id>` | Yes | Local |\n| Screenshot a session's browser | see \"Screenshot\" | No | Local |\n| A session's files | see \"Files\" | No | Local |\n| Keep the host awake | see \"Keep awake\" | Yes | Local |\n| Recurring agent work | see \"Automations\" | Yes | Local |\n| Start one worker directly | `aoapi POST sessions '<json>'` with `projectId`, `displayName`, `prompt` | Yes | All |\n\nFor an action marked Local on a remote host, ask that host's orchestrator to do it (ao-orchestrator).\n\nStart a worker directly only when the project has no orchestrator and the user doesn't want one (ao-rules \"orchestrator first\").\n\n## Merge\nFirst show the PR and ask:\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions/<session id>/pr\" | python3 -c '\nimport json,sys\nfor p in json.load(sys.stdin).get(\"prs\") or []:\n    if str(p.get(\"number\"))==sys.argv[1]: print(json.dumps({\"url\":p.get(\"url\"),\"headSha\":p.get(\"headSha\"),\"state\":p.get(\"state\"),\n        \"ci\":(p.get(\"ci\") or {}).get(\"state\"),\"review\":(p.get(\"review\") or {}).get(\"decision\"),\"mergeability\":(p.get(\"mergeability\") or {}).get(\"state\")}))' '<pr number>'; }; f\n```\nTell the user the link, checks (`ci`), review decision and whether it can merge (`mergeability`). Never merge on failing checks or `conflicting` without the user saying so for that PR. On yes, merge exactly the commit you showed:\n```sh\nf(){ <aoapi helper>; aoapi POST \"prs/<pr number>/merge\" \"$(python3 -c 'import json,sys; print(json.dumps({\"prUrl\":sys.argv[1],\"expectedHeadSha\":sys.argv[2]}))' '<url>' '<headSha>')\"; }; f\n```\nIf the PR got new commits since you showed it, AO refuses the merge. Show it again and ask again.\n\n## Screenshot\nThe session must have a browser page open. `BROWSER_CAPABILITY_INVALID` means it has none: say so.\n```sh\nf(){ mkdir -p ~/.ao-grok/out && AO_SESSION_ID='<id>' ao browser screenshot ~/.ao-grok/out/<id>-$(date +%H%M%S).png; }; f\n```\nThen CopyToBox and SendToUser.\n\n## Files\nA session's deliverables are in its artifact folder:\n```sh\nf(){ ls -la \"${AO_DATA_DIR:-$HOME/.ao/data}/artifacts/<id>/\"; }; f\n```\nSend the file the user asks for with CopyToBox and SendToUser. HTML reports render best opened on the phone as a file.\n\n## Keep awake\nFor a run that must last overnight, after a yes:\n```sh\nf(){ <aoapi helper>; aoapi POST awake/sessions \"$(python3 -c 'import json,sys; print(json.dumps({\"mode\":\"duration\",\"durationSeconds\":int(sys.argv[1]),\"scope\":\"ao\"}))' '<seconds>')\"; }; f\n```\nSay when it ends. The user can stop it in AO. An `AWAKE` error that mentions a safety stop means AO stopped keep-awake on purpose (for example on battery): tell the user to resume it in AO. Don't resume it yourself.\n\n## Automations\nFor recurring agent work that should run on the host even when the bot is off (for example \"every night, update dependencies in <project>\"), create an AO automation after a yes:\n```sh\nao automation create --project '<project>' --name '<name>' --cron '<m h dom mon dow>' --timezone '<IANA zone>' --prompt '<task>'\n```\n`ao automation list` shows them. To remove one after a yes: `ao automation delete --yes <id>`. Use a Grok routine instead when the job is to tell the user something (ao-status \"Digest\", ao-answer waiting check).\n","frontmatter":{"name":"ao-actions","description":"Direct actions on one AO session or PR: stop or interrupt, resume, merge a PR, start a review, screenshot a session's browser, send a session's files, keep a host awake, and recurring AO automations. Use for \"stop <session>\", \"merge <PR>\", \"review <session>'s PR\", \"show me what <session> built\", \"keep the Mac awake tonight\", \"every night, ...\"."},"isInternal":false,"tokens":1197,"sizeBytes":4375},{"name":"SKILL.md","path":"integrations/grok-bot/skills/ao-answer/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-answer/SKILL.md","title":"ao-answer","category":"anthropic-skill","format":"markdown","content":"---\nname: ao-answer\ndescription: >-\n  Find AO sessions that wait on the user, show each question or approval as\n  tap-to-answer options, and send the answer back to that session, following\n  ao-rules \"Decisions\" (default, away mode, standing approvals). Use for\n  \"what's waiting on me\", \"answer <session>\", \"approve it\", the AO waiting\n  check routine, and away mode.\n---\nFollow the ao-rules skill. Its \"Decisions\" section says who may answer. Answers go straight to the worker, not through the orchestrator: the user's pick must arrive exactly as given.\n\n## 1. Find what's waiting\nOn every host, in parallel:\n```sh\nf(){ <aoapi helper>\n  aoapi GET 'sessions?active=true' | python3 -c '\nimport json,sys,time,calendar\nnow=time.time()\nfor s in json.load(sys.stdin)[\"sessions\"]:\n    st=(s.get(\"activity\") or {}).get(\"state\"); t=(s.get(\"lastEventAt\") or \"\")[:19]\n    if st in (\"waiting_input\",\"blocked\"): print(\"W\", s[\"id\"])\n    elif st==\"idle\" and t and now-calendar.timegm(time.strptime(t,\"%Y-%m-%dT%H:%M:%S\"))<86400: print(\"I\", s[\"id\"], s.get(\"lastEventAt\"))' |\n  while read -r k id at; do\n    if [ \"$k\" = W ]; then\n      aoapi GET \"sessions/$id/conversation\" | python3 -c '\nimport json,sys\nd=json.load(sys.stdin); found=False\nfor a in d.get(\"activities\") or []:\n    if a.get(\"activityKind\") in (\"approval\",\"user_input\") and a.get(\"status\")==\"pending\":\n        found=True; print(json.dumps({\"session\":sys.argv[1],\"kind\":a[\"activityKind\"],\"requestId\":a.get(\"requestId\"),\n            \"summary\":a.get(\"summary\"),\"decisions\":a.get(\"decisions\") or (a.get(\"detail\") or {}).get(\"decisions\"),\"detail\":a.get(\"detail\")}))\nif not found: print(json.dumps({\"session\":sys.argv[1],\"kind\":\"reply\"}))' \"$id\" 2>/dev/null\n    else\n      aoapi GET \"sessions/$id/history?offset=0&limit=1\" | python3 -c '\nimport json,sys,re\nt=(json.load(sys.stdin).get(\"turns\") or [{}])[0]; r=(t.get(\"agentResponse\") or \"\").strip()\nif re.search(r\"\\?[\\s*_`)\\]]*$\", r): print(json.dumps({\"session\":sys.argv[1],\"kind\":\"reply\",\"lastEventAt\":sys.argv[2],\"asked\":r[-300:]}))' \"$id\" \"$at\" 2>/dev/null\n    fi\n  done; }; f\n```\nEach line is one thing waiting:\n\n| `kind` | What it is |\n|---|---|\n| `approval` | Permission to run a command or change files. `summary` and `detail.input` say what; `decisions` are the options `[{id, kind, label}]` |\n| `user_input` | A question. `detail.message` asks it; `detail.schema.properties` are the fields, with choices in `enum` or `oneOf` |\n| `reply` | The agent asked in plain text: a session that waits with no request (or a terminal session), or an idle session from the last 24 hours whose last reply ends with a question (`asked` holds its end). Read its last reply (ao-status \"One session in detail\") |\n\nIn the **AO waiting check** routine: keep what you already showed in `~/.ao-grok/shown.txt` on `via`, one line per item (`<host> <session> <requestId>`, or `<host> <session> reply <lastEventAt>` for a `reply`), and message only about new items. Send nothing when nothing new is waiting.\n\n## 2. Show it\nPer session, one short briefing first: `<host>/<session>` and its name, what it is doing, and what it asks, in one or two sentences. Don't recommend anything. Then:\n- `approval`: the command or change verbatim, the risk you judge (ao-rules), and the `decisions` labels exactly as options in one card. Mark a decision whose `kind` is `allow_always` as \"changes this agent's permissions for good\".\n- `user_input`: one card with every question in it, in order (the card pages through them). A field with `oneOf` or `enum` is a question: use the `oneOf` titles or `enum` values as its options, exactly. A field whose `_meta._askUserQuestionCustomAnswer.questionId` names another field is that question's \"Other\" box: show it as a typed-answer option on that question, not as its own question. Any other free-text field is a question with a typed answer. `detail.inputMode` `url` can't be answered from chat: tell the user to open AO.\n- `reply`: the agent's question from its last reply, with options if it gave clear ones, else ask for a typed answer.\n\nSeveral sessions at once: explain them together, then cards per session.\n\n## 3. Answer\nOn the owner host, from its `via` computer:\n- **Approval**:\n  `aoapi POST \"sessions/<id>/conversation/approvals/<requestId>/resolve\" \"$(python3 -c 'import json,sys; print(json.dumps({\"decisionId\":sys.argv[1]}))' '<decision id>')\"`\n- **Question**: `content` maps each field name to the pick. For a picked option use its `oneOf` `const` (or the `enum` value), not the title. For a typed \"Other\" answer, put the text under the \"Other\" field (for example `question_0_custom`) and leave its question out:\n  `aoapi POST \"sessions/<id>/conversation/inputs/<requestId>/resolve\" \"$(python3 -c 'import json,sys; print(json.dumps({\"action\":\"accept\",\"content\":json.loads(sys.argv[1])}))' '{\"<field>\":\"<pick>\"}')\"`\n  The user says no or skip: `{\"action\":\"decline\"}`.\n- **reply**: send the answer as a message (ao-rules \"Messages to agents\"):\n  `aoapi POST \"sessions/<id>/send\" \"$(python3 -c 'import json,sys; print(json.dumps({\"message\":\"[via Grok Bot] \"+sys.argv[1],\"userAuthored\":True}))' '<answer>')\"`\n\nConfirm in one line. An error that says the request is not pending or not found means it was already answered or closed: say so. Then run step 1 for that session again, and deal with anything still open.\n\n## Away mode\nWhen memory says away mode is on and its end time hasn't passed, answer as ao-rules \"Decisions\" allows instead of showing cards, and log each one. Tell the user afterwards in one line per answer: session, what it asked, what you picked, why. Anything you may not decide: show it as in step 2, and say away mode left it for them.\n","frontmatter":{"name":"ao-answer","description":"Find AO sessions that wait on the user, show each question or approval as tap-to-answer options, and send the answer back to that session, following ao-rules \"Decisions\" (default, away mode, standing approvals). Use for \"what's waiting on me\", \"answer <session>\", \"approve it\", the AO waiting check routine, and away mode."},"isInternal":false,"tokens":1563,"sizeBytes":5677},{"name":"SKILL.md","path":"integrations/grok-bot/skills/ao-orchestrator/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-orchestrator/SKILL.md","title":"ao-orchestrator","category":"anthropic-skill","format":"markdown","content":"---\nname: ao-orchestrator\ndescription: >-\n  Talk to a project's AO orchestrator: pass the user's request to it, wait for\n  its reply and relay it. The default route for starting or changing work,\n  \"catch me up\", \"why\", \"what next\" and plans. Use for \"in <project>: <ask>\",\n  \"tell the orchestrator ...\", \"catch me up on <project>\", \"start work on ...\".\n---\nFollow the ao-rules skill (\"Who does what: orchestrator first\"). Sending a message is a write: do it only for what the user asked in this turn.\n\n## 1. Pick the host and project\nMatch the user's words against project ids on every host (`aoapi GET projects`). One match: use it. The same project id on two hosts (two separate projects that share a folder name): ask which host, unless the user named one or memory has a default for that project. No match: list the projects and ask.\n\n## 2. Find the orchestrator\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions?orchestratorOnly=true&active=true&project=<project>\" | python3 -c '\nimport json,sys\nfor s in json.load(sys.stdin)[\"sessions\"]: print(s[\"id\"], (s.get(\"activity\") or {}).get(\"state\",\"\"), s.get(\"provisionState\",\"\"))'; }; f\n```\n- One line: that is the orchestrator. Its state tells you if it is busy (`active`).\n- `exited`: resume it first with `aoapi POST \"sessions/<id>/resume-agent\" '{}'`, then go on.\n- Provision state `failed`: AO could not create its workspace, and messages to it fail. Read the reason with `aoapi GET \"sessions/<id>\"` (field `provisionError`), tell the user in plain words, and ask them to fix it in AO. Stop here.\n- No line: ask \"There's no orchestrator in <project> on <host>. Start one with your request?\" On yes, start it with the request as its first message (step 3's file and tag), then go to step 4. Its reply is its first turn:\n\n### Start an orchestrator\n```sh\nf(){ <aoapi helper>; P='<project>'; TAG=\"[via Grok Bot #$(date +%H%M%S)]\"; F=~/.ao-grok/out/$(date +%F)-<short name>.md\n  mkdir -p ~/.ao-grok/out; { printf '%s ' \"$TAG\"; cat <<'EOF'\n<message>\nEOF\n  } > \"$F\"\n  H=$(aoapi GET \"projects/$P\" | python3 -c 'import json,sys; d=json.load(sys.stdin); c=(d.get(\"project\",d).get(\"config\") or {}); print((c.get(\"orchestrator\") or {}).get(\"agent\") or (c.get(\"worker\") or {}).get(\"agent\") or \"\")')\n  aoapi POST sessions \"$(python3 -c 'import json,sys; b={\"projectId\":sys.argv[1],\"kind\":\"orchestrator\",\"mode\":\"chat\",\"displayName\":\"Orchestrator\",\"prompt\":open(sys.argv[2]).read()}; b.update({\"harness\":sys.argv[3]} if sys.argv[3] else {}); print(json.dumps(b))' \"$P\" \"$F\" \"$H\")\" | python3 -c 'import json,sys; d=json.load(sys.stdin); d=d.get(\"session\",d); print(\"started\", d[\"id\"])' && echo \"TAG=$TAG\"; }; f\n```\nAfter about 10 seconds, check `provisionState` with `aoapi GET \"sessions/<new id>\"`. If it is `failed`, handle it as above.\n\n## 3. Send\nWrite the message to a file on `via`, then send it. The message is the user's request in their words, plus only the context from this chat the orchestrator needs. Don't add your own design choices. Start it with a tag so you can find the reply:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; TAG=\"[via Grok Bot #$(date +%H%M%S)]\"; F=~/.ao-grok/out/$(date +%F)-<short name>.md\n  mkdir -p ~/.ao-grok/out; { printf '%s ' \"$TAG\"; cat <<'EOF'\n<message>\nEOF\n  } > \"$F\"\n  B=$(python3 -c 'import json,sys; print(json.dumps({\"message\":open(sys.argv[1]).read(),\"userAuthored\":True}))' \"$F\")\n  if aoapi POST \"sessions/$O/send\" \"$B\" >/dev/null; then echo \"sent TAG=$TAG F=$F\"; return 0; fi\n  echo \"SEND_FAILED: resuming the agent and trying once more\"\n  aoapi POST \"sessions/$O/resume-agent\" '{}' >/dev/null; sleep 5\n  aoapi POST \"sessions/$O/send\" \"$B\" >/dev/null && echo \"sent TAG=$TAG F=$F\"; }; f\n```\nA failed send prints AO's error. If it still fails after the retry, tell the user the orchestrator isn't accepting messages and to open it in AO.\n\nIf the orchestrator was `active` in step 2, the message waits and runs as its own turn after the current one. Tell the user right away, in one line: \"The orchestrator is busy with <what its last turn is about>. Your question is queued and runs next.\" Then go on to step 4.\n\nIf the user wants to change what it is doing right now (\"stop that\", \"use X instead\"), steer instead. Write the file and tag as above, then:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; F='<message file>'\n  aoapi POST \"sessions/$O/conversation/steer-or-send\" \"$(python3 -c 'import json,sys,uuid; print(json.dumps({\"text\":open(sys.argv[1]).read(),\"clientMessageId\":str(uuid.uuid4())}))' \"$F\")\"; }; f\n```\n`\"outcome\":\"sent\"` means it arrived (in the running turn, or as a new turn if the orchestrator was idle). Then go to step 4.\n\n## 4. Wait for the reply\nCheck every 10 seconds for up to 5 minutes. Done when the orchestrator is no longer `active` and a turn that starts with your tag has a reply:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; TAG='<tag>'\n  for i in $(seq 30); do sleep 10\n    st=$(aoapi GET \"sessions/$O\" | python3 -c 'import json,sys; d=json.load(sys.stdin); d=d.get(\"session\",d); print((d.get(\"activity\") or {}).get(\"state\",\"\"))')\n    [ \"$st\" = active ] && continue\n    aoapi GET \"sessions/$O/history?offset=0&limit=5\" | python3 -c '\nimport json,sys\nfor t in json.load(sys.stdin).get(\"turns\") or []:\n    if (t.get(\"userRequest\") or \"\").startswith(sys.argv[1]) and t.get(\"agentResponse\"):\n        print(t[\"agentResponse\"]); raise SystemExit(0)\nraise SystemExit(1)' \"$TAG\" && return 0\n  done; echo STILL_WORKING; }; f\n```\n- A reply: relay it. Keep it faithful. Shorten only for a phone, and send a long reply as a file.\n- `STILL_WORKING`: tell the user the orchestrator is still on it, and offer: \"I'll message you when it replies.\" On yes, create a routine that runs step 4 once every 5 minutes for that tag, reports the reply, then deletes itself.\n- The orchestrator asks the user something back: show it as a card if it gives clear options, and send the pick as a new message (step 3).\n\n## 5. After\nIf the orchestrator started workers, list them in one line (ao-status \"Sessions\" for that project). Don't watch them unless the user asks. Their questions reach the user through ao-answer.\n","frontmatter":{"name":"ao-orchestrator","description":"Talk to a project's AO orchestrator: pass the user's request to it, wait for its reply and relay it. The default route for starting or changing work, \"catch me up\", \"why\", \"what next\" and plans. Use for \"in <project>: <ask>\", \"tell the orchestrator ...\", \"catch me up on <project>\", \"start work on ...\"."},"isInternal":false,"tokens":1757,"sizeBytes":6120},{"name":"SKILL.md","path":"integrations/grok-bot/skills/ao-rules/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-rules/SKILL.md","title":"ao-rules","category":"anthropic-skill","format":"markdown","content":"---\nname: ao-rules\ndescription: >-\n  Shared rules and the connection helper for every ao-* skill (run\n  Orchestrator from chat). Read before running any ao-* skill.\n---\n# AO rules\n\nEvery ao-* skill follows these rules. Other skills link here instead of repeating them.\n\n## AO hosts\nAn **AO host** is one computer that runs the AO daemon. Each host has its own projects, sessions and orchestrators, and AO never links them: a repo cloned on two hosts is two separate projects. AO names a project after its folder, so both can still get the same id, and then the same session id (for example `agent-orchestrator-1-12`) can exist on both. Always name a session as `<host>/<session id>`, and act only on the host that owns it.\n\nMemory keeps one note named **AO hosts**, with one line per host:\n\n| Field | Example | Meaning |\n|---|---|---|\n| `name` | `Pro` | A short name: the user's pick, else the model word of the ListMachines label (`Pro`, `Air`, `mini`). Never the network hostname such as `MacBookAir.lan` |\n| `reach` | `local` or `remote` | How you get to its AO |\n| `via` | `laptop` | The ListMachines label of the computer whose shell you use |\n| `base` | `http://192.168.1.20:7444` | Remote only. The host's LAN address from AO's remote access settings |\n| `header` | `~/.ao-grok/studio.header` | Remote only. File on `via` that holds the host's password |\n\n- **local**: the Grok Bot desktop app runs on the AO host. `via` is the host itself.\n- **remote**: the Grok Bot desktop app runs on another computer. You call the host's AO API over the network from `via`. The `ao` CLI on `via` talks only to `via`'s own AO, so never use it for a remote host.\n\nOne computer can be `via` for itself (local) and for other hosts (remote) at the same time.\n\nEvery run: call ListMachines, then use every host whose `via` computer is connected, in parallel, labelled by host name. Say once which hosts you could not reach. Never hard-code machine ids or home paths.\n\n## Calling AO\nStart every shell command that calls AO with this helper. It works in zsh and bash:\n\n```sh\naoapi(){ # aoapi METHOD PATH [JSON]\n  local base hdr=() data=() f=\"${AO_RUN_FILE:-$HOME/.ao/running.json}\"\n  if [ -n \"$AO_REMOTE_BASE\" ]; then base=\"$AO_REMOTE_BASE\"; hdr=(-H @\"$AO_REMOTE_HEADER\")\n  else [ -f \"$f\" ] || { echo \"AO_NOT_RUNNING\" >&2; return 3; }\n    base=\"http://127.0.0.1:$(grep -o '\"port\": *[0-9]*' \"$f\" | grep -o '[0-9]*$')\"; fi\n  [ -n \"$3\" ] && data=(--data \"$3\")\n  curl -sS --fail-with-body --max-time 30 -X \"$1\" \"${hdr[@]}\" -H 'Content-Type: application/json' \"${data[@]}\" \"$base/api/v1/$2\"\n}\n```\n\n- Local host: use `aoapi` as is.\n- Remote host: on the `via` computer, first set `AO_REMOTE_BASE='<base>' AO_REMOTE_HEADER=\"$HOME/.ao-grok/<name>.header\"`.\n- Build JSON bodies with `python3 -c 'import json,sys; print(json.dumps(...))' \"$ARG\"`, never by pasting text into quotes.\n- Anything longer than one line goes in a file first: `~/.ao-grok/out/<date>-<short name>.md` on `via`. The user can see what was sent.\n- Use the `ao` CLI only where a skill says \"local only\".\n\n### Errors\n| You see | Meaning and next step |\n|---|---|\n| `AO_NOT_RUNNING`, or connection refused on a local host | AO is not running there. Ask the user to open AO |\n| Connection refused or timeout on a remote host | The host is asleep, off this network, or remote access is off. Ask the user to check AO's remote access settings on the host |\n| HTTP 401 or 403 on a remote host | The host's password changed. Run ao-setup \"Remote host\" again |\n| HTTP 404 on a session path | No such session on that host. Check the host name |\n| Any other error | AO returns JSON with `message`. Relay it in plain words |\n\n## Who does what: orchestrator first\nEach project on a host has at most one live **orchestrator**: an agent that plans the project's work, starts and steers workers, and gets their reports. It has more context than you do. You are the user's phone line to it.\n\n- **Send to the orchestrator** (ao-orchestrator): starting or changing work, \"catch me up\", \"why\", \"what next\", plans, and anything that needs judgement about the code.\n- **Do directly**: status lists (ao-status), answering a pending request with the user's own pick (ao-answer), stop and interrupt, merges after the user's yes, files and screenshots (ao-actions).\n- Never start a worker yourself in a project that has a live orchestrator. Ask the orchestrator instead. With no orchestrator, ask the user whether to start one or to start the worker directly.\n- After you act directly on a worker (answer, stop, merge), the orchestrator sees it through AO. Don't send it a separate note.\n\n## Decisions\nA worker asks for two kinds of decision. A **question** (`user_input`) asks what to build. An **approval** asks permission to run a command or change files. Who decides depends on the mode, saved in memory:\n\n1. **Default mode**: show each question or approval to the user as a card with the exact options. Answer only with their pick for that request. Never reuse a pick for a new request.\n2. **Away mode** starts when the user says something like \"I'm away\", \"decide for me\" or \"keep it moving\". Save the scope and the end time in memory. Then:\n   - Answer routine questions yourself, and tell the user afterwards what you picked and why.\n   - Accept `low` and `normal` approvals with the one-time option (`kind` `allow_once`). Never pick an `allow_always` option: it changes the agent's permissions for good. Never accept a `high` approval without the user's yes for that request.\n   - Leave product direction, money, publishing and anything the user kept for themselves to the user.\n   - Away mode ends at the end time or when the user is back. Say when it ended.\n3. **Standing approvals**: the user may list kinds of approvals to always accept. Follow the list exactly.\n\nAO gives no risk level, so you judge it. Treat these as a floor. If a command looks riskier, call it high.\n\n| Risk | Examples |\n|---|---|\n| high | Deletes outside the session's worktree, `rm -rf`, `git push --force`, push to `main` or `master`, `git reset --hard`, history rewrites, deploy, publish, release, secrets, credentials, tokens, `sudo`, system installs, payments |\n| low | Reading or searching files, `git status`/`diff`/`log`, tests, lint, typecheck, builds |\n| normal | Everything else, such as edits and commits in the session's worktree, or pushing the session's own branch |\n\nNever invent the user's preferences. The worker decides how to do the work. The user decides what to build.\n\n## Writes\nChange nothing on the user's computers unless the user approved that exact change in chat, or away mode or a standing approval covers it. Approval for one change is not approval for the next. Never delete or archive sessions or projects, never change AO settings, and never merge, publish or deploy without the user's yes for that item.\n\n## Secrets\n- The `header` file holds a host's password. Pass it only to curl as `-H @<file>`. Never open, print, copy or paste it.\n- Never read AO's own credential files: `~/.ao/mobile/`, `~/.ao/data/agent-accounts/`, `~/.ao/electron/`, or any `*token*`, `*auth*`, `.env` or keychain item.\n- If session text contains a key, never repeat it.\n\n## Messages to agents\n- Before you send a follow-up, read the last turn (`aoapi GET \"sessions/<id>/history?offset=0&limit=1\"`) so you don't repeat or contradict it.\n- Keep messages short and concrete: what is right so far, then the next step. Leave out check-ins, your own process and these rules.\n- Start every message you send with `[via Grok Bot]`, so the user can tell it apart in AO.\n\n## Output\n- Answer first, in short plain words. Say what you could not check.\n- Write every session as `<host name>/<session id>`, every time, in every skill and every line, even when only one host has that id: `Air/agent-orchestrator-31`, `Pro/agent-orchestrator-1-249`. Add the display name when it helps.\n- Give times in the user's timezone.\n- One message per event. If two checks report the same thing, say it once. News (a merge, a finished review) is reported once: ao-status keeps a seen list.\n- Send files with SendToUser. Copy them to the box first with CopyToBox.\n\n## Memory\n- Save hosts, modes and preferences, not activity. A check where nothing changed is not worth a note.\n- When the user corrects you, save the correction.\n- A follow-up you promise for later (\"I'll tell you when it's done\") goes into a Routine, not only into memory.\n\n## Grok Bot only\nThese steps need tools only Grok Bot has. Any other agent (Claude Code, Codex, Cursor) runs on one computer and does this instead:\n\n| Grok Bot step | Other agents |\n|---|---|\n| ListMachines, every connected computer | Only the computer you run on, as a local host |\n| Routines | Run the check once when asked |\n| Cards | Plain text with numbered options |\n| Memory | Ask, or use the notes file the user names |\n| SendToUser, CopyToBox | Give the file path |\n","frontmatter":{"name":"ao-rules","description":"Shared rules and the connection helper for every ao-* skill (run Orchestrator from chat). Read before running any ao-* skill."},"isInternal":false,"tokens":2298,"sizeBytes":8905},{"name":"SKILL.md","path":"integrations/grok-bot/skills/ao-setup/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-setup/SKILL.md","title":"ao-setup","category":"anthropic-skill","format":"markdown","content":"---\nname: ao-setup\ndescription: >-\n  First run of Orchestrator Bot: find every computer that runs AO, save them as\n  AO hosts, add a remote AO host that has no Grok Bot desktop app, and turn on\n  optional routines. On a computer without Orchestrator.inc it helps install it\n  and get it ready: a coding agent, a first project and the first orchestrator.\n  Use on the first chat, when memory has no \"AO hosts\" note, or when the user\n  says \"set up AO\", \"add a host\", \"add remote host\", \"check my AO setup\" or\n  \"install Orchestrator\".\n---\nFollow the ao-rules skill. Detection is read-only. Nothing is written until the user says yes.\n\nOpen with one line: \"Give me a few seconds to look for AO on your computers.\"\n\n## 1. Detect\n1. ListMachines. Use desktops only. If none is connected, say: \"Install the Grok Bot desktop app on the computer where you run Orchestrator.inc (or want to), sign in, and tell me when it shows up,\" then stop.\n2. On each connected desktop, in parallel, run this read-only probe with the `aoapi` helper from ao-rules: run \"Probe\" below.\n3. Each desktop where the probe prints a `projects=` line is a **local** AO host; an empty list means it still needs \"First run\". For any other result, see \"Missing pieces\". On a Windows desktop, don't run the probe: say once \"These skills need macOS or Linux; Windows isn't supported yet,\" and skip it.\n\n### Probe\n```sh\nf(){ <aoapi helper>; echo \"ao=$(command -v ao >/dev/null && ao version 2>/dev/null | head -1 || echo missing)\"\n  if [ \"$(uname -s)\" = Darwin ] && [ \"$(command -v python3)\" = /usr/bin/python3 ] && ! xcode-select -p >/dev/null 2>&1; then echo \"python=missing\"\n  else echo \"python=$(command -v python3 >/dev/null && python3 -c 'import sys;print(\"%d.%d\"%sys.version_info[:2])' || echo missing)\"; fi\n  [ \"$(uname -s)\" = Darwin ] && A=$(find /Applications \"$HOME/Applications\" -maxdepth 1 -name '*Orchestrator*.app' 2>/dev/null | head -1) && echo \"app=${A:-missing}\"\n  if P=$(aoapi GET projects 2>/dev/null); then\n    echo \"$P\" | python3 -c 'import json,sys; d=json.load(sys.stdin); p=d.get(\"projects\",d) if isinstance(d,dict) else d; print(\"projects=\" + \", \".join(x.get(\"id\",\"?\") for x in p))'\n    aoapi GET 'sessions?active=true' | python3 -c 'import json,sys; print(\"live_sessions=%d\" % len(json.load(sys.stdin)[\"sessions\"]))'\n  else echo \"daemon=not running\"; fi; }; f\n```\n\n## Missing pieces\nUse the probe result for each computer. Install or open anything only after the user's yes.\n\n| Probe shows | Next step |\n|---|---|\n| `python=missing` | Fix this first: every step needs it. macOS: `xcode-select --install` (the user confirms the system dialog). Linux: give the package manager line for python3 |\n| `daemon=not running` and `app=missing` (macOS) | Say: \"Orchestrator.inc isn't installed on <computer>. Want me to install it? It's about a 300 MB download.\" On yes, run \"Install on a Mac\" |\n| `daemon=not running` and `app=<path>` | On yes, open it with `open \"<path>\"`, then \"Wait for the app\" |\n| `daemon=not running` on Linux | If Orchestrator.inc is installed, ask the user to open it and say **check again**. Otherwise give the download for the user's distribution: [AppImage](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.AppImage), [.deb](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.deb) or [.rpm](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.rpm). The user installs and opens it, then says **check again** |\n| `projects=` with nothing after it | Run \"First run\" |\n| `ao=missing` with projects listed | Everything works except starting a review, screenshots and automations, which use the `ao` CLI. Say so once |\n\n**check again** runs the probe on that computer again and goes on from its result.\n\n**Wait for the app:** run the probe every 15 seconds, for up to 2 minutes, until it prints a `projects=` line. Still `daemon=not running` after that: ask the user to look at the Orchestrator.inc window and say **check again** when it's open.\n\n### Install on a Mac\nAfter a yes, on that computer. The download takes a few minutes, so the install runs in the background, in its own session so it keeps going after this command returns, and writes its progress to `~/.ao-grok/install.log`. It picks the build for the Mac's chip, checks the app's code signature (Orchestrator.inc's Developer ID team `X9LNSP8MC2`), copies it to Applications (or `~/Applications` if that isn't writable) and opens it:\n```sh\nf(){ mkdir -p ~/.ao-grok && cat > ~/.ao-grok/install-orchestrator.sh <<'EOF'\na=$([ \"$(sysctl -n hw.optional.arm64 2>/dev/null)\" = 1 ] && echo arm64 || echo x64); d=$(mktemp -d)\necho \"downloading the $a build\"\ncurl -fsSL -o \"$d/o.dmg\" \"https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/Orchestrator-darwin-$a.dmg\" || { echo DOWNLOAD_FAILED; rm -rf \"$d\"; exit 1; }\nm=$(hdiutil attach -nobrowse -readonly \"$d/o.dmg\" | awk -F'\\t' '/\\/Volumes\\//{print $NF}' | tail -1)\n[ -n \"$m\" ] || { echo INSTALL_FAILED; rm -rf \"$d\"; exit 1; }\napp=$(find \"$m\" -maxdepth 1 -name '*.app' 2>/dev/null | head -1)\ndone_(){ [ -n \"$m\" ] && hdiutil detach -quiet \"$m\"; rm -rf \"$d\"; }\nif [ -z \"$app\" ] || ! codesign --verify --deep --strict \"$app\" 2>/dev/null || ! codesign -dv \"$app\" 2>&1 | grep -q 'TeamIdentifier=X9LNSP8MC2'; then echo BAD_SIGNATURE; done_; exit 1; fi\ndest=/Applications\ncp -R \"$app\" \"$dest/\" 2>/dev/null || { dest=\"$HOME/Applications\"; mkdir -p \"$dest\" && cp -R \"$app\" \"$dest/\"; } || { echo INSTALL_FAILED; done_; exit 1; }\ndone_\nopen \"$dest/${app##*/}\" && echo \"INSTALLED $dest/${app##*/}\" || echo \"INSTALLED_NOT_OPENED $dest/${app##*/}\"\nEOF\nnohup python3 -c 'import os,sys; os.setsid(); os.execvp(\"sh\", [\"sh\", sys.argv[1]])' ~/.ao-grok/install-orchestrator.sh > ~/.ao-grok/install.log 2>&1 & echo STARTED; }; f\n```\nTell the user it has started. Then check `tail -1 ~/.ao-grok/install.log` every 20 seconds, for up to 15 minutes:\n\n| Last line | Next step |\n|---|---|\n| `downloading …` | Still going |\n| `INSTALLED <path>` | Say \"Orchestrator.inc is open on <computer>. I'll get it ready: a coding agent and your first project.\" Then \"Wait for the app\" and run \"First run\" |\n| `INSTALLED_NOT_OPENED <path>` | Open it with `open \"<path>\"`, then as above |\n| `DOWNLOAD_FAILED`, `BAD_SIGNATURE`, `INSTALL_FAILED`, or no change after 15 minutes | Say what happened and give the user the [download page](https://orchestrator.inc/download/) instead. Never retry `BAD_SIGNATURE` |\n\n## First run\nGets a computer ready for work once Orchestrator.inc is running there: a coding agent, a project, and the first orchestrator. Every change needs the user's yes. If Orchestrator.inc shows its own welcome steps and the user prefers them, let them finish there and say **check again**.\n\n### 1. A coding agent\n```sh\nf(){ <aoapi helper>; aoapi POST agents/refresh '{}' >/dev/null; aoapi GET agents/readiness | python3 -c '\nimport json,sys\nfor a in json.load(sys.stdin).get(\"agents\") or []:\n    inst=(a.get(\"installation\") or {}).get(\"state\",\"\"); auth=(a.get(\"authentication\") or {}).get(\"state\",\"\")\n    if inst!=\"not_installed\" or a.get(\"id\") in (\"claude-code\",\"codex\"):\n        print(\"\\t\".join([a.get(\"id\",\"\"), a.get(\"label\",\"\"), a.get(\"effectiveReadiness\",\"\"), inst, auth]))'; }; f\n```\nColumns: id, name, readiness, installed, signed in.\n- **Some agent is `ready`:** use it. If more than one is ready, ask which one should do the work. Don't pick for the user.\n- **Installed but not signed in:** on yes, `aoapi POST \"agents/<id>/auth\" '{}'` and relay its `guidance`. The sign-in runs in a terminal inside Orchestrator.inc; the user finishes it there (it may open their browser). When they say done, run this step again: it refreshes the checks.\n- **None installed:** ask \"Which coding agent do you want to use: Claude Code or Codex?\" On the pick and a yes, `aoapi POST \"agents/<id>/install\" '{}'`, then check `aoapi GET \"agents/<id>/install\"` every 15 seconds. `status` `succeeded`: sign in as above. `failed`, `unsupported` or `interrupted`: relay it, and point the user to the agent settings in Orchestrator.inc.\n\n### 2. A project\nSuggest the git clones the user worked in most recently (read-only; worktrees are left out):\n```sh\npython3 -c '\nimport glob,os\nhome=os.path.expanduser(\"~\"); found=set()\nfor r in (\"Development\",\"Projects\",\"projects\",\"code\",\"Code\",\"src\",\"dev\",\"GitHub\",\"Documents/GitHub\"):\n    for pat in (\"*/.git\",\"*/*/.git\",\"*/*/*/.git\"): found.update(os.path.dirname(g) for g in glob.glob(os.path.join(home,r,pat)) if os.path.isdir(g))\nfor p in sorted(found,key=lambda p:-os.path.getmtime(os.path.join(p,\".git\")))[:10]: print(p.replace(home,\"~\",1))'\n```\nShow them as one card, plus a typed option for another folder. On the pick, register it with the agent from step 1:\n```sh\nf(){ <aoapi helper>; aoapi POST projects \"$(python3 -c 'import json,os,sys; print(json.dumps({\"path\":os.path.expanduser(sys.argv[1]),\"config\":{\"worker\":{\"agent\":sys.argv[2]},\"orchestrator\":{\"agent\":sys.argv[2]}}}))' '<repo path>' '<agent id>')\" 2>/dev/null | python3 -c '\nimport json,sys\nd=json.load(sys.stdin); p=d.get(\"project\",d)\nif p.get(\"id\"): print(\"added\", p[\"id\"])\nelse: print(d.get(\"code\",\"ERROR\"), d.get(\"message\",\"\"), (d.get(\"details\") or {}).get(\"existingProjectId\",\"\"))'; }; f\n```\n- `added <id>`: done.\n- `NOT_A_GIT_REPO`: the folder needs to be a git repository with at least one commit. Ask for another folder.\n- `PATH_ALREADY_REGISTERED <id>`: it is already a project; use that id.\n\n### 3. The first orchestrator\nAsk: \"Want me to start the orchestrator for <project>? Tell me what you'd like done first, or I'll ask it to look around the repo and suggest a first task.\" On yes, run ao-orchestrator \"Start an orchestrator\" with that request.\n\nThen continue with section 2.\n\n## 2. Report and ask once\nOne message, at most 6 lines: per computer, AO found or not, its projects, and how many sessions are live. For a computer without a working AO, add the one next step from \"Missing pieces\". Then:\n\"Reply **yes** and I'll save these as your AO hosts. Is AO also running on a computer without the Grok Bot desktop app? Say **add remote host** and I'll connect to it from one of these.\"\n\nOn yes, save the **AO hosts** note (ao-rules \"AO hosts\") with `reach: local` and `via` = the same computer. Name each host with its short name (ao-rules `name`) and say the names in one line: \"I'll call them Pro and Air. Say if you want other names.\"\n\n## 3. Remote host (optional)\nUse this when AO runs on a computer that has no Grok Bot desktop app, for example a Mac mini host that a laptop's AO app already connects to.\n\n1. Ask for a short host name (letters, digits, `-`) and which connected computer to use as `via`. Default: the one the user's message came from.\n2. Tell the user, in one message:\n   \"On the host, open AO, go to remote access (Connect Mobile) and turn on network access. It shows an address and a password. Send me the **address** here. You'll type the password on <via> in a window I open, so it never passes through this chat.\"\n   On the host's own terminal, `ao remote-host enable` turns on the same network access, and `ao remote-host status` shows the address and the password.\n3. When the address arrives, check it looks like `http://<ip or name>:<port>`. Then, on `via`, write a one-time password window and open it. Replace `<name>` with the host name you checked: run \"Password window\" below.\n   Tell the user: \"A Terminal window opened on <via>. Type the password there and press Return.\"\n   On Linux, `open` doesn't run `.command` files: write the same lines to `~/.ao-grok/add-<name>.sh` and ask the user to run `zsh ~/.ao-grok/add-<name>.sh` in a terminal on `via`.\n4. When they say done, test it from `via`: run \"Connection test\" below.\n   HTTP 401 means a wrong password: open the window again. A timeout means the host is not reachable from `via` (another network, asleep, or access off).\n5. Add the host to the **AO hosts** note with `reach: remote`, `via`, `base` and `header`.\n\n### Password window\n```sh\nf(){ mkdir -p ~/.ao-grok/out && cat > ~/.ao-grok/add-<name>.command <<'EOF'\n#!/bin/zsh\numask 077\nread -rs \"p?AO password for <name>: \"; echo\nprintf 'Authorization: Bearer %s\\n' \"$p\" > ~/.ao-grok/<name>.header\necho \"Saved. You can close this window.\"; rm -- \"$0\"\nEOF\nchmod +x ~/.ao-grok/add-<name>.command && open ~/.ao-grok/add-<name>.command; }; f\n```\n\n### Connection test\n```sh\nf(){ <aoapi helper>; AO_REMOTE_BASE='<address>' AO_REMOTE_HEADER=\"$HOME/.ao-grok/<name>.header\" aoapi GET 'sessions?active=true' | python3 -c 'import json,sys; print(\"live_sessions=%d\" % len(json.load(sys.stdin)[\"sessions\"]))'; }; f\n```\n\nLimits of a remote host, said once: keep-awake, browser screenshots and starting a review work only on local hosts. For those, ask the host's orchestrator (ao-orchestrator). Quick-tunnel addresses change when the tunnel restarts, so prefer the LAN address or a named tunnel. If the user presses Regenerate in AO, run this section again.\n\n## 4. Mode and routines\n1. Save **Mode: default** in memory (ao-rules \"Decisions\"). Say in one line that away mode exists: \"Say 'I'm away till 6' and I'll keep routine work moving.\"\n2. Offer the routines in one multi-select card, nothing pre-selected, plus **none**:\n   - **AO waiting check**: every 30 minutes, 9:00 to 19:00 on weekdays. Runs ao-answer \"Find what's waiting\" and messages only when something new is waiting.\n   - **AO daily digest**: weekdays at 9:00. Runs ao-status \"Digest\".\n   Create the picked routines, then save \"Routines on: <names>\" in memory. Never create a second copy.\n3. Say once: \"AO's mobile app pushes questions to your phone the moment they happen. These routines check on a schedule.\"\n\n## 5. Finish\nOne line: the hosts saved (local and remote), the mode and the routines on. Then run ao-status as a first look, then:\n\nThings to try:\n- what's waiting on me\n- catch me up on <project>\n- in <project>: <what you want done>\n- I'm away till 6, keep things moving\n- what's ready to merge\n- show me what <session> built\n","frontmatter":{"name":"ao-setup","description":"First run of Orchestrator Bot: find every computer that runs AO, save them as AO hosts, add a remote AO host that has no Grok Bot desktop app, and turn on optional routines. On a computer without Orchestrator.inc it helps install it and get it ready: a coding agent, a first project and the first orchestrator. Use on the first chat, when memory has no \"AO hosts\" note, or when the user says \"set up AO\", \"add a host\", \"add remote host\", \"check my AO setup\" or \"install Orchestrator\"."},"isInternal":false,"tokens":3951,"sizeBytes":14128},{"name":"SKILL.md","path":"integrations/grok-bot/skills/ao-status/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-status/SKILL.md","title":"ao-status","category":"anthropic-skill","format":"markdown","content":"---\nname: ao-status\ndescription: >-\n  What AO is doing on every host: which sessions are running, waiting on the\n  user, idle or exited, which PRs are ready to merge or got a review, and a\n  daily digest. Read-only. Use for \"status\", \"what's running\", \"what's waiting\n  on me\", \"what's ready to merge\", \"anything stuck\", and the AO daily digest\n  routine.\n---\nFollow the ao-rules skill. Read-only in AO: it never marks anything read there. It keeps its own seen list in `~/.ao-grok/` on each `via` computer. Run on every host in the **AO hosts** note, in parallel, each from its `via` computer with the `aoapi` helper (set `AO_REMOTE_BASE` and `AO_REMOTE_HEADER` for remote hosts). If memory has no **AO hosts** note, run ao-setup first. Don't save hosts without the user's yes.\n\n## 1. Sessions\n```sh\nf(){ <aoapi helper>; aoapi GET 'sessions?active=true' | python3 -c '\nimport json,sys\nfor s in json.load(sys.stdin)[\"sessions\"]:\n    a=s.get(\"activity\") or {}\n    print(\"\\t\".join([s[\"id\"], s.get(\"kind\",\"\"), a.get(\"state\",\"\"), str(len(s.get(\"prs\") or [])), (s.get(\"displayName\") or \"\")[:60]]))'; }; f\n```\nColumns: id, kind (`orchestrator` or `worker`), state, PR count, name. States:\n\n| State | Say |\n|---|---|\n| `active` | running |\n| `waiting_input`, `blocked` | waiting on you |\n| `idle` | idle: finished its turn, or not started |\n| `exited` | the agent exited; it can be resumed (ao-actions) |\n\nFor what's waiting on the user, run ao-answer \"Find what's waiting\": it finds sessions in `waiting_input` or `blocked`, and idle sessions whose last reply asked the user a question. Never use notifications for it. Group by host, then by project (the session id starts with the project id).\n\nKeep the reply short enough for a phone, at most 6 lines: first what needs the user, then what's running, then one line per host with counts (for example \"MacBook Pro: 25 idle, 9 exited\"). Name a session only when it needs the user or is running. Leave out idle orchestrators, PR numbers and exited sessions unless asked. Report what you saw; don't guess why (a crash, a restart) unless the user asks.\n\n## 2. PRs and reviews\n```sh\nf(){ <aoapi helper>\n  aoapi GET 'notifications?status=unresolved' | python3 -c '\nimport json,sys\nfor n in json.load(sys.stdin)[\"notifications\"]:\n    if n.get(\"type\")==\"ready_to_merge\": print(\"\\t\".join([\"ready_to_merge\", n.get(\"sessionId\",\"\"), n.get(\"prUrl\",\"\"), (n.get(\"title\") or \"\")[:80]]))'\n  SEEN=\"$HOME/.ao-grok/<host name>.seen-news\"; mkdir -p ~/.ao-grok; touch \"$SEEN\"\n  aoapi GET 'notifications?status=unread' | python3 -c '\nimport json,sys\nseen=set(open(sys.argv[1]).read().split()); new=[]\nfor n in json.load(sys.stdin)[\"notifications\"]:\n    if n.get(\"type\") in (\"review_completed\",\"review_changes_requested\",\"pr_merged\",\"pr_closed_unmerged\") and not n.get(\"resolvedAt\") and n.get(\"id\") not in seen:\n        new.append(n[\"id\"]); print(\"\\t\".join([n[\"type\"], n.get(\"sessionId\",\"\"), n.get(\"prUrl\",\"\"), (n.get(\"title\") or \"\")[:80]]))\nopen(sys.argv[1],\"a\").writelines(i+\"\\n\" for i in new)' \"$SEEN\"\n  tail -n 500 \"$SEEN\" > \"$SEEN.tmp\" && mv \"$SEEN.tmp\" \"$SEEN\"; }; f\n```\n- `ready_to_merge` comes from the unresolved list, so a PR that was merged or changed since drops off. For \"what's ready to merge\", list these with the PR link, and offer the merge (ao-actions; needs the user's yes per PR).\n- `review_completed`, `review_changes_requested`, `pr_merged`, `pr_closed_unmerged` are news. The command prints only news this bot hasn't reported before, and records it as reported, so each item appears once, in a status reply or in the digest, whichever comes first. Mention each in one line. For \"what's new again\" or \"show all news\", run it without the seen list.\n- Never use `needs_input` notifications. They can outlive the wait (the session answered or exited); section 1 is the source for what's waiting.\n\n## 3. One session in detail\nFor \"what is <session> doing\": find it (ask which host if the id is on two hosts), then read its last turn:\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions/<id>/history?offset=0&limit=1\" | python3 -c '\nimport json,sys\nt=(json.load(sys.stdin).get(\"turns\") or [{}])[0]\nprint(\"asked:\", (t.get(\"userRequest\") or \"\")[:500]); print(\"replied:\", (t.get(\"agentResponse\") or \"\")[-1500:])'; }; f\n```\nSummarise in two or three lines. For \"catch me up on <project>\", ask the project's orchestrator instead (ao-orchestrator). It has the workers' reports.\n\n## Digest\nThe **AO daily digest** routine runs this skill. Per host: what finished since the last digest (idle sessions with `lastEventAt` since then), what's waiting on the user, what's ready to merge, and anything exited unexpectedly. Skip quiet projects. Send nothing if nothing happened and nothing is waiting. Write the time of this digest to `~/.ao-grok/<host name>.last-digest` on `via` and read it next time, instead of keeping it in memory.\n","frontmatter":{"name":"ao-status","description":"What AO is doing on every host: which sessions are running, waiting on the user, idle or exited, which PRs are ready to merge or got a review, and a daily digest. Read-only. Use for \"status\", \"what's running\", \"what's waiting on me\", \"what's ready to merge\", \"anything stuck\", and the AO daily digest routine."},"isInternal":false,"tokens":1333,"sizeBytes":4854},{"name":"SKILL.md","path":"integrations/grok-bot/skills/ao-update/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-update/SKILL.md","title":"ao-update","category":"anthropic-skill","format":"markdown","content":"# ao-update\n\nPath: `integrations/grok-bot/skills/ao-update/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-update/SKILL.md)","tokens":300,"sizeBytes":216},{"name":"package.json","path":"packages/ao-darwin-arm64/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-arm64/package.json","title":"Ao-darwin-arm64 Skill","category":"anthropic-skill","format":"json","content":"# Ao-darwin-arm64 Skill\n\nPath: `packages/ao-darwin-arm64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-arm64/package.json)","tokens":300,"sizeBytes":208},{"name":"package.json","path":"packages/ao-darwin-x64/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-x64/package.json","title":"Ao-darwin-x64 Skill","category":"anthropic-skill","format":"json","content":"# Ao-darwin-x64 Skill\n\nPath: `packages/ao-darwin-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-x64/package.json)","tokens":300,"sizeBytes":202},{"name":"package.json","path":"packages/ao-linux-x64/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-linux-x64/package.json","title":"Ao-linux-x64 Skill","category":"anthropic-skill","format":"json","content":"# Ao-linux-x64 Skill\n\nPath: `packages/ao-linux-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-linux-x64/package.json)","tokens":300,"sizeBytes":199},{"name":"package.json","path":"packages/ao-win32-x64/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-win32-x64/package.json","title":"Ao-win32-x64 Skill","category":"anthropic-skill","format":"json","content":"# Ao-win32-x64 Skill\n\nPath: `packages/ao-win32-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-win32-x64/package.json)","tokens":300,"sizeBytes":199},{"name":"package.json","path":"packages/ao/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao/package.json","title":"Ao Skill","category":"anthropic-skill","format":"json","content":"# Ao Skill\n\nPath: `packages/ao/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao/package.json)","tokens":300,"sizeBytes":169},{"name":"package-lock.json","path":"packages/cloud-client/package-lock.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/package-lock.json","title":"Cloud-client Skill","category":"anthropic-skill","format":"json","content":"# Cloud-client Skill\n\nPath: `packages/cloud-client/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/package-lock.json)","tokens":300,"sizeBytes":209},{"name":"package.json","path":"packages/cloud-client/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/package.json","title":"Cloud-client Skill","category":"anthropic-skill","format":"json","content":"# Cloud-client Skill\n\nPath: `packages/cloud-client/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/package.json)","tokens":300,"sizeBytes":199},{"name":"tsconfig.json","path":"packages/cloud-client/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/tsconfig.json","title":"Cloud-client Skill","category":"anthropic-skill","format":"json","content":"# Cloud-client Skill\n\nPath: `packages/cloud-client/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/tsconfig.json)","tokens":300,"sizeBytes":201},{"name":"tsconfig.test.json","path":"packages/cloud-client/tsconfig.test.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/tsconfig.test.json","title":"Cloud-client Skill","category":"anthropic-skill","format":"json","content":"# Cloud-client Skill\n\nPath: `packages/cloud-client/tsconfig.test.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/tsconfig.test.json)","tokens":300,"sizeBytes":211},{"name":"app.json","path":"packages/mobile/app.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/app.json","title":"Mobile Skill","category":"anthropic-skill","format":"json","content":"# Mobile Skill\n\nPath: `packages/mobile/app.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/app.json)","tokens":300,"sizeBytes":173},{"name":"icon.json","path":"packages/mobile/assets/AO.icon/icon.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/assets/AO.icon/icon.json","title":"AO.icon Skill","category":"anthropic-skill","format":"json","content":"# AO.icon Skill\n\nPath: `packages/mobile/assets/AO.icon/icon.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/assets/AO.icon/icon.json)","tokens":300,"sizeBytes":206},{"name":"Contents.json","path":"packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json","title":"CircleDashedCheck.imageset Skill","category":"anthropic-skill","format":"json","content":"# CircleDashedCheck.imageset Skill\n\nPath: `packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/assets/icons/CircleDashedCheck.imageset/Contents.json)","tokens":300,"sizeBytes":283},{"name":"eas.json","path":"packages/mobile/eas.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/eas.json","title":"Mobile Skill","category":"anthropic-skill","format":"json","content":"# Mobile Skill\n\nPath: `packages/mobile/eas.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/eas.json)","tokens":300,"sizeBytes":173},{"name":"package.json","path":"packages/mobile/native/image-paste/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/native/image-paste/package.json","title":"Image-paste Skill","category":"anthropic-skill","format":"json","content":"# Image-paste Skill\n\nPath: `packages/mobile/native/image-paste/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/native/image-paste/package.json)","tokens":300,"sizeBytes":224},{"name":"package.json","path":"packages/mobile/native/response-selection/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/native/response-selection/package.json","title":"Response-selection Skill","category":"anthropic-skill","format":"json","content":"# Response-selection Skill\n\nPath: `packages/mobile/native/response-selection/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/native/response-selection/package.json)","tokens":300,"sizeBytes":245},{"name":"package-lock.json","path":"packages/mobile/package-lock.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/package-lock.json","title":"Mobile Skill","category":"anthropic-skill","format":"json","content":"# Mobile Skill\n\nPath: `packages/mobile/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/package-lock.json)","tokens":300,"sizeBytes":191},{"name":"package.json","path":"packages/mobile/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/package.json","title":"Mobile Skill","category":"anthropic-skill","format":"json","content":"# Mobile Skill\n\nPath: `packages/mobile/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/package.json)","tokens":300,"sizeBytes":181},{"name":"tsconfig.json","path":"packages/mobile/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/tsconfig.json","title":"Mobile Skill","category":"anthropic-skill","format":"json","content":"# Mobile Skill\n\nPath: `packages/mobile/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/tsconfig.json)","tokens":300,"sizeBytes":183},{"name":"package-lock.json","path":"packages/product-ui/package-lock.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/package-lock.json","title":"Product-ui Skill","category":"anthropic-skill","format":"json","content":"# Product-ui Skill\n\nPath: `packages/product-ui/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/package-lock.json)","tokens":300,"sizeBytes":203},{"name":"package.json","path":"packages/product-ui/package.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/package.json","title":"Product-ui Skill","category":"anthropic-skill","format":"json","content":"# Product-ui Skill\n\nPath: `packages/product-ui/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/package.json)","tokens":300,"sizeBytes":193},{"name":"tsconfig.build.json","path":"packages/product-ui/tsconfig.build.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/tsconfig.build.json","title":"Product-ui Skill","category":"anthropic-skill","format":"json","content":"# Product-ui Skill\n\nPath: `packages/product-ui/tsconfig.build.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/tsconfig.build.json)","tokens":300,"sizeBytes":207},{"name":"tsconfig.json","path":"packages/product-ui/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/tsconfig.json","title":"Product-ui Skill","category":"anthropic-skill","format":"json","content":"# Product-ui Skill\n\nPath: `packages/product-ui/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/tsconfig.json)","tokens":300,"sizeBytes":195},{"name":"push_fix_to_github.py","path":".claude/skills/bug-triage/scripts/push_fix_to_github.py","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.claude/skills/bug-triage/scripts/push_fix_to_github.py","title":"Claude Directive: push_fix_to_github.py","category":"claude-rule","format":"markdown","content":"# Claude Directive: push_fix_to_github.py\n\nPath: `.claude/skills/bug-triage/scripts/push_fix_to_github.py`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.claude/skills/bug-triage/scripts/push_fix_to_github.py)","tokens":300,"sizeBytes":262},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# Claude Agent Guidelines & System Prompt\n\nPath: `CLAUDE.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/CLAUDE.md)","tokens":300,"sizeBytes":170},{"name":"README.md","path":"packages/cloud-client/README.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/README.md","title":"cloud-client Documentation","category":"plugin-manifest","format":"markdown","content":"# cloud-client Documentation\n\nPath: `packages/cloud-client/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/cloud-client/README.md)","tokens":300,"sizeBytes":201},{"name":"README.md","path":"packages/mobile/README.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/README.md","title":"mobile Documentation","category":"plugin-manifest","format":"markdown","content":"# mobile Documentation\n\nPath: `packages/mobile/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/README.md)","tokens":300,"sizeBytes":183},{"name":"README.md","path":"packages/mobile/scripts/README.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/scripts/README.md","title":"scripts Documentation","category":"plugin-manifest","format":"markdown","content":"# scripts Documentation\n\nPath: `packages/mobile/scripts/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/mobile/scripts/README.md)","tokens":300,"sizeBytes":200},{"name":"README.md","path":"packages/product-ui/README.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/README.md","title":"product-ui Documentation","category":"plugin-manifest","format":"markdown","content":"# product-ui Documentation\n\nPath: `packages/product-ui/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/product-ui/README.md)","tokens":300,"sizeBytes":195},{"name":"automation.md","path":"backend/internal/skillassets/using-ao/commands/automation.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/automation.md","title":"Command: /automation","category":"command-prompt","format":"markdown","content":"# Command: /automation\n\nPath: `backend/internal/skillassets/using-ao/commands/automation.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/automation.md)","tokens":300,"sizeBytes":253},{"name":"browser-remote.md","path":"backend/internal/skillassets/using-ao/commands/browser-remote.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/browser-remote.md","title":"Command: /browser-remote","category":"command-prompt","format":"markdown","content":"# Command: /browser-remote\n\nPath: `backend/internal/skillassets/using-ao/commands/browser-remote.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/browser-remote.md)","tokens":300,"sizeBytes":265},{"name":"browser.md","path":"backend/internal/skillassets/using-ao/commands/browser.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/browser.md","title":"Command: /browser","category":"command-prompt","format":"markdown","content":"# Command: /browser\n\nPath: `backend/internal/skillassets/using-ao/commands/browser.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/browser.md)","tokens":300,"sizeBytes":244},{"name":"cua.md","path":"backend/internal/skillassets/using-ao/commands/cua.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/cua.md","title":"Command: /cua","category":"command-prompt","format":"markdown","content":"# Command: /cua\n\nPath: `backend/internal/skillassets/using-ao/commands/cua.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/cua.md)","tokens":300,"sizeBytes":232},{"name":"cue.md","path":"backend/internal/skillassets/using-ao/commands/cue.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/cue.md","title":"Command: /cue","category":"command-prompt","format":"markdown","content":"# Command: /cue\n\nPath: `backend/internal/skillassets/using-ao/commands/cue.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/cue.md)","tokens":300,"sizeBytes":232},{"name":"doctor.md","path":"backend/internal/skillassets/using-ao/commands/doctor.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/doctor.md","title":"Command: /doctor","category":"command-prompt","format":"markdown","content":"# Command: /doctor\n\nPath: `backend/internal/skillassets/using-ao/commands/doctor.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/doctor.md)","tokens":300,"sizeBytes":241},{"name":"import.md","path":"backend/internal/skillassets/using-ao/commands/import.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/import.md","title":"Command: /import","category":"command-prompt","format":"markdown","content":"# Command: /import\n\nPath: `backend/internal/skillassets/using-ao/commands/import.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/import.md)","tokens":300,"sizeBytes":241},{"name":"orchestrator.md","path":"backend/internal/skillassets/using-ao/commands/orchestrator.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/orchestrator.md","title":"Command: /orchestrator","category":"command-prompt","format":"markdown","content":"# Command: /orchestrator\n\nPath: `backend/internal/skillassets/using-ao/commands/orchestrator.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/orchestrator.md)","tokens":300,"sizeBytes":259},{"name":"preview.md","path":"backend/internal/skillassets/using-ao/commands/preview.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/preview.md","title":"Command: /preview","category":"command-prompt","format":"markdown","content":"# Command: /preview\n\nPath: `backend/internal/skillassets/using-ao/commands/preview.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/preview.md)","tokens":300,"sizeBytes":244},{"name":"project.md","path":"backend/internal/skillassets/using-ao/commands/project.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/project.md","title":"Command: /project","category":"command-prompt","format":"markdown","content":"# Command: /project\n\nPath: `backend/internal/skillassets/using-ao/commands/project.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/project.md)","tokens":300,"sizeBytes":244},{"name":"remote-host.md","path":"backend/internal/skillassets/using-ao/commands/remote-host.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/remote-host.md","title":"Command: /remote-host","category":"command-prompt","format":"markdown","content":"# Command: /remote-host\n\nPath: `backend/internal/skillassets/using-ao/commands/remote-host.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/remote-host.md)","tokens":300,"sizeBytes":256},{"name":"render.md","path":"backend/internal/skillassets/using-ao/commands/render.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/render.md","title":"Command: /render","category":"command-prompt","format":"markdown","content":"# Command: /render\n\nPath: `backend/internal/skillassets/using-ao/commands/render.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/render.md)","tokens":300,"sizeBytes":241},{"name":"report.md","path":"backend/internal/skillassets/using-ao/commands/report.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/report.md","title":"Command: /report","category":"command-prompt","format":"markdown","content":"# Command: /report\n\nPath: `backend/internal/skillassets/using-ao/commands/report.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/report.md)","tokens":300,"sizeBytes":241},{"name":"review.md","path":"backend/internal/skillassets/using-ao/commands/review.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/review.md","title":"Command: /review","category":"command-prompt","format":"markdown","content":"# Command: /review\n\nPath: `backend/internal/skillassets/using-ao/commands/review.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/review.md)","tokens":300,"sizeBytes":241},{"name":"send.md","path":"backend/internal/skillassets/using-ao/commands/send.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/send.md","title":"Command: /send","category":"command-prompt","format":"markdown","content":"# Command: /send\n\nPath: `backend/internal/skillassets/using-ao/commands/send.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/send.md)","tokens":300,"sizeBytes":235},{"name":"session.md","path":"backend/internal/skillassets/using-ao/commands/session.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/session.md","title":"Command: /session","category":"command-prompt","format":"markdown","content":"# Command: /session\n\nPath: `backend/internal/skillassets/using-ao/commands/session.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/session.md)","tokens":300,"sizeBytes":244},{"name":"spawn.md","path":"backend/internal/skillassets/using-ao/commands/spawn.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/spawn.md","title":"Command: /spawn","category":"command-prompt","format":"markdown","content":"# Command: /spawn\n\nPath: `backend/internal/skillassets/using-ao/commands/spawn.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/spawn.md)","tokens":300,"sizeBytes":238},{"name":"start.md","path":"backend/internal/skillassets/using-ao/commands/start.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/start.md","title":"Command: /start","category":"command-prompt","format":"markdown","content":"# Command: /start\n\nPath: `backend/internal/skillassets/using-ao/commands/start.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/start.md)","tokens":300,"sizeBytes":238},{"name":"status.md","path":"backend/internal/skillassets/using-ao/commands/status.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/status.md","title":"Command: /status","category":"command-prompt","format":"markdown","content":"# Command: /status\n\nPath: `backend/internal/skillassets/using-ao/commands/status.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/status.md)","tokens":300,"sizeBytes":241},{"name":"stop.md","path":"backend/internal/skillassets/using-ao/commands/stop.md","rawUrl":"https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/stop.md","title":"Command: /stop","category":"command-prompt","format":"markdown","content":"# Command: /stop\n\nPath: `backend/internal/skillassets/using-ao/commands/stop.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/backend/internal/skillassets/using-ao/commands/stop.md)","tokens":300,"sizeBytes":235}],"systemPromptSnippet":"<yakaai_skills repo=\"ComposioHQ/agent-orchestrator\">\n<!-- File: AGENTS.md (Tokens: ~300 | Category: root-instruction) -->\n# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/AGENTS.md)\n\n<!-- File: DESIGN.md (Tokens: ~300 | Category: project-spec) -->\n# UI Design System & Style Tokens\n\nPath: `DESIGN.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/DESIGN.md)\n\n<!-- File: docs/architecture.md (Tokens: ~300 | Category: project-spec) -->\n# docs - System Architecture & Module Boundaries\n\nPath: `docs/architecture.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/docs/architecture.md)\n\n<!-- File: .agents/skills/ao-desktop-dev/agents/openai.yaml (Tokens: ~300 | Category: anthropic-skill) -->\n# Agents Skill\n\nPath: `.agents/skills/ao-desktop-dev/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/.agents/skills/ao-desktop-dev/agents/openai.yaml)\n\n<!-- File: .agents/skills/ao-desktop-dev/SKILL.md (Tokens: ~2089 | Category: anthropic-skill) -->\n---\nname: ao-desktop-dev\ndescription: Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data.\n---\n\n# AO Desktop Dev\n\nRun the Electron application from the current checkout and verify it in the native window. Keep the dev daemon, renderer, Electron preload, and selected data mode explicit so the user never reviews a mock or stale build by accident.\n\n## Choose the data mode\n\nAsk only when the request does not make the desired data source clear.\n\n- Use **isolated mode** by default for implementation and destructive testing. Electron uses port `3002`, `~/.ao/dev/running.json`, `~/.ao/dev/data`, and `~/.ao/dev/electron`.\n- Use **real-data mode** only when the user explicitly asks to see this machine's actual AO projects or sessions. Start the checkout's dev daemon on the isolated dev port/run file while pointing `AO_DATA_DIR` at the real AO data directory. This is a separate daemon process using real data; do not describe it as the installed app's daemon.\n- Never try to attach an unpackaged Electron app directly to a packaged daemon from another checkout. The supervisor intentionally rejects daemon identity mismatches.\n- Warn before actions in real-data mode that create, terminate, rename, or otherwise mutate sessions. Merely opening and inspecting the UI is expected.\n- Real-data mode reads the same database as the installed app, and only one daemon can own a data directory. Quit the packaged app first: while its daemon runs, the dev daemon waits for the data-dir lock (9 x `AO_SHUTDOWN_TIMEOUT` + 18s, 108s by default) and then exits with code 75. The dev window is marked with an `Agent Orchestrator (dev)` title, an orange-badged `DEV` dock icon, and an in-app `dev` badge — verify those markers before acting.\n\n## Preflight\n\n1. Work from the repository root and inspect `git status --short --branch`.\n2. Read `frontend/package.json`, `frontend/src/main.ts`, and `frontend/forge.config.ts` when the launch behavior may have changed. Treat source as authoritative over this skill.\n3. Confirm Node/npm and the Go version required by `backend/go.mod` are available. Run `npm ci` in `frontend/` only when dependencies are absent or inconsistent; do not reinstall on every launch.\n4. Check for an existing dev instance from this exact checkout before starting another. Do not kill by process name alone, and never terminate every Electron process.\n\nOn macOS/Linux, inspect checkout-scoped processes and listeners with finite commands:\n\n```bash\nps -axo pid=,ppid=,pgid=,lstart=,command= | rg 'frontend/(node_modules/.bin/electron-forge|node_modules/electron/dist/Electron)'\nlsof -nP -iTCP:3002 -sTCP:LISTEN\n```\n\nUse the full command paths and start times to distinguish this checkout from other AO worktrees. On Windows, use `Get-CimInstance Win32_Process` and `Get-NetTCPConnection`; preserve the same exact-target rule.\n\n## Launch the app\n\nRun Electron Forge in a foreground interactive process so its output and restart input remain available. Do not append `&`, use a detached shell, or start a browser preview instead.\n\n### Isolated mode\n\nOn macOS/Linux:\n\n```bash\ncd frontend\nenv -u AO_DATA_DIR -u AO_RUN_FILE -u AO_PORT npm run dev\n```\n\nOn PowerShell:\n\n```powershell\nSet-Location frontend\nRemove-Item Env:AO_DATA_DIR, Env:AO_RUN_FILE, Env:AO_PORT -ErrorAction SilentlyContinue\nnpm run dev\n```\n\n### Real-data mode\n\nFirst resolve and report the actual data directory. In an AO worker session, `AO_DATA_DIR` normally already identifies it. Otherwise the repository default is the absolute path corresponding to `~/.ao/data`.\n\nKeep the real data directory but remove inherited port/run-file overrides so the dev app retains its own daemon handshake and port:\n\n```bash\ncd frontend\nenv -u AO_RUN_FILE -u AO_PORT AO_DATA_DIR=\"${AO_DATA_DIR:-$HOME/.ao/data}\" npm run dev\n```\n\nPowerShell equivalent:\n\n```powershell\nSet-Location frontend\n$realAoData = if ($env:AO_DATA_DIR) { $env:AO_DATA_DIR } else { Join-Path $HOME \".ao/data\" }\nRemove-Item Env:AO_RUN_FILE, Env:AO_PORT -ErrorAction SilentlyContinue\n$env:AO_DATA_DIR = $realAoData\nnpm run dev\n```\n\nDo not print unrelated environment variables: AO sessions may carry credentials. It is safe to report only `AO_DATA_DIR`, `AO_RUN_FILE`, and `AO_PORT`.\n\n## Confirm the correct app is ready\n\nWait for all of these signals:\n\n- Electron Forge reports `Launched Electron app`.\n- The daemon reports `daemon listening`, normally on `127.0.0.1:3002` unless it explicitly reports another bound port.\n- The renderer makes successful requests such as `/api/v1/projects` and `/api/v1/sessions`.\n- The native Electron window shows the checkout's UI. A Vite URL opened in a normal browser is not equivalent because it lacks the Electron preload bridge.\n\nIf several AO windows exist, identify the newest Electron main process belonging to this checkout. On macOS, foreground that exact PID only when needed:\n\n```bash\nosascript -e 'tell application \"System Events\" to set frontmost of first process whose unix id is <verified-pid> to true'\n```\n\nDo not claim real data from appearance alone. Verify the selected data directory and successful API responses. Do not claim visual success from compilation alone; interact with the requested flow in Electron or ask the user for a screenshot when screen capture is unavailable.\n\n## Reload changes correctly\n\n- Renderer-only React/CSS changes normally hot reload.\n- Changes to `frontend/src/main.ts`, preload files, Forge configuration, shared bridge types, or IPC registration require an Electron main-process restart. Type `rs` into the active Forge terminal or fully stop and relaunch the dev process.\n- A renderer error such as `aoBridge.<method> is not a function` almost always means the renderer hot-reloaded against a stale preload. Restart Electron before changing code to add guards around a bridge method that should exist.\n- Backend changes require restarting the managed dev daemon or the Electron process; renderer hot reload cannot apply Go changes.\n\nAfter a restart, confirm the new Electron PID/start time and re-check the logs for the original error.\n\n## Preview multiple PRs locally\n\nWhen the user wants to see multiple unmerged PRs together:\n\n1. Require a clean worktree and fetch each PR head.\n2. Create a clearly named local-only integration branch using the session/repository branch convention.\n3. Merge or cherry-pick the requested PR heads without rewriting or pushing either source branch.\n4. Resolve overlaps according to the requested combined behavior and run focused typechecks/tests.\n5. Let renderer changes hot reload; restart Electron if either PR changes main/preload/IPC code.\n6. State that the integration branch is local-only. Do not push it unless the user explicitly requests a combined PR.\n\nOnce one PR merges, prefer rebasing the remaining PR onto current `main`; the normal PR branch then contains both views without a local integration merge.\n\n## Stop without collateral damage\n\n1. Send Ctrl+C to the foreground dev process and wait briefly for Electron and its managed daemon to exit.\n2. Re-run the checkout-scoped process query. If the exact process group remains, identify the group created by this launch before sending `TERM` to that group.\n3. On Windows, terminate the verified parent tree only. Never use a broad Electron, Node, Go, or port-based kill.\n4. Confirm the captured Electron PID and dev daemon listener are gone. Leave installed AO and other worktrees untouched.\n\n## Common mistakes\n\n- `ao preview` controls the AO Browser panel; it does not launch the desktop shell.\n- `npm run dev:web` is useful for browser-only renderer work but does not provide Electron APIs or native chrome.\n- Renderer URLs can move from `5173` when a port is occupied. Trust Forge's printed URL rather than assuming one.\n- Multiple dev instances share `~/.ao/dev/electron` by default, and Chromium's\n  singleton lock lives in the profile, so a second checkout's `npm run dev`\n  loses `requestSingleInstanceLock()` and exits immediately with code 0. To run\n  two worktrees at once, give each its own profile, run file, and data dir:\n\n  ```bash\n  env -u AO_PORT \\\n    AO_DEV_ELECTRON_DIR=\"$HOME/.ao/dev/<name>/electron\" \\\n    AO_RUN_FILE=\"$HOME/.ao/dev/<name>/running.json\" \\\n    AO_DATA_DIR=\"$HOME/.ao/dev/<name>/data\" \\\n    npm run dev\n  ```\n\n  Without all three the instances still collide, on the profile lock, the run\n  file, or the daemon's SQLite data.\n- An inherited `AO_DATA_DIR` changes dev mode from isolated data to real data. Always choose and report the mode instead of inheriting it accidentally.\n- Repeated `/healthz/` 404 entries from external probes can be noisy; readiness is determined by Electron's daemon status and successful API traffic, not by log volume.\n\n## Completion report\n\nReport:\n\n- checkout and branch being displayed;\n- isolated or real-data mode and the non-sensitive data/run-file paths;\n- renderer and daemon addresses actually reported;\n- whether Electron was restarted for main/preload changes;\n- user flows exercised in the native window;\n- any remaining stale process, port, or visual-verification limitation.\n\n<!-- File: .agents/skills/bug-triage/SKILL.md (Tokens: ~1855 | Category: anthropic-skill) -->\n---\nname: bug-triage\ndescription: Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft.\n---\n\n# Bug triage\n\nHelp the reporter describe what they observed and add useful evidence. A short human\nobservation is enough to report a bug; reproduction, logs, and a diagnosis are optional.\nUse this skill for reports from chat, an existing issue, or a local user.\n\n## Clarify the observation\n\nRead the available report, screenshots, and follow-ups first. Preserve the original\nreporter's words and attribution, including when someone else relays their report.\nDon't infer a GitHub username from a chat display name.\n\nAsk only questions that would materially clarify the symptom, a few at a time. Don't\nrepeat questions already answered or turn these suggestions into required fields:\n\n- What did you do, and what happened instead of what you expected?\n- Where did it happen, and does it happen every time or only sometimes?\n- For a visual problem, can you share a screenshot or short recording showing it?\n- If relevant, which AO version and OS were you using, and did it start after a change?\n\nIf a screenshot is unavailable, accept a description. If the reporter cannot remember\nsteps or reproduce the problem, preserve that uncertainty and proceed with what is\nknown. Never invent steps or make the reporter diagnose the bug before accepting it.\n\n## Keep the report and investigation separate\n\nDraft a specific symptom-based title and a short body, normally one paragraph or a few\nbullets. Include only details supplied directly by the human: their observation,\nexpected behavior, steps, frequency, environment, and impact when they provided them.\nLight editing for clarity is fine; preserve meaning and uncertainty. Omit empty\nsections and unnecessary background. Do not add agent-inferred impact, root cause,\nconfidence scores, or proposed fixes to the report.\n\nExample human report:\n\n> After I switched projects, the terminal stayed blank. I expected to see the session\n> prompt. It happened twice today on macOS; I don't know how to reproduce it reliably.\n\nKeep agent-discovered information separate from the human report and label it\n**Agent-collected evidence**, even when it confirms the report. Include only relevant\nexcerpts and:\n\n- The command or read-only query used, collection time, and relevant AO version or\n  checkout commit, so another person can interpret the result.\n- Observed output, screenshots, or reproduction results, with enough context to verify\n  the finding. Distinguish the reporter's environment from a separate test build.\n- A brief explanation of what the evidence supports and its limits. Label hypotheses\n  explicitly; don't present a code-path guess as a confirmed cause.\n\nIf no useful evidence is available, deliver the human report alone. Never pad it with\nspeculation or claim a reproduction succeeded when it didn't.\n\n## Gather relevant evidence\n\nUse diagnostics that fit the symptom, within the user's requested scope. Prefer\nread-only checks against the affected installation. Don't restart sessions, upgrade\nAO, change live data, or alter the user's checkout just to collect evidence.\n\nAO uses a Go daemon and an Electron/React frontend. Read `docs/architecture.md` for\ncurrent boundaries and locate actual files with `rg` before citing code. Do not rely\non the old TypeScript implementation or assume which runtime backs a session.\n\nBefore trusting diagnostics, identify the AO executable and affected daemon. A PATH\nlookup may resolve to a legacy install. Check the executable's version and status,\nand the configured run file/data directory (`AO_RUN_FILE` / `AO_DATA_DIR` when set).\nThe primary daemon normally uses loopback port 3001; port alone does not establish\nwhich version or installation is affected. Consult the installed CLI help for commands.\n\nFor local-daemon evidence, use the affected binary's `--version` and `status --json`;\nstatus reads existing state without starting the daemon. For a known affected session,\nuse `session get <id> --json` and keep only fields relevant to the symptom. If the\ndaemon is unavailable, record its status or error and mark session evidence unavailable.\n\nRecord app and CLI versions separately from daemon identity. Health probes provide no\ndaemon release version; `dev` alone or missing build metadata does not identify the\nsource. Label source findings approximate when the affected build cannot be matched.\n\nDo not run `doctor` or `agent ls` as routine evidence collectors: doctor writes files\nand checks remote authentication; agent listing triggers readiness checks.\n`remote-host status` can print the pairing password. Desktop status refresh may start\na replacement daemon; prefer the CLI status check or already available evidence.\n\nCollect only what helps explain this symptom:\n\n| Symptom | Potential evidence |\n| --- | --- |\n| UI rendering or interaction | Screenshot/recording, relevant console errors, affected view |\n| Session or terminal state | Affected session's daemon state, relevant log excerpt, runtime details |\n| Daemon or CLI failure | Version/status, exact command and error, relevant daemon logs |\n| Persisted state mismatch | Relevant rows and schema from a read-only SQLite query |\n\nLocate logs for the affected process rather than assuming `~/.ao/daemon.log` is current.\nDaemon output goes to stderr and may not persist; that file mostly covers keep-alive\nlaunches. Record missing evidence instead of enabling logging just to create it.\n\nUse the daemon API/CLI for state first. If database evidence is needed, discover the\nactual database location and schema, open it read-only, and select only relevant rows\nand columns. Never attach an entire database, broad log dump, or Electron profile\nfolder, which also holds browser cookies and storage. Redact tokens,\ncredentials, private prompts, and unrelated personal or repository data from every\nartifact, including screenshots. Keep diagnostic artifacts under `~/.ao` and out of\nGit commits. Preserve evidentiary content when redacting, and verify that unrelated\ncontent did not change. Share a useful excerpt rather than a wall of output.\n\nThe report form's sanitizer masks known patterns only; review the exact draft and\nartifacts before sharing.\n\nTry a safe reproduction when practical, recording the build actually tested. Failure\nto reproduce does not invalidate the human report. Code tracing or dependency research\nis optional when it can add concrete evidence. Keep findings in the separate evidence.\n\n## Check for duplicates\n\nResolve AO's canonical repository name before searching. GitHub issue and PR searches\ncan return empty results for a former owner even when repository API requests redirect.\nUse the resolved name, not the reporter's project repository. Search open and closed\nissues and related PRs using the symptom or exact error:\n\n```bash\nif ao_triage_repo=$(gh api repos/OrchestratorInc/agent-orchestrator --jq .full_name) && [ -n \"$ao_triage_repo\" ]; then\n  gh issue list --repo \"$ao_triage_repo\" --state all --search '<symptom or error>' --limit 100\n  gh pr list --repo \"$ao_triage_repo\" --state all --search '<symptom or error>' --limit 100\nelse\n  printf '%s\\n' 'Repository lookup failed; duplicate search skipped.' >&2\nfi\n```\n\nInclude the searched repository and candidates considered in the separate evidence.\nTry useful symptom synonyms or a shorter error fragment when needed.\n\nRead likely matches before calling a report a duplicate. If one matches, give the\nreporter its link and draft only their new observation for a comment, with evidence\nattached separately. If a closed issue appears to have regressed, explain that to the\nreporter rather than silently treating it as resolved. If repository lookup or either\nsearch fails or is unavailable, say which part could not be checked. Empty, truncated,\nor failed searches do not prove there is no duplicate; continue preparing the report.\n\n## Preserve attribution and submission scope\n\nA local coding agent may help draft and gather attachments. Existing authorization\nstill applies; triage alone is not permission to publish.\n\nFor an existing issue, preserve its human body and attribution. Add evidence separately\nwhen authorized. Don't rewrite the report into an investigation narrative.\n\nWhen authorized to publish, include useful collected evidence before finishing. Use a\nclearly labeled comment or attachment, whichever fits the evidence. If evidence cannot\nbe published, state the exact blocker and provide its local path. Never invent\nattachment URLs or create asset branches to host diagnostics. Keep the report body\nlimited to human details. Apply only existing, relevant labels; don't add\npriority/confidence prose just to fill a template.\n\nFinish with the concise draft (or issue link if submitted), any duplicate link, and\nattachment paths/links. Do not automatically file an issue, implement a fix, push a\nPR, or spawn a worker. Follow the user's requested scope and the repository's normal\ncontribution workflow if they separately ask for implementation.\n\nThe bundled `scripts/push_fix_to_github.py` is a legacy fix publisher, not a triage step.\n\n<!-- File: .agents/skills/pr-description/SKILL.md (Tokens: ~745 | Category: anthropic-skill) -->\n---\nname: pr-description\ndescription: Write and maintain pull request descriptions in this repository, including the required change-count header, the before-and-after section, and screenshots or recordings for visible changes.\n---\n\n# PR description\n\nUse the section order in `.github/pull_request_template.md`: change-count header,\nWhat, Why, Before / After, How, Testing, Checklist. Preserve the rest of an existing\nPR description when updating it.\n\n## Change-count header\n\nBegin every PR description with these three lines, using Markdown hard line breaks\nso each renders separately:\n\n```text\nCode changes: +<added> -<deleted>\nTests: +<added> -<deleted>\nOthers: +<added> -<deleted>\n```\n\nCalculate the numbers from the net diff against the PR's actual base. For a local\nbranch, use `git diff --numstat <base>...<head>`. After pushing, prefer GitHub's\nper-file additions and deletions. Recalculate after the final push rather than\nsumming commit churn or estimating counts.\n\nCount every changed file exactly once:\n\n- **Code changes:** handwritten implementation, including SQL, migrations, styles,\n  and executable scripts.\n- **Tests:** test code, fixtures, snapshots, and test-only helpers.\n- **Others:** generated or vendored files, lockfiles, documentation, configuration,\n  and assets. Generated output belongs here even when it contains source code.\n\nShow `+0 -0` for empty categories. Binary files have no line count; mention their\ncount separately when present. Add a brief qualifier when useful, such as\n`Others: +11 -0 (generated sqlc)`.\n\n## Before / After\n\nEvery PR has a `## Before / After` section with a two-column table, one row per\nbehavior that changed:\n\n```markdown\n| Before | After |\n| --- | --- |\n| ![Before: empty model list](before.png) | ![After: list filtered to six models](after.png) |\n| `ao session ls` exits 1 when a project has no sessions | Prints `No sessions` and exits 0 |\n```\n\n- **UI changes** need a screenshot of each changed state, before and after. Use a\n  short recording for flows, animations, focus or keyboard behavior, and timing.\n- **Non-visual changes** compare observable behavior: command output, API\n  responses, errors, logs, or measured numbers with their units.\n- **No user-visible change:** write `No user-visible change` and one line saying why,\n  such as an internal refactor or a test-only change.\n\nCapture both sides from the real app with the same screen, window size, and data,\nso they compare directly. Take the before capture from the PR's base branch. The\n`ao-desktop-dev` skill launches the desktop app from a checkout.\n\nScreenshots and GIFs go in the table. GitHub renders a video player only for a\nbare attachment URL on its own line, so put MP4 or MOV recordings on their own\nline below the table, with one line saying what they show.\n\nNever commit screenshots or recordings to the repository. Attach them in the PR\ndescription, or in a PR comment when the description gets long. If you cannot\nupload, give the capture file paths to the person who will attach them. Remove\nsecrets, tokens, and personal data from every capture.\n\n## Verify\n\nAfter creating or updating the PR, read the published description and verify that:\n\n- its opening lines match the current GitHub diff counts and required order;\n- every image and recording in Before / After, or in a PR comment, loads.\n\n<!-- File: .claude/skills/ao-desktop-dev/SKILL.md (Tokens: ~153 | Category: anthropic-skill) -->\n---\nname: ao-desktop-dev\ndescription: Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real local AO data; combine PR branches for local UI review; and diagnose stale Electron processes, port conflicts, or preload bridge mismatches. Use whenever asked to run, open, show, or visually verify AO frontend changes in the actual desktop app rather than ao preview, dev:web, or mock data.\n---\n\n# AO Desktop Dev\n\nRead and follow [`../../../.agents/skills/ao-desktop-dev/SKILL.md`](../../../.agents/skills/ao-desktop-dev/SKILL.md) completely before launching or troubleshooting the desktop app. That file is the canonical cross-agent workflow for this repository.\n\n<!-- File: .claude/skills/bug-triage/SKILL.md (Tokens: ~91 | Category: anthropic-skill) -->\n---\nname: bug-triage\ndescription: Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft.\n---\n\n# Bug triage\n\nRead and follow [`../../../.agents/skills/bug-triage/SKILL.md`](../../../.agents/skills/bug-triage/SKILL.md) completely before clarifying, drafting, or filing anything. That file is the canonical cross-agent workflow for this repository.\n\n<!-- File: backend/internal/skillassets/using-ao/SKILL.md (Tokens: ~1376 | Category: anthropic-skill) -->\n---\nname: using-ao\ndescription: \"Catalog of the AO (Agent Orchestrator) `ao` CLI: spawning workers, managing sessions and projects, creating reusable Cues, sending messages, controlling the shared browser, previewing pages, and daemon control. Use when using the ao CLI, creating Cues, spawning workers, or managing AO sessions in an AO workspace.\"\ntrigger: \"Using the ao CLI in an AO workspace: creating Cues, spawning workers, managing sessions/projects, sending messages, controlling or previewing pages.\"\n---\n\n# AO CLI Catalog\n\n`ao` is a thin CLI over the local AO daemon. Every command is `ao <command> --help` for the authoritative flag list.\n\n| Command | What it does | When to use | Details |\n|---|---|---|---|\n| `spawn` | Spawn a project worker, orchestrator, or projectless standalone worker | Starting a new task or issue | [commands/spawn.md](commands/spawn.md) |\n| `session` | Manage agent sessions (list, kill, rename, restore, history, etc.) | Inspecting or controlling running/terminated sessions, or reading the full conversation after taking over from another agent | [commands/session.md](commands/session.md) |\n| `agent` | Inspect installed harnesses and launch readiness | Choosing or diagnosing an agent harness | `ao agent ls --refresh` |\n| `pr` | Merge a PR or resolve its review threads | Completing a reviewed change | `ao pr merge` / `ao pr resolve-comments` |\n| `project` | Register, inspect, configure, or remove projects | Setting up or managing repos AO knows about | [commands/project.md](commands/project.md) |\n| `automation` | Manage durable recurring session automations | Creating, editing, disabling, deleting, and inspecting scheduled runs | [commands/automation.md](commands/automation.md) |\n| `cue` | Create or list reusable project Cues | Saving a repetitive command or agent task at the user's request | [commands/cue.md](commands/cue.md) |\n| `orchestrator` | List orchestrator sessions | Viewing which sessions are orchestrators | [commands/orchestrator.md](commands/orchestrator.md) |\n| `review` | Start, list, cancel, or submit AO's native reviewer for a worker's PR (default: this session) | Reviewing implementation PRs owned by AO workers. Use a normal review-only worker for someone else's PR | [commands/review.md](commands/review.md) |\n| `send` | Send a message to a running agent session | Messaging a live agent; use `--steer` to correct it mid-turn | [commands/send.md](commands/send.md) |\n| `report` | Persist a meaningful worker report | Checkpoints, blockers, decisions, outputs, and completion | [commands/report.md](commands/report.md) |\n| `preview` | Start a session-owned app or open an exact URL/file | Running and showing the worker's relevant app, Markdown, HTML, PDF, or image | [commands/preview.md](commands/preview.md) |\n| `render` | Show a self-contained HTML page inline in a chat thread | Answering with a chart, table, diagram, or mockup | [commands/render.md](commands/render.md) |\n| `browser` | Inspect and control the session's shared live browser | Verifying a web app through snapshots, interactions, waits, screenshots, console, and errors | [commands/browser.md](commands/browser.md) |\n| `browser` (remote host) | Drive the host's shared remote Chromium, used when `AO_AGENT_BROWSER_URL` is set | Same browser verification on a self-hosted remote host; one browser is shared across sessions | [commands/browser-remote.md](commands/browser-remote.md) |\n| `remote-host` | Link this machine to the user's AO account, or turn its remote access on or off | Setting up a VM or other headless machine so the user's desktops and phones can use it | [commands/remote-host.md](commands/remote-host.md) |\n| `start` | Fetch (if needed) and open the AO desktop app | Launching the app | [commands/start.md](commands/start.md) |\n| `stop` | Stop the AO daemon | Shutting down AO | [commands/stop.md](commands/stop.md) |\n| `status` | Show daemon status | Verifying the daemon is up and healthy | [commands/status.md](commands/status.md) |\n| `doctor` | Run local health checks | Diagnosing AO setup problems | [commands/doctor.md](commands/doctor.md) |\n| `import` | Import projects from a legacy AO install | Migrating from the old flat-file store | [commands/import.md](commands/import.md) |\n| `version` | Print version information | Checking installed version | - |\n| `completion` | Generate shell completion scripts | Setting up tab completion | - |\n\n## Conventions\n\n- Most read commands accept `--json` for machine-readable output.\n- `-p / --project` scopes session subcommand lookups to one project.\n- Session and project ids are shown by `ao session ls` and `ao project ls`.\n- To refer to a session in AO Chat or the AO terminal, use the canonical in-app\n  link `ao://sessions/{project-id}/{session-id}`. Read\n  [commands/session.md](commands/session.md) for identity, encoding, and safety\n  rules before constructing one.\n- When the user asks to save a repeatable task as a Cue, use `ao cue list --json` to check existing definitions, then `ao cue create`. An agent Cue stores a reusable instruction; a command Cue stores an exact shell command. This agent-facing command can create and read Cues, but cannot edit or delete them. Direct the user to project settings for changes to existing Cues.\n- `--agent` is an alias for `--harness` on `ao spawn`.\n- Every command accepts `-h / --help` for the full flag list.\n- For frontend launch, preview selection, or artifact handoff, read\n  [commands/preview.md](commands/preview.md) before acting. Its static-file,\n  project-runtime, and automatic-handoff rules are load-bearing.\n- For page inspection, interaction, or request diagnosis, read\n  [commands/browser.md](commands/browser.md). It defines shared-tab behavior\n  and the opt-in network policy.\n\nUse [references.md](references.md) only when a natural-language request does\nnot map clearly to a command above.\n\n<!-- File: frontend/src/docs/content/plugins/agents/meta.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Agents Skill\n\nPath: `frontend/src/docs/content/plugins/agents/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/agents/meta.json)\n\n<!-- File: frontend/src/docs/content/plugins/meta.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Plugins Skill\n\nPath: `frontend/src/docs/content/plugins/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/meta.json)\n\n<!-- File: frontend/src/docs/content/plugins/notifiers/meta.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Notifiers Skill\n\nPath: `frontend/src/docs/content/plugins/notifiers/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/notifiers/meta.json)\n\n<!-- File: frontend/src/docs/content/plugins/runtimes/meta.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Runtimes Skill\n\nPath: `frontend/src/docs/content/plugins/runtimes/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/runtimes/meta.json)\n\n<!-- File: frontend/src/docs/content/plugins/scm/meta.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Scm Skill\n\nPath: `frontend/src/docs/content/plugins/scm/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/scm/meta.json)\n\n<!-- File: frontend/src/docs/content/plugins/terminals/meta.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Terminals Skill\n\nPath: `frontend/src/docs/content/plugins/terminals/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/terminals/meta.json)\n\n<!-- File: frontend/src/docs/content/plugins/trackers/meta.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Trackers Skill\n\nPath: `frontend/src/docs/content/plugins/trackers/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/trackers/meta.json)\n\n<!-- File: frontend/src/docs/content/plugins/workspaces/meta.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Workspaces Skill\n\nPath: `frontend/src/docs/content/plugins/workspaces/meta.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/frontend/src/docs/content/plugins/workspaces/meta.json)\n\n<!-- File: integrations/grok-bot/skills/ao-actions/SKILL.md (Tokens: ~1197 | Category: anthropic-skill) -->\n---\nname: ao-actions\ndescription: >-\n  Direct actions on one AO session or PR: stop or interrupt, resume, merge a PR,\n  start a review, screenshot a session's browser, send a session's files, keep\n  a host awake, and recurring AO automations. Use for \"stop <session>\",\n  \"merge <PR>\", \"review <session>'s PR\", \"show me what <session> built\",\n  \"keep the Mac awake tonight\", \"every night, ...\".\n---\nFollow the ao-rules skill. Find the session first (ao-rules \"AO hosts\": `<host>/<session id>`). Run each action on the owner host from its `via` computer. \"Yes\" means the user's yes for that exact action in this chat.\n\n| Ask | Do | Yes needed | Hosts |\n|---|---|---|---|\n| Stop what it's doing now | `aoapi POST \"sessions/<id>/conversation/interrupt\"` | No | All |\n| End the session | `aoapi POST \"sessions/<id>/kill\" '{}'` | Yes | All |\n| Resume an exited agent | `aoapi POST \"sessions/<id>/resume-agent\" '{}'` | No | All |\n| Restore an ended session | `aoapi POST \"sessions/<id>/restore\" '{}'` (an ended orchestrator can't come back while its project has another live one) | Yes | All |\n| Merge a PR | see \"Merge\" | Yes, per PR | All |\n| Start AO's reviewer on a session's PR | `ao review trigger <id>` | Yes | Local |\n| Screenshot a session's browser | see \"Screenshot\" | No | Local |\n| A session's files | see \"Files\" | No | Local |\n| Keep the host awake | see \"Keep awake\" | Yes | Local |\n| Recurring agent work | see \"Automations\" | Yes | Local |\n| Start one worker directly | `aoapi POST sessions '<json>'` with `projectId`, `displayName`, `prompt` | Yes | All |\n\nFor an action marked Local on a remote host, ask that host's orchestrator to do it (ao-orchestrator).\n\nStart a worker directly only when the project has no orchestrator and the user doesn't want one (ao-rules \"orchestrator first\").\n\n## Merge\nFirst show the PR and ask:\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions/<session id>/pr\" | python3 -c '\nimport json,sys\nfor p in json.load(sys.stdin).get(\"prs\") or []:\n    if str(p.get(\"number\"))==sys.argv[1]: print(json.dumps({\"url\":p.get(\"url\"),\"headSha\":p.get(\"headSha\"),\"state\":p.get(\"state\"),\n        \"ci\":(p.get(\"ci\") or {}).get(\"state\"),\"review\":(p.get(\"review\") or {}).get(\"decision\"),\"mergeability\":(p.get(\"mergeability\") or {}).get(\"state\")}))' '<pr number>'; }; f\n```\nTell the user the link, checks (`ci`), review decision and whether it can merge (`mergeability`). Never merge on failing checks or `conflicting` without the user saying so for that PR. On yes, merge exactly the commit you showed:\n```sh\nf(){ <aoapi helper>; aoapi POST \"prs/<pr number>/merge\" \"$(python3 -c 'import json,sys; print(json.dumps({\"prUrl\":sys.argv[1],\"expectedHeadSha\":sys.argv[2]}))' '<url>' '<headSha>')\"; }; f\n```\nIf the PR got new commits since you showed it, AO refuses the merge. Show it again and ask again.\n\n## Screenshot\nThe session must have a browser page open. `BROWSER_CAPABILITY_INVALID` means it has none: say so.\n```sh\nf(){ mkdir -p ~/.ao-grok/out && AO_SESSION_ID='<id>' ao browser screenshot ~/.ao-grok/out/<id>-$(date +%H%M%S).png; }; f\n```\nThen CopyToBox and SendToUser.\n\n## Files\nA session's deliverables are in its artifact folder:\n```sh\nf(){ ls -la \"${AO_DATA_DIR:-$HOME/.ao/data}/artifacts/<id>/\"; }; f\n```\nSend the file the user asks for with CopyToBox and SendToUser. HTML reports render best opened on the phone as a file.\n\n## Keep awake\nFor a run that must last overnight, after a yes:\n```sh\nf(){ <aoapi helper>; aoapi POST awake/sessions \"$(python3 -c 'import json,sys; print(json.dumps({\"mode\":\"duration\",\"durationSeconds\":int(sys.argv[1]),\"scope\":\"ao\"}))' '<seconds>')\"; }; f\n```\nSay when it ends. The user can stop it in AO. An `AWAKE` error that mentions a safety stop means AO stopped keep-awake on purpose (for example on battery): tell the user to resume it in AO. Don't resume it yourself.\n\n## Automations\nFor recurring agent work that should run on the host even when the bot is off (for example \"every night, update dependencies in <project>\"), create an AO automation after a yes:\n```sh\nao automation create --project '<project>' --name '<name>' --cron '<m h dom mon dow>' --timezone '<IANA zone>' --prompt '<task>'\n```\n`ao automation list` shows them. To remove one after a yes: `ao automation delete --yes <id>`. Use a Grok routine instead when the job is to tell the user something (ao-status \"Digest\", ao-answer waiting check).\n\n<!-- File: integrations/grok-bot/skills/ao-answer/SKILL.md (Tokens: ~1563 | Category: anthropic-skill) -->\n---\nname: ao-answer\ndescription: >-\n  Find AO sessions that wait on the user, show each question or approval as\n  tap-to-answer options, and send the answer back to that session, following\n  ao-rules \"Decisions\" (default, away mode, standing approvals). Use for\n  \"what's waiting on me\", \"answer <session>\", \"approve it\", the AO waiting\n  check routine, and away mode.\n---\nFollow the ao-rules skill. Its \"Decisions\" section says who may answer. Answers go straight to the worker, not through the orchestrator: the user's pick must arrive exactly as given.\n\n## 1. Find what's waiting\nOn every host, in parallel:\n```sh\nf(){ <aoapi helper>\n  aoapi GET 'sessions?active=true' | python3 -c '\nimport json,sys,time,calendar\nnow=time.time()\nfor s in json.load(sys.stdin)[\"sessions\"]:\n    st=(s.get(\"activity\") or {}).get(\"state\"); t=(s.get(\"lastEventAt\") or \"\")[:19]\n    if st in (\"waiting_input\",\"blocked\"): print(\"W\", s[\"id\"])\n    elif st==\"idle\" and t and now-calendar.timegm(time.strptime(t,\"%Y-%m-%dT%H:%M:%S\"))<86400: print(\"I\", s[\"id\"], s.get(\"lastEventAt\"))' |\n  while read -r k id at; do\n    if [ \"$k\" = W ]; then\n      aoapi GET \"sessions/$id/conversation\" | python3 -c '\nimport json,sys\nd=json.load(sys.stdin); found=False\nfor a in d.get(\"activities\") or []:\n    if a.get(\"activityKind\") in (\"approval\",\"user_input\") and a.get(\"status\")==\"pending\":\n        found=True; print(json.dumps({\"session\":sys.argv[1],\"kind\":a[\"activityKind\"],\"requestId\":a.get(\"requestId\"),\n            \"summary\":a.get(\"summary\"),\"decisions\":a.get(\"decisions\") or (a.get(\"detail\") or {}).get(\"decisions\"),\"detail\":a.get(\"detail\")}))\nif not found: print(json.dumps({\"session\":sys.argv[1],\"kind\":\"reply\"}))' \"$id\" 2>/dev/null\n    else\n      aoapi GET \"sessions/$id/history?offset=0&limit=1\" | python3 -c '\nimport json,sys,re\nt=(json.load(sys.stdin).get(\"turns\") or [{}])[0]; r=(t.get(\"agentResponse\") or \"\").strip()\nif re.search(r\"\\?[\\s*_`)\\]]*$\", r): print(json.dumps({\"session\":sys.argv[1],\"kind\":\"reply\",\"lastEventAt\":sys.argv[2],\"asked\":r[-300:]}))' \"$id\" \"$at\" 2>/dev/null\n    fi\n  done; }; f\n```\nEach line is one thing waiting:\n\n| `kind` | What it is |\n|---|---|\n| `approval` | Permission to run a command or change files. `summary` and `detail.input` say what; `decisions` are the options `[{id, kind, label}]` |\n| `user_input` | A question. `detail.message` asks it; `detail.schema.properties` are the fields, with choices in `enum` or `oneOf` |\n| `reply` | The agent asked in plain text: a session that waits with no request (or a terminal session), or an idle session from the last 24 hours whose last reply ends with a question (`asked` holds its end). Read its last reply (ao-status \"One session in detail\") |\n\nIn the **AO waiting check** routine: keep what you already showed in `~/.ao-grok/shown.txt` on `via`, one line per item (`<host> <session> <requestId>`, or `<host> <session> reply <lastEventAt>` for a `reply`), and message only about new items. Send nothing when nothing new is waiting.\n\n## 2. Show it\nPer session, one short briefing first: `<host>/<session>` and its name, what it is doing, and what it asks, in one or two sentences. Don't recommend anything. Then:\n- `approval`: the command or change verbatim, the risk you judge (ao-rules), and the `decisions` labels exactly as options in one card. Mark a decision whose `kind` is `allow_always` as \"changes this agent's permissions for good\".\n- `user_input`: one card with every question in it, in order (the card pages through them). A field with `oneOf` or `enum` is a question: use the `oneOf` titles or `enum` values as its options, exactly. A field whose `_meta._askUserQuestionCustomAnswer.questionId` names another field is that question's \"Other\" box: show it as a typed-answer option on that question, not as its own question. Any other free-text field is a question with a typed answer. `detail.inputMode` `url` can't be answered from chat: tell the user to open AO.\n- `reply`: the agent's question from its last reply, with options if it gave clear ones, else ask for a typed answer.\n\nSeveral sessions at once: explain them together, then cards per session.\n\n## 3. Answer\nOn the owner host, from its `via` computer:\n- **Approval**:\n  `aoapi POST \"sessions/<id>/conversation/approvals/<requestId>/resolve\" \"$(python3 -c 'import json,sys; print(json.dumps({\"decisionId\":sys.argv[1]}))' '<decision id>')\"`\n- **Question**: `content` maps each field name to the pick. For a picked option use its `oneOf` `const` (or the `enum` value), not the title. For a typed \"Other\" answer, put the text under the \"Other\" field (for example `question_0_custom`) and leave its question out:\n  `aoapi POST \"sessions/<id>/conversation/inputs/<requestId>/resolve\" \"$(python3 -c 'import json,sys; print(json.dumps({\"action\":\"accept\",\"content\":json.loads(sys.argv[1])}))' '{\"<field>\":\"<pick>\"}')\"`\n  The user says no or skip: `{\"action\":\"decline\"}`.\n- **reply**: send the answer as a message (ao-rules \"Messages to agents\"):\n  `aoapi POST \"sessions/<id>/send\" \"$(python3 -c 'import json,sys; print(json.dumps({\"message\":\"[via Grok Bot] \"+sys.argv[1],\"userAuthored\":True}))' '<answer>')\"`\n\nConfirm in one line. An error that says the request is not pending or not found means it was already answered or closed: say so. Then run step 1 for that session again, and deal with anything still open.\n\n## Away mode\nWhen memory says away mode is on and its end time hasn't passed, answer as ao-rules \"Decisions\" allows instead of showing cards, and log each one. Tell the user afterwards in one line per answer: session, what it asked, what you picked, why. Anything you may not decide: show it as in step 2, and say away mode left it for them.\n\n<!-- File: integrations/grok-bot/skills/ao-orchestrator/SKILL.md (Tokens: ~1757 | Category: anthropic-skill) -->\n---\nname: ao-orchestrator\ndescription: >-\n  Talk to a project's AO orchestrator: pass the user's request to it, wait for\n  its reply and relay it. The default route for starting or changing work,\n  \"catch me up\", \"why\", \"what next\" and plans. Use for \"in <project>: <ask>\",\n  \"tell the orchestrator ...\", \"catch me up on <project>\", \"start work on ...\".\n---\nFollow the ao-rules skill (\"Who does what: orchestrator first\"). Sending a message is a write: do it only for what the user asked in this turn.\n\n## 1. Pick the host and project\nMatch the user's words against project ids on every host (`aoapi GET projects`). One match: use it. The same project id on two hosts (two separate projects that share a folder name): ask which host, unless the user named one or memory has a default for that project. No match: list the projects and ask.\n\n## 2. Find the orchestrator\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions?orchestratorOnly=true&active=true&project=<project>\" | python3 -c '\nimport json,sys\nfor s in json.load(sys.stdin)[\"sessions\"]: print(s[\"id\"], (s.get(\"activity\") or {}).get(\"state\",\"\"), s.get(\"provisionState\",\"\"))'; }; f\n```\n- One line: that is the orchestrator. Its state tells you if it is busy (`active`).\n- `exited`: resume it first with `aoapi POST \"sessions/<id>/resume-agent\" '{}'`, then go on.\n- Provision state `failed`: AO could not create its workspace, and messages to it fail. Read the reason with `aoapi GET \"sessions/<id>\"` (field `provisionError`), tell the user in plain words, and ask them to fix it in AO. Stop here.\n- No line: ask \"There's no orchestrator in <project> on <host>. Start one with your request?\" On yes, start it with the request as its first message (step 3's file and tag), then go to step 4. Its reply is its first turn:\n\n### Start an orchestrator\n```sh\nf(){ <aoapi helper>; P='<project>'; TAG=\"[via Grok Bot #$(date +%H%M%S)]\"; F=~/.ao-grok/out/$(date +%F)-<short name>.md\n  mkdir -p ~/.ao-grok/out; { printf '%s ' \"$TAG\"; cat <<'EOF'\n<message>\nEOF\n  } > \"$F\"\n  H=$(aoapi GET \"projects/$P\" | python3 -c 'import json,sys; d=json.load(sys.stdin); c=(d.get(\"project\",d).get(\"config\") or {}); print((c.get(\"orchestrator\") or {}).get(\"agent\") or (c.get(\"worker\") or {}).get(\"agent\") or \"\")')\n  aoapi POST sessions \"$(python3 -c 'import json,sys; b={\"projectId\":sys.argv[1],\"kind\":\"orchestrator\",\"mode\":\"chat\",\"displayName\":\"Orchestrator\",\"prompt\":open(sys.argv[2]).read()}; b.update({\"harness\":sys.argv[3]} if sys.argv[3] else {}); print(json.dumps(b))' \"$P\" \"$F\" \"$H\")\" | python3 -c 'import json,sys; d=json.load(sys.stdin); d=d.get(\"session\",d); print(\"started\", d[\"id\"])' && echo \"TAG=$TAG\"; }; f\n```\nAfter about 10 seconds, check `provisionState` with `aoapi GET \"sessions/<new id>\"`. If it is `failed`, handle it as above.\n\n## 3. Send\nWrite the message to a file on `via`, then send it. The message is the user's request in their words, plus only the context from this chat the orchestrator needs. Don't add your own design choices. Start it with a tag so you can find the reply:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; TAG=\"[via Grok Bot #$(date +%H%M%S)]\"; F=~/.ao-grok/out/$(date +%F)-<short name>.md\n  mkdir -p ~/.ao-grok/out; { printf '%s ' \"$TAG\"; cat <<'EOF'\n<message>\nEOF\n  } > \"$F\"\n  B=$(python3 -c 'import json,sys; print(json.dumps({\"message\":open(sys.argv[1]).read(),\"userAuthored\":True}))' \"$F\")\n  if aoapi POST \"sessions/$O/send\" \"$B\" >/dev/null; then echo \"sent TAG=$TAG F=$F\"; return 0; fi\n  echo \"SEND_FAILED: resuming the agent and trying once more\"\n  aoapi POST \"sessions/$O/resume-agent\" '{}' >/dev/null; sleep 5\n  aoapi POST \"sessions/$O/send\" \"$B\" >/dev/null && echo \"sent TAG=$TAG F=$F\"; }; f\n```\nA failed send prints AO's error. If it still fails after the retry, tell the user the orchestrator isn't accepting messages and to open it in AO.\n\nIf the orchestrator was `active` in step 2, the message waits and runs as its own turn after the current one. Tell the user right away, in one line: \"The orchestrator is busy with <what its last turn is about>. Your question is queued and runs next.\" Then go on to step 4.\n\nIf the user wants to change what it is doing right now (\"stop that\", \"use X instead\"), steer instead. Write the file and tag as above, then:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; F='<message file>'\n  aoapi POST \"sessions/$O/conversation/steer-or-send\" \"$(python3 -c 'import json,sys,uuid; print(json.dumps({\"text\":open(sys.argv[1]).read(),\"clientMessageId\":str(uuid.uuid4())}))' \"$F\")\"; }; f\n```\n`\"outcome\":\"sent\"` means it arrived (in the running turn, or as a new turn if the orchestrator was idle). Then go to step 4.\n\n## 4. Wait for the reply\nCheck every 10 seconds for up to 5 minutes. Done when the orchestrator is no longer `active` and a turn that starts with your tag has a reply:\n```sh\nf(){ <aoapi helper>; O='<orchestrator id>'; TAG='<tag>'\n  for i in $(seq 30); do sleep 10\n    st=$(aoapi GET \"sessions/$O\" | python3 -c 'import json,sys; d=json.load(sys.stdin); d=d.get(\"session\",d); print((d.get(\"activity\") or {}).get(\"state\",\"\"))')\n    [ \"$st\" = active ] && continue\n    aoapi GET \"sessions/$O/history?offset=0&limit=5\" | python3 -c '\nimport json,sys\nfor t in json.load(sys.stdin).get(\"turns\") or []:\n    if (t.get(\"userRequest\") or \"\").startswith(sys.argv[1]) and t.get(\"agentResponse\"):\n        print(t[\"agentResponse\"]); raise SystemExit(0)\nraise SystemExit(1)' \"$TAG\" && return 0\n  done; echo STILL_WORKING; }; f\n```\n- A reply: relay it. Keep it faithful. Shorten only for a phone, and send a long reply as a file.\n- `STILL_WORKING`: tell the user the orchestrator is still on it, and offer: \"I'll message you when it replies.\" On yes, create a routine that runs step 4 once every 5 minutes for that tag, reports the reply, then deletes itself.\n- The orchestrator asks the user something back: show it as a card if it gives clear options, and send the pick as a new message (step 3).\n\n## 5. After\nIf the orchestrator started workers, list them in one line (ao-status \"Sessions\" for that project). Don't watch them unless the user asks. Their questions reach the user through ao-answer.\n\n<!-- File: integrations/grok-bot/skills/ao-rules/SKILL.md (Tokens: ~2298 | Category: anthropic-skill) -->\n---\nname: ao-rules\ndescription: >-\n  Shared rules and the connection helper for every ao-* skill (run\n  Orchestrator from chat). Read before running any ao-* skill.\n---\n# AO rules\n\nEvery ao-* skill follows these rules. Other skills link here instead of repeating them.\n\n## AO hosts\nAn **AO host** is one computer that runs the AO daemon. Each host has its own projects, sessions and orchestrators, and AO never links them: a repo cloned on two hosts is two separate projects. AO names a project after its folder, so both can still get the same id, and then the same session id (for example `agent-orchestrator-1-12`) can exist on both. Always name a session as `<host>/<session id>`, and act only on the host that owns it.\n\nMemory keeps one note named **AO hosts**, with one line per host:\n\n| Field | Example | Meaning |\n|---|---|---|\n| `name` | `Pro` | A short name: the user's pick, else the model word of the ListMachines label (`Pro`, `Air`, `mini`). Never the network hostname such as `MacBookAir.lan` |\n| `reach` | `local` or `remote` | How you get to its AO |\n| `via` | `laptop` | The ListMachines label of the computer whose shell you use |\n| `base` | `http://192.168.1.20:7444` | Remote only. The host's LAN address from AO's remote access settings |\n| `header` | `~/.ao-grok/studio.header` | Remote only. File on `via` that holds the host's password |\n\n- **local**: the Grok Bot desktop app runs on the AO host. `via` is the host itself.\n- **remote**: the Grok Bot desktop app runs on another computer. You call the host's AO API over the network from `via`. The `ao` CLI on `via` talks only to `via`'s own AO, so never use it for a remote host.\n\nOne computer can be `via` for itself (local) and for other hosts (remote) at the same time.\n\nEvery run: call ListMachines, then use every host whose `via` computer is connected, in parallel, labelled by host name. Say once which hosts you could not reach. Never hard-code machine ids or home paths.\n\n## Calling AO\nStart every shell command that calls AO with this helper. It works in zsh and bash:\n\n```sh\naoapi(){ # aoapi METHOD PATH [JSON]\n  local base hdr=() data=() f=\"${AO_RUN_FILE:-$HOME/.ao/running.json}\"\n  if [ -n \"$AO_REMOTE_BASE\" ]; then base=\"$AO_REMOTE_BASE\"; hdr=(-H @\"$AO_REMOTE_HEADER\")\n  else [ -f \"$f\" ] || { echo \"AO_NOT_RUNNING\" >&2; return 3; }\n    base=\"http://127.0.0.1:$(grep -o '\"port\": *[0-9]*' \"$f\" | grep -o '[0-9]*$')\"; fi\n  [ -n \"$3\" ] && data=(--data \"$3\")\n  curl -sS --fail-with-body --max-time 30 -X \"$1\" \"${hdr[@]}\" -H 'Content-Type: application/json' \"${data[@]}\" \"$base/api/v1/$2\"\n}\n```\n\n- Local host: use `aoapi` as is.\n- Remote host: on the `via` computer, first set `AO_REMOTE_BASE='<base>' AO_REMOTE_HEADER=\"$HOME/.ao-grok/<name>.header\"`.\n- Build JSON bodies with `python3 -c 'import json,sys; print(json.dumps(...))' \"$ARG\"`, never by pasting text into quotes.\n- Anything longer than one line goes in a file first: `~/.ao-grok/out/<date>-<short name>.md` on `via`. The user can see what was sent.\n- Use the `ao` CLI only where a skill says \"local only\".\n\n### Errors\n| You see | Meaning and next step |\n|---|---|\n| `AO_NOT_RUNNING`, or connection refused on a local host | AO is not running there. Ask the user to open AO |\n| Connection refused or timeout on a remote host | The host is asleep, off this network, or remote access is off. Ask the user to check AO's remote access settings on the host |\n| HTTP 401 or 403 on a remote host | The host's password changed. Run ao-setup \"Remote host\" again |\n| HTTP 404 on a session path | No such session on that host. Check the host name |\n| Any other error | AO returns JSON with `message`. Relay it in plain words |\n\n## Who does what: orchestrator first\nEach project on a host has at most one live **orchestrator**: an agent that plans the project's work, starts and steers workers, and gets their reports. It has more context than you do. You are the user's phone line to it.\n\n- **Send to the orchestrator** (ao-orchestrator): starting or changing work, \"catch me up\", \"why\", \"what next\", plans, and anything that needs judgement about the code.\n- **Do directly**: status lists (ao-status), answering a pending request with the user's own pick (ao-answer), stop and interrupt, merges after the user's yes, files and screenshots (ao-actions).\n- Never start a worker yourself in a project that has a live orchestrator. Ask the orchestrator instead. With no orchestrator, ask the user whether to start one or to start the worker directly.\n- After you act directly on a worker (answer, stop, merge), the orchestrator sees it through AO. Don't send it a separate note.\n\n## Decisions\nA worker asks for two kinds of decision. A **question** (`user_input`) asks what to build. An **approval** asks permission to run a command or change files. Who decides depends on the mode, saved in memory:\n\n1. **Default mode**: show each question or approval to the user as a card with the exact options. Answer only with their pick for that request. Never reuse a pick for a new request.\n2. **Away mode** starts when the user says something like \"I'm away\", \"decide for me\" or \"keep it moving\". Save the scope and the end time in memory. Then:\n   - Answer routine questions yourself, and tell the user afterwards what you picked and why.\n   - Accept `low` and `normal` approvals with the one-time option (`kind` `allow_once`). Never pick an `allow_always` option: it changes the agent's permissions for good. Never accept a `high` approval without the user's yes for that request.\n   - Leave product direction, money, publishing and anything the user kept for themselves to the user.\n   - Away mode ends at the end time or when the user is back. Say when it ended.\n3. **Standing approvals**: the user may list kinds of approvals to always accept. Follow the list exactly.\n\nAO gives no risk level, so you judge it. Treat these as a floor. If a command looks riskier, call it high.\n\n| Risk | Examples |\n|---|---|\n| high | Deletes outside the session's worktree, `rm -rf`, `git push --force`, push to `main` or `master`, `git reset --hard`, history rewrites, deploy, publish, release, secrets, credentials, tokens, `sudo`, system installs, payments |\n| low | Reading or searching files, `git status`/`diff`/`log`, tests, lint, typecheck, builds |\n| normal | Everything else, such as edits and commits in the session's worktree, or pushing the session's own branch |\n\nNever invent the user's preferences. The worker decides how to do the work. The user decides what to build.\n\n## Writes\nChange nothing on the user's computers unless the user approved that exact change in chat, or away mode or a standing approval covers it. Approval for one change is not approval for the next. Never delete or archive sessions or projects, never change AO settings, and never merge, publish or deploy without the user's yes for that item.\n\n## Secrets\n- The `header` file holds a host's password. Pass it only to curl as `-H @<file>`. Never open, print, copy or paste it.\n- Never read AO's own credential files: `~/.ao/mobile/`, `~/.ao/data/agent-accounts/`, `~/.ao/electron/`, or any `*token*`, `*auth*`, `.env` or keychain item.\n- If session text contains a key, never repeat it.\n\n## Messages to agents\n- Before you send a follow-up, read the last turn (`aoapi GET \"sessions/<id>/history?offset=0&limit=1\"`) so you don't repeat or contradict it.\n- Keep messages short and concrete: what is right so far, then the next step. Leave out check-ins, your own process and these rules.\n- Start every message you send with `[via Grok Bot]`, so the user can tell it apart in AO.\n\n## Output\n- Answer first, in short plain words. Say what you could not check.\n- Write every session as `<host name>/<session id>`, every time, in every skill and every line, even when only one host has that id: `Air/agent-orchestrator-31`, `Pro/agent-orchestrator-1-249`. Add the display name when it helps.\n- Give times in the user's timezone.\n- One message per event. If two checks report the same thing, say it once. News (a merge, a finished review) is reported once: ao-status keeps a seen list.\n- Send files with SendToUser. Copy them to the box first with CopyToBox.\n\n## Memory\n- Save hosts, modes and preferences, not activity. A check where nothing changed is not worth a note.\n- When the user corrects you, save the correction.\n- A follow-up you promise for later (\"I'll tell you when it's done\") goes into a Routine, not only into memory.\n\n## Grok Bot only\nThese steps need tools only Grok Bot has. Any other agent (Claude Code, Codex, Cursor) runs on one computer and does this instead:\n\n| Grok Bot step | Other agents |\n|---|---|\n| ListMachines, every connected computer | Only the computer you run on, as a local host |\n| Routines | Run the check once when asked |\n| Cards | Plain text with numbered options |\n| Memory | Ask, or use the notes file the user names |\n| SendToUser, CopyToBox | Give the file path |\n\n<!-- File: integrations/grok-bot/skills/ao-setup/SKILL.md (Tokens: ~3951 | Category: anthropic-skill) -->\n---\nname: ao-setup\ndescription: >-\n  First run of Orchestrator Bot: find every computer that runs AO, save them as\n  AO hosts, add a remote AO host that has no Grok Bot desktop app, and turn on\n  optional routines. On a computer without Orchestrator.inc it helps install it\n  and get it ready: a coding agent, a first project and the first orchestrator.\n  Use on the first chat, when memory has no \"AO hosts\" note, or when the user\n  says \"set up AO\", \"add a host\", \"add remote host\", \"check my AO setup\" or\n  \"install Orchestrator\".\n---\nFollow the ao-rules skill. Detection is read-only. Nothing is written until the user says yes.\n\nOpen with one line: \"Give me a few seconds to look for AO on your computers.\"\n\n## 1. Detect\n1. ListMachines. Use desktops only. If none is connected, say: \"Install the Grok Bot desktop app on the computer where you run Orchestrator.inc (or want to), sign in, and tell me when it shows up,\" then stop.\n2. On each connected desktop, in parallel, run this read-only probe with the `aoapi` helper from ao-rules: run \"Probe\" below.\n3. Each desktop where the probe prints a `projects=` line is a **local** AO host; an empty list means it still needs \"First run\". For any other result, see \"Missing pieces\". On a Windows desktop, don't run the probe: say once \"These skills need macOS or Linux; Windows isn't supported yet,\" and skip it.\n\n### Probe\n```sh\nf(){ <aoapi helper>; echo \"ao=$(command -v ao >/dev/null && ao version 2>/dev/null | head -1 || echo missing)\"\n  if [ \"$(uname -s)\" = Darwin ] && [ \"$(command -v python3)\" = /usr/bin/python3 ] && ! xcode-select -p >/dev/null 2>&1; then echo \"python=missing\"\n  else echo \"python=$(command -v python3 >/dev/null && python3 -c 'import sys;print(\"%d.%d\"%sys.version_info[:2])' || echo missing)\"; fi\n  [ \"$(uname -s)\" = Darwin ] && A=$(find /Applications \"$HOME/Applications\" -maxdepth 1 -name '*Orchestrator*.app' 2>/dev/null | head -1) && echo \"app=${A:-missing}\"\n  if P=$(aoapi GET projects 2>/dev/null); then\n    echo \"$P\" | python3 -c 'import json,sys; d=json.load(sys.stdin); p=d.get(\"projects\",d) if isinstance(d,dict) else d; print(\"projects=\" + \", \".join(x.get(\"id\",\"?\") for x in p))'\n    aoapi GET 'sessions?active=true' | python3 -c 'import json,sys; print(\"live_sessions=%d\" % len(json.load(sys.stdin)[\"sessions\"]))'\n  else echo \"daemon=not running\"; fi; }; f\n```\n\n## Missing pieces\nUse the probe result for each computer. Install or open anything only after the user's yes.\n\n| Probe shows | Next step |\n|---|---|\n| `python=missing` | Fix this first: every step needs it. macOS: `xcode-select --install` (the user confirms the system dialog). Linux: give the package manager line for python3 |\n| `daemon=not running` and `app=missing` (macOS) | Say: \"Orchestrator.inc isn't installed on <computer>. Want me to install it? It's about a 300 MB download.\" On yes, run \"Install on a Mac\" |\n| `daemon=not running` and `app=<path>` | On yes, open it with `open \"<path>\"`, then \"Wait for the app\" |\n| `daemon=not running` on Linux | If Orchestrator.inc is installed, ask the user to open it and say **check again**. Otherwise give the download for the user's distribution: [AppImage](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.AppImage), [.deb](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.deb) or [.rpm](https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/agent-orchestrator-linux-x64.rpm). The user installs and opens it, then says **check again** |\n| `projects=` with nothing after it | Run \"First run\" |\n| `ao=missing` with projects listed | Everything works except starting a review, screenshots and automations, which use the `ao` CLI. Say so once |\n\n**check again** runs the probe on that computer again and goes on from its result.\n\n**Wait for the app:** run the probe every 15 seconds, for up to 2 minutes, until it prints a `projects=` line. Still `daemon=not running` after that: ask the user to look at the Orchestrator.inc window and say **check again** when it's open.\n\n### Install on a Mac\nAfter a yes, on that computer. The download takes a few minutes, so the install runs in the background, in its own session so it keeps going after this command returns, and writes its progress to `~/.ao-grok/install.log`. It picks the build for the Mac's chip, checks the app's code signature (Orchestrator.inc's Developer ID team `X9LNSP8MC2`), copies it to Applications (or `~/Applications` if that isn't writable) and opens it:\n```sh\nf(){ mkdir -p ~/.ao-grok && cat > ~/.ao-grok/install-orchestrator.sh <<'EOF'\na=$([ \"$(sysctl -n hw.optional.arm64 2>/dev/null)\" = 1 ] && echo arm64 || echo x64); d=$(mktemp -d)\necho \"downloading the $a build\"\ncurl -fsSL -o \"$d/o.dmg\" \"https://github.com/OrchestratorInc/agent-orchestrator/releases/latest/download/Orchestrator-darwin-$a.dmg\" || { echo DOWNLOAD_FAILED; rm -rf \"$d\"; exit 1; }\nm=$(hdiutil attach -nobrowse -readonly \"$d/o.dmg\" | awk -F'\\t' '/\\/Volumes\\//{print $NF}' | tail -1)\n[ -n \"$m\" ] || { echo INSTALL_FAILED; rm -rf \"$d\"; exit 1; }\napp=$(find \"$m\" -maxdepth 1 -name '*.app' 2>/dev/null | head -1)\ndone_(){ [ -n \"$m\" ] && hdiutil detach -quiet \"$m\"; rm -rf \"$d\"; }\nif [ -z \"$app\" ] || ! codesign --verify --deep --strict \"$app\" 2>/dev/null || ! codesign -dv \"$app\" 2>&1 | grep -q 'TeamIdentifier=X9LNSP8MC2'; then echo BAD_SIGNATURE; done_; exit 1; fi\ndest=/Applications\ncp -R \"$app\" \"$dest/\" 2>/dev/null || { dest=\"$HOME/Applications\"; mkdir -p \"$dest\" && cp -R \"$app\" \"$dest/\"; } || { echo INSTALL_FAILED; done_; exit 1; }\ndone_\nopen \"$dest/${app##*/}\" && echo \"INSTALLED $dest/${app##*/}\" || echo \"INSTALLED_NOT_OPENED $dest/${app##*/}\"\nEOF\nnohup python3 -c 'import os,sys; os.setsid(); os.execvp(\"sh\", [\"sh\", sys.argv[1]])' ~/.ao-grok/install-orchestrator.sh > ~/.ao-grok/install.log 2>&1 & echo STARTED; }; f\n```\nTell the user it has started. Then check `tail -1 ~/.ao-grok/install.log` every 20 seconds, for up to 15 minutes:\n\n| Last line | Next step |\n|---|---|\n| `downloading …` | Still going |\n| `INSTALLED <path>` | Say \"Orchestrator.inc is open on <computer>. I'll get it ready: a coding agent and your first project.\" Then \"Wait for the app\" and run \"First run\" |\n| `INSTALLED_NOT_OPENED <path>` | Open it with `open \"<path>\"`, then as above |\n| `DOWNLOAD_FAILED`, `BAD_SIGNATURE`, `INSTALL_FAILED`, or no change after 15 minutes | Say what happened and give the user the [download page](https://orchestrator.inc/download/) instead. Never retry `BAD_SIGNATURE` |\n\n## First run\nGets a computer ready for work once Orchestrator.inc is running there: a coding agent, a project, and the first orchestrator. Every change needs the user's yes. If Orchestrator.inc shows its own welcome steps and the user prefers them, let them finish there and say **check again**.\n\n### 1. A coding agent\n```sh\nf(){ <aoapi helper>; aoapi POST agents/refresh '{}' >/dev/null; aoapi GET agents/readiness | python3 -c '\nimport json,sys\nfor a in json.load(sys.stdin).get(\"agents\") or []:\n    inst=(a.get(\"installation\") or {}).get(\"state\",\"\"); auth=(a.get(\"authentication\") or {}).get(\"state\",\"\")\n    if inst!=\"not_installed\" or a.get(\"id\") in (\"claude-code\",\"codex\"):\n        print(\"\\t\".join([a.get(\"id\",\"\"), a.get(\"label\",\"\"), a.get(\"effectiveReadiness\",\"\"), inst, auth]))'; }; f\n```\nColumns: id, name, readiness, installed, signed in.\n- **Some agent is `ready`:** use it. If more than one is ready, ask which one should do the work. Don't pick for the user.\n- **Installed but not signed in:** on yes, `aoapi POST \"agents/<id>/auth\" '{}'` and relay its `guidance`. The sign-in runs in a terminal inside Orchestrator.inc; the user finishes it there (it may open their browser). When they say done, run this step again: it refreshes the checks.\n- **None installed:** ask \"Which coding agent do you want to use: Claude Code or Codex?\" On the pick and a yes, `aoapi POST \"agents/<id>/install\" '{}'`, then check `aoapi GET \"agents/<id>/install\"` every 15 seconds. `status` `succeeded`: sign in as above. `failed`, `unsupported` or `interrupted`: relay it, and point the user to the agent settings in Orchestrator.inc.\n\n### 2. A project\nSuggest the git clones the user worked in most recently (read-only; worktrees are left out):\n```sh\npython3 -c '\nimport glob,os\nhome=os.path.expanduser(\"~\"); found=set()\nfor r in (\"Development\",\"Projects\",\"projects\",\"code\",\"Code\",\"src\",\"dev\",\"GitHub\",\"Documents/GitHub\"):\n    for pat in (\"*/.git\",\"*/*/.git\",\"*/*/*/.git\"): found.update(os.path.dirname(g) for g in glob.glob(os.path.join(home,r,pat)) if os.path.isdir(g))\nfor p in sorted(found,key=lambda p:-os.path.getmtime(os.path.join(p,\".git\")))[:10]: print(p.replace(home,\"~\",1))'\n```\nShow them as one card, plus a typed option for another folder. On the pick, register it with the agent from step 1:\n```sh\nf(){ <aoapi helper>; aoapi POST projects \"$(python3 -c 'import json,os,sys; print(json.dumps({\"path\":os.path.expanduser(sys.argv[1]),\"config\":{\"worker\":{\"agent\":sys.argv[2]},\"orchestrator\":{\"agent\":sys.argv[2]}}}))' '<repo path>' '<agent id>')\" 2>/dev/null | python3 -c '\nimport json,sys\nd=json.load(sys.stdin); p=d.get(\"project\",d)\nif p.get(\"id\"): print(\"added\", p[\"id\"])\nelse: print(d.get(\"code\",\"ERROR\"), d.get(\"message\",\"\"), (d.get(\"details\") or {}).get(\"existingProjectId\",\"\"))'; }; f\n```\n- `added <id>`: done.\n- `NOT_A_GIT_REPO`: the folder needs to be a git repository with at least one commit. Ask for another folder.\n- `PATH_ALREADY_REGISTERED <id>`: it is already a project; use that id.\n\n### 3. The first orchestrator\nAsk: \"Want me to start the orchestrator for <project>? Tell me what you'd like done first, or I'll ask it to look around the repo and suggest a first task.\" On yes, run ao-orchestrator \"Start an orchestrator\" with that request.\n\nThen continue with section 2.\n\n## 2. Report and ask once\nOne message, at most 6 lines: per computer, AO found or not, its projects, and how many sessions are live. For a computer without a working AO, add the one next step from \"Missing pieces\". Then:\n\"Reply **yes** and I'll save these as your AO hosts. Is AO also running on a computer without the Grok Bot desktop app? Say **add remote host** and I'll connect to it from one of these.\"\n\nOn yes, save the **AO hosts** note (ao-rules \"AO hosts\") with `reach: local` and `via` = the same computer. Name each host with its short name (ao-rules `name`) and say the names in one line: \"I'll call them Pro and Air. Say if you want other names.\"\n\n## 3. Remote host (optional)\nUse this when AO runs on a computer that has no Grok Bot desktop app, for example a Mac mini host that a laptop's AO app already connects to.\n\n1. Ask for a short host name (letters, digits, `-`) and which connected computer to use as `via`. Default: the one the user's message came from.\n2. Tell the user, in one message:\n   \"On the host, open AO, go to remote access (Connect Mobile) and turn on network access. It shows an address and a password. Send me the **address** here. You'll type the password on <via> in a window I open, so it never passes through this chat.\"\n   On the host's own terminal, `ao remote-host enable` turns on the same network access, and `ao remote-host status` shows the address and the password.\n3. When the address arrives, check it looks like `http://<ip or name>:<port>`. Then, on `via`, write a one-time password window and open it. Replace `<name>` with the host name you checked: run \"Password window\" below.\n   Tell the user: \"A Terminal window opened on <via>. Type the password there and press Return.\"\n   On Linux, `open` doesn't run `.command` files: write the same lines to `~/.ao-grok/add-<name>.sh` and ask the user to run `zsh ~/.ao-grok/add-<name>.sh` in a terminal on `via`.\n4. When they say done, test it from `via`: run \"Connection test\" below.\n   HTTP 401 means a wrong password: open the window again. A timeout means the host is not reachable from `via` (another network, asleep, or access off).\n5. Add the host to the **AO hosts** note with `reach: remote`, `via`, `base` and `header`.\n\n### Password window\n```sh\nf(){ mkdir -p ~/.ao-grok/out && cat > ~/.ao-grok/add-<name>.command <<'EOF'\n#!/bin/zsh\numask 077\nread -rs \"p?AO password for <name>: \"; echo\nprintf 'Authorization: Bearer %s\\n' \"$p\" > ~/.ao-grok/<name>.header\necho \"Saved. You can close this window.\"; rm -- \"$0\"\nEOF\nchmod +x ~/.ao-grok/add-<name>.command && open ~/.ao-grok/add-<name>.command; }; f\n```\n\n### Connection test\n```sh\nf(){ <aoapi helper>; AO_REMOTE_BASE='<address>' AO_REMOTE_HEADER=\"$HOME/.ao-grok/<name>.header\" aoapi GET 'sessions?active=true' | python3 -c 'import json,sys; print(\"live_sessions=%d\" % len(json.load(sys.stdin)[\"sessions\"]))'; }; f\n```\n\nLimits of a remote host, said once: keep-awake, browser screenshots and starting a review work only on local hosts. For those, ask the host's orchestrator (ao-orchestrator). Quick-tunnel addresses change when the tunnel restarts, so prefer the LAN address or a named tunnel. If the user presses Regenerate in AO, run this section again.\n\n## 4. Mode and routines\n1. Save **Mode: default** in memory (ao-rules \"Decisions\"). Say in one line that away mode exists: \"Say 'I'm away till 6' and I'll keep routine work moving.\"\n2. Offer the routines in one multi-select card, nothing pre-selected, plus **none**:\n   - **AO waiting check**: every 30 minutes, 9:00 to 19:00 on weekdays. Runs ao-answer \"Find what's waiting\" and messages only when something new is waiting.\n   - **AO daily digest**: weekdays at 9:00. Runs ao-status \"Digest\".\n   Create the picked routines, then save \"Routines on: <names>\" in memory. Never create a second copy.\n3. Say once: \"AO's mobile app pushes questions to your phone the moment they happen. These routines check on a schedule.\"\n\n## 5. Finish\nOne line: the hosts saved (local and remote), the mode and the routines on. Then run ao-status as a first look, then:\n\nThings to try:\n- what's waiting on me\n- catch me up on <project>\n- in <project>: <what you want done>\n- I'm away till 6, keep things moving\n- what's ready to merge\n- show me what <session> built\n\n<!-- File: integrations/grok-bot/skills/ao-status/SKILL.md (Tokens: ~1333 | Category: anthropic-skill) -->\n---\nname: ao-status\ndescription: >-\n  What AO is doing on every host: which sessions are running, waiting on the\n  user, idle or exited, which PRs are ready to merge or got a review, and a\n  daily digest. Read-only. Use for \"status\", \"what's running\", \"what's waiting\n  on me\", \"what's ready to merge\", \"anything stuck\", and the AO daily digest\n  routine.\n---\nFollow the ao-rules skill. Read-only in AO: it never marks anything read there. It keeps its own seen list in `~/.ao-grok/` on each `via` computer. Run on every host in the **AO hosts** note, in parallel, each from its `via` computer with the `aoapi` helper (set `AO_REMOTE_BASE` and `AO_REMOTE_HEADER` for remote hosts). If memory has no **AO hosts** note, run ao-setup first. Don't save hosts without the user's yes.\n\n## 1. Sessions\n```sh\nf(){ <aoapi helper>; aoapi GET 'sessions?active=true' | python3 -c '\nimport json,sys\nfor s in json.load(sys.stdin)[\"sessions\"]:\n    a=s.get(\"activity\") or {}\n    print(\"\\t\".join([s[\"id\"], s.get(\"kind\",\"\"), a.get(\"state\",\"\"), str(len(s.get(\"prs\") or [])), (s.get(\"displayName\") or \"\")[:60]]))'; }; f\n```\nColumns: id, kind (`orchestrator` or `worker`), state, PR count, name. States:\n\n| State | Say |\n|---|---|\n| `active` | running |\n| `waiting_input`, `blocked` | waiting on you |\n| `idle` | idle: finished its turn, or not started |\n| `exited` | the agent exited; it can be resumed (ao-actions) |\n\nFor what's waiting on the user, run ao-answer \"Find what's waiting\": it finds sessions in `waiting_input` or `blocked`, and idle sessions whose last reply asked the user a question. Never use notifications for it. Group by host, then by project (the session id starts with the project id).\n\nKeep the reply short enough for a phone, at most 6 lines: first what needs the user, then what's running, then one line per host with counts (for example \"MacBook Pro: 25 idle, 9 exited\"). Name a session only when it needs the user or is running. Leave out idle orchestrators, PR numbers and exited sessions unless asked. Report what you saw; don't guess why (a crash, a restart) unless the user asks.\n\n## 2. PRs and reviews\n```sh\nf(){ <aoapi helper>\n  aoapi GET 'notifications?status=unresolved' | python3 -c '\nimport json,sys\nfor n in json.load(sys.stdin)[\"notifications\"]:\n    if n.get(\"type\")==\"ready_to_merge\": print(\"\\t\".join([\"ready_to_merge\", n.get(\"sessionId\",\"\"), n.get(\"prUrl\",\"\"), (n.get(\"title\") or \"\")[:80]]))'\n  SEEN=\"$HOME/.ao-grok/<host name>.seen-news\"; mkdir -p ~/.ao-grok; touch \"$SEEN\"\n  aoapi GET 'notifications?status=unread' | python3 -c '\nimport json,sys\nseen=set(open(sys.argv[1]).read().split()); new=[]\nfor n in json.load(sys.stdin)[\"notifications\"]:\n    if n.get(\"type\") in (\"review_completed\",\"review_changes_requested\",\"pr_merged\",\"pr_closed_unmerged\") and not n.get(\"resolvedAt\") and n.get(\"id\") not in seen:\n        new.append(n[\"id\"]); print(\"\\t\".join([n[\"type\"], n.get(\"sessionId\",\"\"), n.get(\"prUrl\",\"\"), (n.get(\"title\") or \"\")[:80]]))\nopen(sys.argv[1],\"a\").writelines(i+\"\\n\" for i in new)' \"$SEEN\"\n  tail -n 500 \"$SEEN\" > \"$SEEN.tmp\" && mv \"$SEEN.tmp\" \"$SEEN\"; }; f\n```\n- `ready_to_merge` comes from the unresolved list, so a PR that was merged or changed since drops off. For \"what's ready to merge\", list these with the PR link, and offer the merge (ao-actions; needs the user's yes per PR).\n- `review_completed`, `review_changes_requested`, `pr_merged`, `pr_closed_unmerged` are news. The command prints only news this bot hasn't reported before, and records it as reported, so each item appears once, in a status reply or in the digest, whichever comes first. Mention each in one line. For \"what's new again\" or \"show all news\", run it without the seen list.\n- Never use `needs_input` notifications. They can outlive the wait (the session answered or exited); section 1 is the source for what's waiting.\n\n## 3. One session in detail\nFor \"what is <session> doing\": find it (ask which host if the id is on two hosts), then read its last turn:\n```sh\nf(){ <aoapi helper>; aoapi GET \"sessions/<id>/history?offset=0&limit=1\" | python3 -c '\nimport json,sys\nt=(json.load(sys.stdin).get(\"turns\") or [{}])[0]\nprint(\"asked:\", (t.get(\"userRequest\") or \"\")[:500]); print(\"replied:\", (t.get(\"agentResponse\") or \"\")[-1500:])'; }; f\n```\nSummarise in two or three lines. For \"catch me up on <project>\", ask the project's orchestrator instead (ao-orchestrator). It has the workers' reports.\n\n## Digest\nThe **AO daily digest** routine runs this skill. Per host: what finished since the last digest (idle sessions with `lastEventAt` since then), what's waiting on the user, what's ready to merge, and anything exited unexpectedly. Skip quiet projects. Send nothing if nothing happened and nothing is waiting. Write the time of this digest to `~/.ao-grok/<host name>.last-digest` on `via` and read it next time, instead of keeping it in memory.\n\n<!-- File: integrations/grok-bot/skills/ao-update/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# ao-update\n\nPath: `integrations/grok-bot/skills/ao-update/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/integrations/grok-bot/skills/ao-update/SKILL.md)\n\n<!-- File: packages/ao-darwin-arm64/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Ao-darwin-arm64 Skill\n\nPath: `packages/ao-darwin-arm64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-arm64/package.json)\n\n<!-- File: packages/ao-darwin-x64/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Ao-darwin-x64 Skill\n\nPath: `packages/ao-darwin-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-darwin-x64/package.json)\n\n<!-- File: packages/ao-linux-x64/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Ao-linux-x64 Skill\n\nPath: `packages/ao-linux-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-linux-x64/package.json)\n\n<!-- File: packages/ao-win32-x64/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Ao-win32-x64 Skill\n\nPath: `packages/ao-win32-x64/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao-win32-x64/package.json)\n\n<!-- File: packages/ao/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Ao Skill\n\nPath: `packages/ao/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/HEAD/packages/ao/package.json)\n\n<!-- ... +43 more modular skills available via /api/skills/ComposioHQ/agent-orchestrator?path={path} -->\n</yakaai_skills>"}