Skip to content

refactor(teams): unify team model and kill directory-backed team layer#1846

Open
wpfleger96 wants to merge 3 commits into
mainfrom
duncan/team-instructions-first-class
Open

refactor(teams): unify team model and kill directory-backed team layer#1846
wpfleger96 wants to merge 3 commits into
mainfrom
duncan/team-instructions-first-class

Conversation

@wpfleger96

Copy link
Copy Markdown
Collaborator

Summary

Collapses two parallel team systems — directory-backed packs and JSON-store teams — into one unified model where team instructions are a first-class field layered at runtime, and snapshots replace directory-based team sharing.

What changed

Unified team model with first-class instructions

  • TeamRecord.instructions: Option<String> replaces the old pattern of baking pack instructions into each member's system_prompt via compose_prompt.
  • team_id: Option<String> on ManagedAgentRecord binds deployed instances to their team, resolving the multi-team-persona ambiguity (a persona in 3 teams deployed 3× = 3 instances, 3 team_ids).
  • instructions field is projected onto the relay kind:30176 event, synced inbound, and wired through create/update request types + TeamDialog editor UI.

Runtime [Team Instructions] section

  • New with_team() in pool.rs inserts a [Team Instructions] section between [System] and [Agent Memory — core], consistent with how base, core memory, and canvas are already layered.
  • Both modern (protocol_version >= 2, pool.rs) and legacy (user-message sections, queue.rs) prompt paths carry it.
  • Fed by BUZZ_ACP_TEAM_INSTRUCTIONS env var, resolved from the instance's team_id → local TeamRecord.instructions at spawn. Editing team instructions rehashes → restart (same discipline as effective_spawn_prompt).

Boot migration (T4)

  • Idempotent detach_directory_backed_teams step (after backfill_standalone_agents): lifts instructions.md text to TeamRecord.instructions, backfills team_id on ManagedAgentRecords, clears source_dir/is_symlink/symlink_target/version/persona_team_dir/persona_name_in_team.
  • Second boot detaches zero — idempotency verified by test.

Team snapshot parity (T5)

  • TeamSnapshotMeta carries instructions; export accepts caller-supplied MemoryLevel (PNG format forces None per the shared-image plaintext guard).
  • confirm_team_snapshot_import mints per-member keypairs + ManagedAgentRecords with two-phase all-or-none atomicity: validate all → mint keypairs/auth-tags in memory → single store-lock write of all AgentDefinitions + ManagedAgentRecords (with team_id) + TeamRecord → profile sync → memory restore with per-member error reporting. Failing member N leaves zero local records.

Deleted: entire directory-backed team file layer (T6)

  • Rust: writeback.rs module (1152 lines), persona_card.rs, 5 Tauri commands (install_team_from_directory, sync_team_directory, pick_team_directory, export_team_to_json, parse_team_file), parse_team_from_pack_zip, directory install/sync helpers, old migration functions (migrate_packs_to_teams, reconcile_persona_team_dirs, sync_team_personas).
  • TypeScript: TeamImportDialog, TeamImportUpdateDialog, teamImportPlan, teamImportUpdateState + tests, old useTeamActions handlers (export/import/install/sync/reveal), old tauriTeams bindings, TeamsSection file-import UI (drag zone, Export/Sync/Reveal/Install buttons).
  • BUZZ_ACP_PERSONA_PACK/BUZZ_ACP_PERSONA_NAME env vars + config.rs pack re-resolve branch + spawn_hash.rs pack-fallback suppression exception.

User-facing behavior change

Directory-backed team packs (installed from local directories or imported from .zip files) are superseded by the unified team model. Existing directory-backed teams are silently migrated on next app launch — they become standard relay-synced teams with their instructions preserved as a first-class field. The directory install, sync, and export-to-flat-JSON workflows are removed; team sharing is now exclusively via .team.json/.team.png snapshots (matching the agent snapshot flow).

Collapse two parallel team systems (directory-backed packs and JSON-store
teams) into one unified model where team instructions are a first-class
field layered at runtime, and snapshots replace directory-based sharing.

The pack/directory layer baked team instructions into each member's
system_prompt at resolve time, creating N identical copies and requiring
reverse-parsing to recover the raw body. The unified model stores
instructions once on TeamRecord and layers them as a discrete
[Team Instructions] section at spawn — consistent with how base, core
memory, and canvas are already layered.

Key changes:
- team_id binding on ManagedAgentRecord for instance→team resolution
- instructions field on TeamRecord with relay kind:30176 projection
- [Team Instructions] runtime section in both modern and legacy paths
- Boot migration: lifts instructions.md, backfills team_id, detaches
  directory-backed teams (clears source_dir/is_symlink/symlink_target/
  version/persona_team_dir/persona_name_in_team)
- Team snapshot import mints per-member keypairs + ManagedAgentRecords
  with two-phase all-or-none atomicity and memory restore
- Deletes: writeback module, persona_card, 5 old Tauri commands,
  pack-ZIP parsing, directory install/sync, TeamImportDialog,
  TeamImportUpdateDialog, and all associated test/state/plan files
@wpfleger96 wpfleger96 requested a review from a team as a code owner July 14, 2026 03:16
…, and dead code

T4: migration detach now uses atomic_write_json_restricted / atomic_write_json
instead of raw std::fs::write, ensuring a mid-write crash leaves the prior
valid JSON intact and the idempotency gate open for retry.

T5: team snapshot import Phase 3 snapshots the raw agent store before writes
and rolls back on partial failure — save_managed_agents or save_teams errors
restore the pre-import state. retain_*_pending calls moved after all writes
succeed to avoid spurious in-memory state on rollback.

F4: removed unreachable legacy import path from TeamDialog.tsx (file picker,
drag listeners, import state, handlers) and deleted teamDialogImportState
module + tests.

Deleted migrate_packs_to_teams_* husk tests that reimplemented deleted
production logic. Deleted #[cfg(test)] filter_derived_provider_model_env_vars
wrapper and its tests. Updated stale team-pack suppression comment in
runtime.rs.
The import store phase now snapshots both files (or notes them absent)
before writing, cleans minted keyring entries on failure via a new
result-returning try_delete_agent_key seam, and aggregates rollback
errors alongside the original write failure. Process death between
commits is explicitly outside contract.

Also: delete stale packs-migration test husk and section header,
replace duplicate idempotency test with write-seam interruption test,
fix event_sync.rs prerequisite comment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant