Adds `scripts/buzz-adopt-prod-agents.sh`, which copies the installed-DMG
(production) agent records and owner identity into the dev app-data
store so a dev build boots as the **same agents and same owner npub** as
the installed app — surviving `just reset`.
## What it restores
`just reset` wipes the two things Buzz cannot re-derive:
- The agent **records** — `managed-agents.json`, `personas.json`,
`teams.json`, and `agents/teams/`.
- The **owner identity** nsec, written as `identity.key` (0600, atomic).
Agent private keys and identity-key adoption then happen automatically
on the next dev boot via the shipped in-app migrations.
## When to run it
1. Quit any running **dev** build. A running installed DMG is fine — the
script treats it as a read-only source and only warns against
creating/archiving agents or editing teams while it runs. It never kills
processes.
2. Run `just reset`.
3. Before the first dev boot, run `bash
scripts/buzz-adopt-prod-agents.sh`.
- `--dry-run` prints every action with zero writes.
- `--force` overwrites an already-populated dev store.
- One keychain prompt is expected (reading the prod owner identity).
4. Start the dev build. First boot copies the agent keys prod→dev and
adopts `identity.key`, then deletes it. For worktree launches, export
`BUZZ_SHARE_IDENTITY=1` (and `BUZZ_PRIVATE_KEY`) or the worktree mints
its own duplicate agents.
## Running-process check
Only a running **dev** build blocks the run: the script atomically swaps
the entire dev `agents/` directory and stages `identity.key` for the
next dev boot to consume, so doing that under a live dev process is the
corruption the check must prevent. A running installed DMG is allowed —
the app writes `managed-agents.json` via tmp+atomic-rename, so it can
never hand the script a torn file. Each matching `buzz-desktop` PID is
classified by its true post-exec executable path (via `lsof -d txt`,
which reports the running vnode with symlinks already resolved); the
installed `/Applications/Buzz.app/Contents/MacOS/buzz-desktop` path is
the only allow. Anything else still alive blocks fail-closed; a PID that
exits before its path can be resolved is ignored.
## Requirements
Requires `python3` when a dev `agents/` already exists — it drives the
`renamex_np(RENAME_SWAP)` syscall bash cannot call. The script fails in
preflight with a clear message if `python3` is absent, never mid-commit.
## Safety
Prod is strictly read-only; symlinked or aliased prod/dev roots are
refused before any write. The records/identity restore commits in one
atomic operation (`renamex_np(RENAME_SWAP)` when a dev store exists, a
single `mv` when absent) that fails closed — a crash or I/O error leaves
`agents/` either fully old or fully new, and unrelated live dev state
(`logs/`, `agent-pids/`, `global-agent-config.json`, retention stores)
is preserved verbatim across the swap.
This is a temporary measure while we trial it and decide whether to port
the logic into the dev-build startup path.
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>