Collapses the operator setup from an 8-flag command + two hand-written scripts to essentially two commands, without removing any of the safety. - `buzz workflow run` gains `--accept-from-channel` (parity with the job scheduler): scope intake to the channel's kind-39002 roster instead of pasting every teammate key. `--worktree` now defaults to the current directory. - Ship the gated reference wrappers (tools/buzz-agent/workflow-agent.sh → agent+commit; workflow-ship.sh → push+PR after the gate), split around the approval gate the way agent-exec.sh is the one-shot ungated version. - `buzz agent up RELAY --repo DIR --approver NPUB` — one command: resolves the channel (the relay's only one, or --channel), defaults worktree/intake, extracts the bundled wrappers to ~/.amy/buzz-agent, and delegates to `workflow run`. The only thing it can't default is the human approver. - `buzz agent doctor [--repo DIR]` — preflight that turns the security checklist into a green/red report: gh authenticated, token can write to the repo, default branch protected against force-push, worktree clean. Exits non-zero if not. - cli build: set duplicatesStrategy on processResources (the explicit resources.srcDir re-adds the default root, which now doubles the bundled scripts). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011mApqAbr8vkLC7gUDjavu6
5.3 KiB
Buzz agent --exec wrapper
agent-exec.sh is the reference command you point amy buzz agent serve --exec at to turn
Buzz job requests into pull requests. It runs a coding agent (Claude Code by default) on the
task inside the job's isolated git worktree, then commits, pushes the job branch, and opens a
PR — printing the PR URL as the job result. It never touches the default branch and never
force-pushes; the merge is a human action on GitHub.
See the design in cli/plans/2026-07-25-buzz-agent-support-channel.md.
The contract (how the scheduler calls it)
| Channel | Meaning |
|---|---|
| stdin | the task text (the kind-43001 request) |
| cwd | the job's git worktree — a fresh branch off --base-ref |
| env | BUZZ_JOB_ID BUZZ_REQUESTER BUZZ_CHANNEL BUZZ_RELAY BUZZ_AGENT BUZZ_UPVOTES BUZZ_BRANCH BUZZ_WORKTREE BUZZ_BASE_REF |
| stdout | becomes the job result (kind-43004) — the wrapper prints the PR URL |
| non-zero exit | becomes the job error (kind-43006); stderr is the detail |
Its steps: read task → run agent → verify a diff exists → commit → push the branch → open (or reuse) the PR → print the URL.
Two paths: gated vs direct
- Direct (ungated) jobs —
agent-exec.sh(this file's subject) does agent → commit → push → PR in one shot. Pointamy buzz agent serveat it. - Gated workflow runs — the work pauses on a human-approval gate before anything ships, so it's
split into two steps around the gate:
workflow-agent.sh(the--execstep: agent → commit, no push) andworkflow-ship.sh(the--on-approvestep: push → PR, runs only after a human grants). Pointamy buzz workflow runat them.
The easy button: amy buzz agent up
For the gated path you don't need to wire any of this by hand. amy bundles workflow-agent.sh +
workflow-ship.sh and runs them for you:
amy buzz agent up wss://your-buzz-relay --repo /path/to/your/checkout --approver npub1you…
It resolves the channel (the relay's only one, or pass --channel), defaults the worktree to
--repo, scopes intake to the channel roster (--accept-from-channel), and extracts the wrappers to
~/.amy/buzz-agent/ (edit them there to customize, or pass your own --exec/--on-approve). Before
first run, check the host is safe:
amy buzz agent doctor --repo /path/to/your/checkout # gh token scope + branch protection + clean tree
Usage (manual / direct path)
amy buzz agent serve wss://your-buzz-relay <channel-uuid> \
--exec /path/to/tools/buzz-agent/agent-exec.sh \
--worktree /path/to/amethyst \
--accept-from-channel \
--parallel 2
The bundled copies agent up extracts live in cli/src/main/resources/buzz-agent/; the copies here
in tools/buzz-agent/ are the readable, customizable reference (same content).
--worktree is required (the wrapper needs BUZZ_BRANCH/BUZZ_WORKTREE). --parallel N
runs N jobs at once, each in its own worktree+branch.
Config knobs (env)
| Var | Default | Purpose |
|---|---|---|
AGENT_CMD |
(unset) | Override the whole agent invocation. Receives the prompt on stdin and as $AGENT_PROMPT. Use this for Goose/Codex or a custom runner. |
AGENT_ALLOWED_TOOLS |
Edit,Write,Read,Bash,Glob,Grep |
Claude Code --allowedTools — the agent's capability boundary. |
COMMIT_PREFIX |
feat |
Prefix for the auto-commit subject when the agent didn't commit. |
Adjust the default claude -p … --permission-mode acceptEdits --allowedTools … line to match
your Claude Code version, or bypass it entirely with AGENT_CMD.
Security — the guardrails that make this safe
Buzz authorizes by identity, not capability flags, so none of the "can't merge or destroy
main, can't code other things" guarantees come from Buzz. They come from three things you
configure here:
- A PR-only git credential. Authenticate
ghon the agent host with a fine-grained PAT scoped to theamethystrepo only, granting exactly Contents: Read and write + Pull requests: Read and write — and nothing else. No Administration, no org scope. The token can open PRs on feature branches; it cannot merge, bypass checks, or reach other repos. - Branch protection on the default branch. Protect
main: require a pull request, require review approval, require status checks (CI) to pass, and block force-pushes and branch deletion. Do not grant the bot an exception. This is what actually stops a bad merge — the wrapper only ever pushesclaude/job-*feature branches. - Scoped intake + agent tools. Run the scheduler with
--accept-from/--accept-from-channelso only your team's keys can file jobs, keepAGENT_ALLOWED_TOOLStight, and run on a host whose checkout is amethyst only — so the agent "can't code other things."
The merge is deliberately outside this loop: a completed job's result is its PR, and a human merges it on GitHub.
Testing
agent-exec.sh is verified end-to-end against a throwaway repo with a stubbed gh + agent
(reads task → runs agent → commits the diff → pushes the feature branch → prints the PR URL;
and errors cleanly when the agent makes no changes). Point AGENT_CMD at a stub to dry-run the
git/PR plumbing without invoking a real agent.