ao-desktop-dev
Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real…
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",
$ npx -y skills add orchestratorinc/agent-orchestrator --skill ao-answer --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/ao-answerContext preview
The summary Claude sees to decide when to auto-load this skill.
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",
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.
Follow 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.
On every host, in parallel:
f(){ <aoapi helper>
aoapi GET 'sessions?active=true' | python3 -c '
import json,sys,time,calendar
now=time.time()
for s in json.load(sys.stdin)["sessions"]:
st=(s.get("activity") or {}).get("state"); t=(s.get("lastEventAt") or "")[:19]
if st in ("waiting_input","blocked"): print("W", s["id"])
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"))' |
while read -r k id at; do
if [ "$k" = W ]; then
aoapi GET "sessions/$id/conversation" | python3 -c '
import json,sys
d=json.load(sys.stdin); found=False
for a in d.get("activities") or []:
if a.get("activityKind") in ("approval","user_input") and a.get("status")=="pending":
found=True; print(json.dumps({"session":sys.argv[1],"kind":a["activityKind"],"requestId":a.get("requestId"),
"summary":a.get("summary"),"decisions":a.get("decisions") or (a.get("detail") or {}).get("decisions"),"detail":a.get("detail")}))
if not found: print(json.dumps({"session":sys.argv[1],"kind":"reply"}))' "$id" 2>/dev/null
else
aoapi GET "sessions/$id/history?offset=0&limit=1" | python3 -c '
import json,sys,re
t=(json.load(sys.stdin).get("turns") or [{}])[0]; r=(t.get("agentResponse") or "").strip()
if 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
fi
done; }; fEach line is one thing waiting:
| `kind` | What it is | |---|---| | `approval` | Permission to run a command or change files. `summary` and `detail.input` say what; `decisions` are the options `[{id, kind, label}]` | | `user_input` | A question. `detail.message` asks it; `detail.schema.properties` are the fields, with choices in `enum` or `oneOf` | | `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") |
In 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.
Per 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:
Several sessions at once: explain them together, then cards per session.
On the owner host, from its `via` computer:
`aoapi POST "sessions/<id>/conversation/approvals/<requestId>/resolve" "$(python3 -c 'import json,sys; print(json.dumps({"decisionId":sys.argv[1]}))' '<decision id>')"`
`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>"}')"` The user says no or skip: `{"action":"decline"}`.
`aoapi POST "sessions/<id>/send" "$(python3 -c 'import json,sys; print(json.dumps({"message":"[via Grok Bot] "+sys.argv[1],"userAuthored":True}))' '<answer>')"`
Confirm 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.
When 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.
Plan, run and supervise fleets of agents from task to merged PR. Desktop (macOS, Windows, Linux) + iPhone & Android apps. Supports Claude Code, Codex & 35+ coding agents.
Launch, restart, or troubleshoot the real AO Electron desktop app from this repository; run a checkout against isolated or real…
Help clarify human bug reports, search for duplicates, and gather diagnostic evidence separately from a concise issue draft.
Direct actions on one AO session or PR: stop or interrupt, resume, merge a PR, start a review, screenshot a session's browser,…
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…
Shared rules and the connection helper for every ao-* skill (run Orchestrator from chat). Read before running any ao-* skill.
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…