fix(scripts): copy global-agent-config.json in buzz-adopt-prod-agents (#7303)

## What

Extend `scripts/buzz-adopt-prod-agents.sh` to copy
`agents/global-agent-config.json` from the prod app-data store to dev as
part of the existing atomic bundle commit, and document what the script
cannot copy (baked build-time defaults).

## Why

`global-agent-config.json` holds the owner's global agent defaults
(`env_vars`, `provider`, `model`, `preferred_runtime`). Previously the
script carried the dev copy across verbatim — it was absent from the
bundle drop list and not in `RECORD_FILES`. After a `just reset`, the
dev build inherited stale global defaults (or none at all) instead of
mirroring prod, inconsistent with how all other bundle files are
handled.

The "WHAT THIS DOES NOT DO" header lacked any mention of baked
build-time defaults, which are a separate (and common) source of
prod/dev parity confusion.

## Changes

- **`RECORD_FILES`** — add `global-agent-config.json`. The file has no
volatile fields (`GlobalAgentConfig` struct =
`env_vars`/`provider`/`model`/`preferred_runtime`), so it joins the
verbatim-copy path already used by `teams.json` — no new transform.
- **Stage-seed block** — add `global-agent-config.json` to the `rm -rf`
drop list so the prod overlay replaces it cleanly; remove its stale
mention in the "carried verbatim" comment.
- **Docs/comments** — update "4-file bundle" → "5-file bundle" in the
DMG concurrent-run warning and the step 2 comment; list the file
explicitly in the step 2 header comment.
- **"WHAT THIS DOES NOT DO" header** — add a bullet explaining that
baked build-time agent defaults (`BUZZ_BUILD_BUZZ_AGENT_PROVIDER` /
`BUZZ_BUILD_AGENT_ENV` via `option_env!` in `build.rs`) are compiled
into the binary, not stored in app-data. Includes the correct `just
production` invocation pattern and a `.env` warning.
- **Preflight symlink checks and dry-run output** iterate `RECORD_FILES`
and pick up the new entry automatically — no other changes needed.

Verified: `bash -n` clean, `shellcheck` clean, `--dry-run --force` shows
`[dry-run] stage global-agent-config.json (0600)` in the expected
position.

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
This commit is contained in:
Will Pfleger
2026-09-03 17:32:10 -04:00
committed by GitHub
parent 88687876f7
commit 8e7b275cb0

View File

@@ -34,6 +34,17 @@
# the post-reset empty-dev-keyring state) with the crash-safe
# marker-before-delete ordering already shipped. The plaintext file exists
# only until that first boot consumes it.
# - It does NOT copy baked build-time agent defaults. The prod DMG bakes a
# provider and default env vars at compile time via `option_env!` in
# `build.rs` (driven by `BUZZ_BUILD_BUZZ_AGENT_PROVIDER` and
# `BUZZ_BUILD_AGENT_ENV`). These are compiled into the binary, not stored in
# app-data — there is no file here to copy. Dev parity means setting those
# env vars when invoking the dev build:
# export BUZZ_BUILD_BUZZ_AGENT_PROVIDER="databricks_v2"
# export BUZZ_BUILD_AGENT_ENV=$'DATABRICKS_HOST=...\nDATABRICKS_MODEL=...'
# just production
# Do NOT add these to .env — `set dotenv-load := true` in the Justfile
# would bake them into every recipe in that checkout, including test runs.
#
# FLAGS
# --dry-run Print every action; write nothing.
@@ -70,7 +81,7 @@ KEYCHAIN_ACCT="${BUZZ_KEYCHAIN_ACCT:-secrets}"
DRY_RUN=0
FORCE=0
RECORD_FILES=(managed-agents.json personas.json teams.json)
RECORD_FILES=(managed-agents.json personas.json teams.json global-agent-config.json)
# --- helpers ----------------------------------------------------------------
say() { printf '%s\n' "$*"; }
@@ -251,7 +262,7 @@ if [[ ${#dev_blocking[@]} -gt 0 ]]; then
fi
if [[ $dmg_running -eq 1 ]]; then
info "installed DMG is running — allowed (read-only source)"
warn "Do NOT create/archive agents or edit teams in the DMG while this runs; the 4-file bundle is read as one snapshot."
warn "Do NOT create/archive agents or edit teams in the DMG while this runs; the 5-file bundle is read as one snapshot."
else
info "no running Buzz process detected"
fi
@@ -326,8 +337,9 @@ if [[ $DRY_RUN -eq 0 && -d "$DEV_DIR/agents" ]] && ! have python3; then
fi
# --- step 2: restore records (exact bundle, one atomic commit) --------------
# The four boot-critical paths (managed-agents.json, personas.json, teams.json,
# teams/) are read as one related state, so the commit must be all-or-nothing.
# The five boot-critical paths (managed-agents.json, personas.json, teams.json,
# global-agent-config.json, teams/) are read as one related state, so the
# commit must be all-or-nothing.
# Phase 1 builds a COMPLETE replacement agents/ in a staging dir beside the live
# one — the prod bundle plus any unrelated live entries carried across verbatim,
# every transform validated, zero live-path mutation. Phase 2 commits it in ONE
@@ -372,16 +384,17 @@ else
STAGE_TEMPS+=("$stage_agents")
# Seed the stage with the entire live agents/ (a single checked copy — under
# `set -e` a partial copy aborts before any commit), then drop the four bundle
# `set -e` a partial copy aborts before any commit), then drop the five bundle
# names FROM THE STAGE so the prod overlay below replaces them cleanly. Any
# other live entry (logs/, agent-pids/, global-agent-config.json, retention
# stores, …) is carried across verbatim and preserved by the directory swap.
# other live entry (logs/, agent-pids/, retention stores, …) is carried across
# verbatim and preserved by the directory swap.
if [[ -d "$DEV_DIR/agents" ]]; then
cp -Rp "$DEV_DIR/agents/." "$stage_agents/"
rm -rf -- \
"$stage_agents/managed-agents.json" \
"$stage_agents/personas.json" \
"$stage_agents/teams.json" \
"$stage_agents/global-agent-config.json" \
"$stage_agents/teams"
fi