Created
August 5, 2026 17:58
-
-
Save imikerussell/cc4f30f1741812c2d345719889617769 to your computer and use it in GitHub Desktop.
Make ONE Buzz agent answer you without an @-mention from ANYWHERE!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # buzz-untag — make ONE Buzz agent answer you without an @-mention. | |
| # | |
| # buzz-untag.sh <AgentName> wire it up | |
| # buzz-untag.sh --undo <AgentName> put everything back | |
| # | |
| # Every change is per-agent. No other agent is touched, and no file is shared. | |
| set -euo pipefail | |
| UNDO=0 | |
| if [ "${1:-}" = "--undo" ]; then UNDO=1; shift; fi | |
| AGENT_NAME="${1:-}" | |
| # --- where Buzz keeps its data, per OS ------------------------------------- | |
| case "$(uname -s)" in | |
| Darwin) APPDIR="$HOME/Library/Application Support/xyz.block.buzz.app" | |
| BIN="/Applications/Buzz.app/Contents/MacOS/buzz-acp" ;; | |
| Linux) APPDIR="$HOME/.local/share/xyz.block.buzz.app" | |
| BIN="$(command -v buzz-acp || echo /usr/bin/buzz-acp)" ;; | |
| MINGW*|MSYS*|CYGWIN*) | |
| APPDIR="${APPDATA:-$HOME/AppData/Roaming}/xyz.block.buzz.app" | |
| BIN="$(command -v buzz-acp || echo buzz-acp)" ;; | |
| *) echo "Unrecognised OS: $(uname -s)"; exit 1 ;; | |
| esac | |
| AGENTS="$APPDIR/agents/managed-agents.json" | |
| [ -f "$AGENTS" ] || { echo "Can't find Buzz's agent list at:"; echo " $AGENTS"; exit 1; } | |
| NEST="${BUZZ_NEST:-$HOME/.buzz}" | |
| # --- pick the agent --------------------------------------------------------- | |
| if [ -z "$AGENT_NAME" ]; then | |
| echo "Agents on this machine:" | |
| python3 - "$AGENTS" <<'PYEOF' | |
| import json,sys,collections | |
| by=collections.defaultdict(int) | |
| for r in json.load(open(sys.argv[1])): | |
| if r.get("pubkey"): by[r["name"]]+=1 | |
| for n,c in sorted(by.items()): | |
| print(f" {n}" + (f" ({c} identities)" if c>1 else "")) | |
| PYEOF | |
| printf "\nWhich agent? " | |
| read -r AGENT_NAME < /dev/tty | |
| fi | |
| SLUG=$(printf '%s' "$AGENT_NAME" | tr '[:upper:]' '[:lower:]' | tr -cd '[:alnum:]') | |
| TOML="$NEST/buzz-acp-$SLUG.toml" | |
| WRAPPER="$NEST/scripts/buzz-acp-untagged-$SLUG.sh" | |
| STATE="$NEST/.buzz-untag-$SLUG.json" | |
| # --- check the agent exists BEFORE we close anything ------------------------ | |
| python3 - "$AGENTS" "$AGENT_NAME" <<'PYEOF' | |
| import json,sys | |
| rows=json.load(open(sys.argv[1])) | |
| if not [r for r in rows if r.get("name")==sys.argv[2] and r.get("pubkey")]: | |
| sys.exit(f"No agent called '{sys.argv[2]}' on this machine. Nothing changed.") | |
| PYEOF | |
| if [ "$UNDO" = "1" ] && [ ! -f "$STATE" ]; then | |
| echo "Nothing to undo for $AGENT_NAME — no record at $STATE"; exit 1 | |
| fi | |
| # The app process is called buzz-desktop, not Buzz — and pgrep does not match it | |
| # at all, so we ask ps directly. Getting this wrong means we edit the agent list | |
| # while Buzz is still shutting down, and Buzz then writes its own copy back over us. | |
| buzz_running() { | |
| ps -Ao comm= | grep -q 'Buzz\.app/Contents/MacOS/buzz-desktop' | |
| } | |
| quit_buzz() { | |
| if [ "$(uname -s)" = "Darwin" ]; then | |
| osascript -e 'quit app "Buzz"' 2>/dev/null || true | |
| for _ in $(seq 1 30); do buzz_running || break; sleep 1; done | |
| if buzz_running; then | |
| echo "Buzz is still running after 30s — refusing to edit its settings, because it would just overwrite them." | |
| echo "Quit Buzz by hand (Cmd-Q), then run this again. Nothing has been changed." | |
| exit 1 | |
| fi | |
| sleep 2 # let it finish flushing managed-agents.json on the way out | |
| else | |
| printf "Close Buzz now, then press Enter. "; read -r _ < /dev/tty | |
| fi | |
| } | |
| open_buzz() { | |
| if [ "$(uname -s)" = "Darwin" ]; then open -a Buzz | |
| else echo "Reopen Buzz now."; fi | |
| } | |
| # ============================================================ UNDO ========== | |
| if [ "$UNDO" = "1" ]; then | |
| quit_buzz | |
| trap 'open_buzz' ERR | |
| cp "$AGENTS" "$AGENTS.backup-$(date +%Y%m%d-%H%M%S)" | |
| python3 - "$AGENTS" "$STATE" <<'PYEOF' | |
| import json,sys | |
| agents,state = sys.argv[1],sys.argv[2] | |
| st=json.load(open(state)) | |
| rows=json.load(open(agents)) | |
| by={r.get("pubkey"):r for r in rows if r.get("pubkey")} | |
| n=0 | |
| for rec in st["instances"]: | |
| r=by.get(rec["pubkey"]) | |
| if not r: continue | |
| r["acp_command"]=rec["prev_acp_command"] | |
| if rec.get("allowlist_added"): | |
| r["respond_to_allowlist"]=[p for p in r.get("respond_to_allowlist",[]) if p!=st["owner"]] | |
| n+=1 | |
| json.dump(rows,open(agents,"w"),indent=2) | |
| print(f"Restored {n} identity/identities.") | |
| PYEOF | |
| rm -f "$TOML" "$WRAPPER" "$STATE" | |
| trap - ERR | |
| open_buzz | |
| cat <<DONE | |
| Undone. $AGENT_NAME is back to mention-only, exactly as it was. | |
| Its rules file and wrapper are deleted. No other agent was touched. | |
| DONE | |
| exit 0 | |
| fi | |
| # ============================================================ WIRE ========== | |
| OWNER=$(python3 - "$AGENTS" <<'PYEOF' | |
| import json,sys | |
| for r in json.load(open(sys.argv[1])): | |
| if r.get("auth_tag"): | |
| print(json.loads(r["auth_tag"])[1]); break | |
| PYEOF | |
| ) | |
| [ -n "$OWNER" ] || { echo "Couldn't work out your pubkey. Is Buzz set up on this machine?"; exit 1; } | |
| mkdir -p "$NEST/scripts" | |
| cat > "$TOML" <<TOMLEOF | |
| # Rules for $AGENT_NAME only. No other agent reads this file. | |
| # Rule 1: anything from you, in any channel, no @-mention needed. | |
| [[rules]] | |
| name = "owner-direct" | |
| channels = "all" | |
| kinds = [9] | |
| require_mention = false | |
| filter = 'author == "$OWNER"' | |
| # Rule 2: everyone else still has to @-mention. Do not delete this. | |
| [[rules]] | |
| name = "everyone-else" | |
| channels = "all" | |
| kinds = [9] | |
| require_mention = true | |
| TOMLEOF | |
| cat > "$WRAPPER" <<WRAPEOF | |
| #!/usr/bin/env bash | |
| export BUZZ_ACP_SUBSCRIBE=config | |
| export BUZZ_ACP_CONFIG="$TOML" | |
| exec "$BIN" "\$@" | |
| WRAPEOF | |
| chmod +x "$WRAPPER" | |
| quit_buzz | |
| trap 'open_buzz' ERR | |
| cp "$AGENTS" "$AGENTS.backup-$(date +%Y%m%d-%H%M%S)" | |
| python3 - "$AGENTS" "$AGENT_NAME" "$WRAPPER" "$OWNER" "$STATE" <<'PYEOF' | |
| import json,sys | |
| agents,name,wrapper,owner,state = sys.argv[1:6] | |
| rows=json.load(open(agents)) | |
| hits=[r for r in rows if r.get("name")==name and r.get("pubkey")] | |
| if not hits: sys.exit(f"No agent called '{name}'. Nothing changed.") | |
| rec=[] | |
| for r in hits: | |
| added=False | |
| # If this agent only answers an allowlist, add yourself to it. Nobody is removed. | |
| if r.get("respond_to")=="allowlist": | |
| al=r.get("respond_to_allowlist") or [] | |
| if owner not in al: | |
| r["respond_to_allowlist"]=al+[owner]; added=True | |
| rec.append({"pubkey":r["pubkey"],"prev_acp_command":r.get("acp_command"),"allowlist_added":added}) | |
| r["acp_command"]=wrapper | |
| json.dump(rows,open(agents,"w"),indent=2) | |
| json.dump({"name":name,"owner":owner,"instances":rec},open(state,"w"),indent=2) | |
| print(f"Wired {len(hits)} identity/identities for {name}.") | |
| if any(x["allowlist_added"] for x in rec): | |
| print(" It only answered an allowlist, so you were added to it. Undo removes you again.") | |
| PYEOF | |
| trap - ERR | |
| open_buzz | |
| cat <<DONE | |
| Done. $AGENT_NAME will now answer you with no @-mention. | |
| Everyone else still has to mention it. No other agent changed. | |
| To put everything back exactly as it was: | |
| $0 --undo $AGENT_NAME | |
| DONE |
Author
can this work on windows?
Yes.
thanks. if i do this for all profiles, will i have a mess?
and how do i run it? i keep getting errors
Author
thanks. if i do this for all profiles, will i have a mess?
You can undo per agent with buzz-untag.sh --undo <AgentName>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
can this work on windows?