Skip to content
agent-workspaces
Skill

/ao-update

Update this bot's ao-* skills to the latest published version: check what changed, show it, and after the user's yes download each changed skill, verify its sha256 against the published manifest, and rewrite it. Use for "update Orchestrator Bot", "update the AO bot", "update my

BOOST
From plugin
untrivial-ai-agent-orchestrator
14k9 skills19 commands
Install
$ npx -y skills add orchestratorinc/agent-orchestrator --skill ao-update --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/ao-update

Context preview

The summary Claude sees to decide when to auto-load this skill.

Update this bot's ao-* skills to the latest published version: check what changed, show it, and after the user's yes download each changed skill, verify its sha256 against the published manifest, and rewrite it. Use for "update Orchestrator Bot", "update the AO bot", "update my

SKILL.md

ao-update.SKILL.md
name: ao-update
description: >-
  Update this bot's ao-* skills to the latest published version: check what
  changed, show it, and after the user's yes download each changed skill,
  verify its sha256 against the published manifest, and rewrite it. Use for
  "update Orchestrator Bot", "update the AO bot", "update my AO skills",
  "what's new in Orchestrator Bot".

Follow the ao-rules skill. This runs on the bot's own cloud computer (the box), not on the user's computers. It changes only this bot's ao-* skills, and only after the user's yes.

The skills are published in the public AO repository (`OrchestratorInc/agent-orchestrator`, folder `integrations/grok-bot/`) with a `manifest.json` that lists each skill's sha256. Every check reads the newest commit on `main`, then downloads the manifest and the skills from that exact commit, so the files always match each other.

1. Save the fetcher

Save it on the box if `/workspace/ao-bot/fetch.py` is missing or differs:

f(){ mkdir -p /workspace/ao-bot && cat > /workspace/ao-bot/fetch.py <<'PY'
import hashlib, json, os, re, subprocess, sys
REPO, DIR = "OrchestratorInc/agent-orchestrator", "integrations/grok-bot"
SRC = os.environ.get("AO_BOT_SOURCE")  # a local folder instead of GitHub, for testing
STATE = os.environ.get("AO_BOT_STATE", "/workspace/ao-bot")
def get(url):  # curl, so the system's certificates are used
    r = subprocess.run(["curl", "-fsSL", "--max-time", "30", "-H", "User-Agent: ao-bot", url], capture_output=True)
    if r.returncode: sys.exit(f"DOWNLOAD_FAILED {url} {r.stderr.decode().strip()}")
    return r.stdout
def commit():
    return "local" if SRC else json.loads(get(f"https://api.github.com/repos/{REPO}/commits/main"))["sha"]
def read(sha, path):
    return open(os.path.join(SRC, path), "rb").read() if SRC else get(f"https://raw.githubusercontent.com/{REPO}/{sha}/{DIR}/{path}")
def installed():
    p = os.path.join(STATE, "manifest.json")
    return json.load(open(p)) if os.path.exists(p) else {"version": None, "skills": []}
def split(text):  # frontmatter name and folded description, then the body
    m = re.match(r"---\nname: (.+)\ndescription: >-\n((?:  .*\n)+)---\n", text)
    if not m: sys.exit("BAD_SKILL_FILE")
    return m.group(1).strip(), " ".join(l.strip() for l in m.group(2).splitlines()), text[m.end():]
cmd = sys.argv[1] if len(sys.argv) > 1 else "check"
sha = commit(); new = json.loads(read(sha, "manifest.json")); old = installed()
was = {s["id"]: s["sha256"] for s in old["skills"]}; now = {s["id"]: s for s in new["skills"]}
changed = [i for i in now if was.get(i) != now[i]["sha256"]]
removed = [i for i in was if i not in now]
if cmd == "check":
    print(json.dumps({"installed": old["version"], "latest": new["version"], "commit": sha[:12], "changed": changed, "removed": removed}))
elif cmd == "fetch":
    out = os.path.join(STATE, "pending"); files = {}
    for i in changed:
        data = read(sha, now[i]["path"])
        if hashlib.sha256(data).hexdigest() != now[i]["sha256"]: sys.exit(f"HASH_MISMATCH {i}")
        files[i] = data.decode()
    os.makedirs(out, exist_ok=True)
    for f in os.listdir(out): os.remove(os.path.join(out, f))
    order = sorted(files, key=lambda i: (i != "ao-rules", i == "ao-update", i))
    for i in order:
        name, desc, body = split(files[i])
        json.dump({"name": name, "description": desc, "body": body}, open(os.path.join(out, i + ".json"), "w"))
    json.dump({"version": new["version"], "commit": sha, "apply": order, "manifest": new}, open(os.path.join(out, "PLAN.json"), "w"))
    print(json.dumps({"ready": order, "folder": out}))
elif cmd == "done":
    plan = json.load(open(os.path.join(STATE, "pending", "PLAN.json")))
    json.dump(plan["manifest"], open(os.path.join(STATE, "manifest.json"), "w")); print("INSTALLED", plan["version"])
PY
}; f

2. Check (read-only, no yes needed)

`python3 /workspace/ao-bot/fetch.py check` prints the installed and latest version, the changed skills and any removed ones. `installed: null` means this bot was never updated here: every skill counts as changed, which is fine. Nothing changed: say it's up to date and stop. `DOWNLOAD_FAILED`: GitHub or the network didn't answer (a 404 means the skills aren't published at that path yet). Say so and try again later.

3. Show and ask once

One short message: installed and latest version, which skills changed, and any removed ones. Ask "Update to <latest>?".

4. On yes

1. `python3 /workspace/ao-bot/fetch.py fetch`. It downloads each changed skill, checks its sha256 against the manifest and, only if all match, writes one `<id>.json` per skill plus `PLAN.json` in `/workspace/ao-bot/pending/`. `HASH_MISMATCH <id>`: stop, change nothing, and tell the user. 2. Go through `PLAN.json` `apply` in order (ao-rules first, ao-update last). For each, call UpdateSkill with that json's `name`, `description` and `body`: rewrite the existing skill of that name, or create it if it doesn't exist. A subagent can't call UpdateSkill: the main agent does this step. 3. `python3 /workspace/ao-bot/fetch.py done` records the new version as installed. 4. For each removed skill, ask "Delete <ids>?" and delete only after a separate yes. 5. Update "Orchestrator Bot version" in memory. Finish in one line: the version, and the skills updated, created and kept.

Read more
Ships withuntrivial-ai-agent-orchestrator

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.

Get the whole plugin