Files
tkmind_go/buzz/README.md
T
2026-08-26 21:29:34 +00:00

393 lines
15 KiB
Markdown

# Goose Buzz automation
These tools connect issues in `aaif-goose/goose` to the public Goose Buzz
community at `buzz.gdk.so`.
The setup uses two separate identities:
- **Github Manager** is a service identity. The scripts use its Nostr key to
create and manage issue channels, add members, post issue summaries, and sync
channel topics.
- **A managed bot**, currently **Doose**, is an agent identity run by Buzz
Desktop. It can review an issue when Github Manager explicitly mentions it.
Github Manager owns the channels it creates. The checked-in core team is also
added so people can find and manage them in Buzz Desktop.
## Requirements
- Node.js
- [GitHub CLI](https://cli.github.com/) authenticated with access to the
repository and its project board; the recipe also needs permission to assign
issues
- Buzz Desktop on macOS, or a `buzz` CLI on `PATH`
- Goose CLI with a configured model provider
- A running public Buzz community
The scripts use `https://buzz.gdk.so` by default. Set `BUZZ_RELAY_URL` to target
another community. Set `BUZZ_BIN` or `GH_BIN` to override CLI discovery.
The community and issue channels are public. Confirm that a new Nostr identity
can join the community before relying on these scripts; relay configuration
names have changed between Buzz releases, so use the controls provided by the
deployed version rather than copying old allowlist environment variables.
## Set up a new installation
### 1. Create Github Manager
Run:
```sh
./buzz/create_github_manager
```
The script:
1. Generates a dedicated Nostr key pair.
2. Stores the keys outside the repository.
3. Uploads `assets/GithubManager.png`.
4. Publishes a Buzz profile named `Github Manager`.
The identity is stored in:
```text
$GOOSE_BUZZ_HOME/github-manager
```
`GOOSE_BUZZ_HOME` defaults to `$XDG_CONFIG_HOME/goose/buzz`, or
`~/.config/goose/buzz` when `XDG_CONFIG_HOME` is not set. The identity directory
is mode `0700`; its files are mode `0600`.
The important files are:
```text
private-key.nsec Secret key used by the scripts
public-key.npub Shareable Nostr public key
public-key.hex Shareable public key used by the Buzz CLI
profile-created Time at which the profile was published
```
The command is deliberately idempotent. If all three key files and the profile
marker exist, it fixes their permissions and changes nothing. If the keys exist
without the marker, it publishes the profile again without replacing the
identity. If only part of the key pair exists, it stops rather than silently
replacing the identity.
Back up the entire `github-manager` directory in a secure password or secrets
manager. The private key cannot be recovered from Buzz. Anyone with it can act
as Github Manager.
### 2. Create and run a bot
Create at least one managed agent in Buzz Desktop. The bot must have its own
Nostr identity; do not reuse the Github Manager key. Start the agent and make
sure it shows as online.
The channel script adds the bot to new channels, but membership alone does not
let Github Manager instruct it. Buzz agents default to accepting instructions
only from their human owner.
### 3. Allow Github Manager to instruct the bot
In Buzz Desktop:
1. Open **Agents**.
2. Select the bot, such as **Doose**.
3. Choose **Edit agent**.
4. Expand **Advanced**.
5. Change **Who can send instructions** to **Selected people**.
6. Search for **Github Manager** and choose **Add**.
7. Save the agent and restart it if Buzz does not restart it automatically.
This permission is security-sensitive. A selected identity can instruct the
agent to use the computer, files, accounts, and connected tools available to
that agent. Keep the list narrow. Do not choose **Anyone** just because the
community itself is public.
To verify the permission, send a message as Github Manager with both readable
mention text and the bot's public key:
```sh
export BUZZ_PRIVATE_KEY="$(cat ~/.config/goose/buzz/github-manager/private-key.nsec)"
export BUZZ_RELAY_URL=https://buzz.gdk.so
BUZZ_CLI="${BUZZ_BIN:-/Applications/Buzz.app/Contents/MacOS/buzz}"
"$BUZZ_CLI" messages send \
--channel <channel-uuid> \
--content "@Doose reply with OK" \
--mention <doose-public-key-hex>
```
A literal `@Doose` without the `--mention` public key may be rendered as text
without waking the remote agent. The successful command returns the bot key in
`mention_pubkeys`. The bot may take a minute or two to respond.
### 4. Configure the core team
`core-team.json` defines the people added to every new issue channel. Each
person has a display name, GitHub handle, stable Buzz public key, and an
`interest` list of topics they know about, based on their typical public issue
and pull-request work. `capacity` sets that person's target share of new
assignments; most people are `1` and Filip is `0.5`. A person can also have a
`bots` mapping from bot display name to bot public key. Adding that person adds
those identities with the Buzz `bot` role.
The current roster is:
- Douwe Osinga as an owner
- Doose as their bot
- Alex Hancock as a member
- filip as a member
- jasper as a member
- Mic as a member
- lifei as a member
- Lifei goose agent as their bot
- Jack Amadeo as a member
Edit the checked-in file when the permanent team changes. Set
`BUZZ_CORE_TEAM_FILE` to use a different roster file for another installation.
Use `--no-core-team` for a one-off channel that should not receive the standard
people. If a person from the file is then supplied explicitly with `--owner` or
`--person`, their associated bots are still included.
## Tools
### `create_github_manager`
Creates the Github Manager key pair and profile as described above. It has no
arguments and never rotates an existing identity.
```sh
./buzz/create_github_manager
```
### `create_issue_channel`
Reads a GitHub issue, creates a permanent open stream, sets its initial topic to
`⚪ GitHub phase: Inbox`, adds owners, people, and bots, and posts the supplied
summary with a link to the issue. It does not modify the GitHub issue.
```sh
./buzz/create_issue_channel 12345 \
--summary "Why the issue matters and what needs to be decided." \
--person "Issue Reporter"
```
The owners and members in `core-team.json` and their associated bots are added
by default. Repeat `--owner`, `--person`, or `--bot` to add more identities.
Each command-line value can be an exact Buzz display name or a 64-character
hexadecimal public key. People receive the `member` role and bots receive the
`bot` role.
Use `--repo owner/repo` for a repository other than `aaif-goose/goose`. A full
GitHub issue URL also works. For a multiline summary, use `--summary-file path`
or pipe the text with `--summary-file -`.
The command prints the issue, channel, message, and participant details as JSON.
Channel names use `#<issue-number> <issue-title>` in the Buzz UI. The script
refuses to create a duplicate when an active or archived channel already
matches the issue number. For an existing channel, explicitly supplied owners,
people, and bots are added without posting the summary a second time. An
archived matching channel is unarchived before its roster is updated. If setup
of a new channel fails after creation, the incomplete channel is deleted so the
next run can retry it.
Adding a bot does not trigger it. After the channel is created, Github Manager
must send a new message with an explicit bot mention:
```sh
"${BUZZ_BIN:-/Applications/Buzz.app/Contents/MacOS/buzz}" messages send \
--channel <channel-uuid> \
--content "@Doose review this issue and post your assessment in this channel." \
--mention <doose-public-key-hex>
```
### `list_issue_work`
Lists issues in the project's Inbox that need an owner or channel, and open
issues linked from the Buzz `issues to add` channel. An assigned Inbox issue
without a channel is included so a failed channel creation can be retried. A
queue entry can contain a Goose issue or pull request URL, or just `#<issue
number>`. Queue entries with an existing issue channel are treated as processed.
Pull request links resolve to their issue when GitHub reports exactly one
closing issue. The JSON also includes the core team, GitHub handles, Buzz public
keys, interests, and assignment capacity so a Goose recipe can select an owner.
`recent_assignment_load` counts core-team assignees across the 100 most recently
created issues, including closed issues. Phase and issue age do not affect the
count. It does not change GitHub or Buzz.
```sh
./buzz/list_issue_work
```
The project defaults to `aaif-goose` project 1. Use `--repo`,
`--project-owner`, `--project-number`, and `--queue-channel` for another
installation. The command fails instead of returning a partial list when the
project, channel, or message limits are reached. Queue links that cannot be
resolved are reported separately instead of guessed. A new installation must
create one Buzz channel with the configured queue name before running the
recipe.
Only the 20 most recent issue or pull-request links in the queue are considered.
Conversation without GitHub links does not consume that limit. Use
`--queue-count` to change it. Older links are reported with
`outside-recent-window`; messages without a valid timestamp are reported with
`invalid-created-at`.
Queue authors are only returned as `queue_requesters` when their public key is
present in `core-team.json`. Other authors are reported as
`ignored_queue_requesters` and cannot influence channel membership.
### `syncissues`
Fetches all open GitHub issues and all Buzz channels, matches issue channels by
the GitHub URL in their description, and synchronizes the project phase and
assignees to the channel topic. Active and archived channels use the same
matching rules. Legacy number-only channels are checked against GitHub so pull
request channels are reported and skipped instead of being treated as closed
issues. When more than one name points at an issue, an explicit GitHub issue URL
in the channel description wins over a legacy or bare numeric name:
| GitHub phase | Buzz topic marker |
| --- | --- |
| Inbox | ⚪ |
| Needs info | 🟡 |
| Accepted / design | 🟣 |
| Ready | 🟢 |
| Verification | 🔵 |
| Done | ✅ |
Topics use this format:
```text
🟢 Ready -- assigned to: @github-handle
```
Multiple assignees are comma-separated. Issues without an assignee say
`assigned to: unassigned`.
Issue channels without a corresponding open GitHub issue get the topic
`✅ GitHub issue: Closed` and are archived. If an issue reopens, its channel is
unarchived even when it has no project status; its project phase is restored
when available. Other Buzz channels are ignored.
The script also checks for new replies from people outside the repository.
GitHub authors associated as `OWNER`, `MEMBER`, or `COLLABORATOR` are considered
internal; other human users are considered outsiders. For each new outsider
reply on an open issue with a matching channel, Github Manager mentions the
issue's core-team assignee and posts the author name and a link to the GitHub
comment. The comment body is deliberately not copied into Buzz, so comment text
cannot inject mentions or bot instructions.
The `Snoozed until` date comes from the GitHub project. Once that date arrives,
Github Manager posts `@owner, the snooze is expired.` to the matching channel.
Each issue is notified once per snooze date. Changing the date permits a new
notification when the new date arrives.
The first non-dry run initializes a repository-specific cursor without posting
historical replies. Later successful runs advance it. The cursor is stored next
to the Github Manager key as
`issue-comment-sync-<owner>-<repository>.json`, with mode `0600`. A dry run reads
the cursor and reports `would-notify` actions without posting messages or
advancing it.
Run the local Buzz checks with `just test-buzz`. The same checks run in GitHub
Actions when the Buzz automation changes.
Snooze notifications have a separate
`issue-snooze-sync-<owner>-<repository>.json` state file in the same directory.
Always inspect a dry run first:
```sh
./buzz/syncissues --dry-run
./buzz/syncissues
```
The script checks that neither the GitHub issue list nor the Buzz channel list
was truncated before changing channels. Raise `--limit` if it stops at the Buzz
limit. Use `--repo`, `--project`, `--project-owner`, or `--project-number` to
target another repository or project.
### `github_issue_manager.yaml`
This Goose recipe manages the full Inbox loop:
1. List unassigned Inbox issues and unresolved work from `issues to add`.
2. Read each issue and rank the three strongest matches based on `interest`.
3. Choose the least loaded of those three using assignments on the 100 newest
issues, adjusting only for the person's configured capacity.
4. Assign the issue to that person's GitHub handle.
5. Create a focused Buzz channel, or promote the owner when the channel already
exists. Start with Douwe and the issue owner, then add relevant people until
the channel has at least three distinct humans. If Douwe owns the issue, two
others are required. A fourth person may be added when useful.
6. Run `syncissues`.
Issue bodies and comments are treated as untrusted data. The recipe is allowed
to assign issues but is instructed not to edit bodies, post GitHub comments,
change project fields, labels, or issue state.
Run it once with:
```sh
goose run \
--recipe "$PWD/buzz/github_issue_manager.yaml" \
--params "automation_dir=$PWD/buzz" \
--no-session
```
Preview assignments without changing GitHub or Buzz:
```sh
goose run \
--recipe "$PWD/buzz/github_issue_manager.yaml" \
--params "automation_dir=$PWD/buzz" \
--params "dry_run=true" \
--no-session
```
### `run_hourly`
Runs the recipe, waits an hour after it finishes, and repeats. Override the wait
with `BUZZ_MANAGER_INTERVAL_SECONDS`.
```sh
./buzz/run_hourly
```
The dedicated machine must stay awake and have working Goose, `gh`, and Buzz
CLI configuration. This runner does not require Goose's scheduler.
## Move or recover the setup
To move Github Manager to another machine, copy its complete identity directory
over a trusted encrypted connection. This moves the manager key and the sync
cursors without copying a human or bot identity:
```text
~/.config/goose/buzz/github-manager
```
On the destination, preserve the directory as `0700` and its files as `0600`,
then run `create_github_manager` to confirm that it finds the identity. Also
install and authenticate `gh`, install and configure Goose, and install Buzz
Desktop or configure `BUZZ_BIN`.
Do not copy Buzz Desktop's application-data directory. The hourly workflow only
needs Github Manager's key. Doose can keep running on the original machine, or
a separate bot identity can be created on the dedicated machine later.
Running `create_github_manager` with an empty identity directory creates a new
identity, not a replacement copy of the old one. If the old private key is lost:
1. Generate a new Github Manager identity.
2. Add the new identity as an owner of channels that must remain manageable.
3. Replace the old Github Manager entry in every bot's **Selected people** list.
4. Remove the old identity where possible.
5. Store a secure backup of the new key.
Existing channel events remain signed by the old identity; they cannot be
re-signed by the new one.