Title now names the template ("Delete Ned template?") and the body
spells out that only the saved template is removed — agents created
from it, and the agent it was saved from, are unaffected.
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Extract the pure cores of list_agent_templates (assemble_agent_templates)
and save_agent_as_template (upsert_template_persona) — behavior unchanged —
and pin them with unit tests: listing filters inactive and builtin-shadow
records and sorts saved templates case-insensitively after built-ins;
saving with an existing name updates the record in place (identity,
created_at, and stored env_vars preserved) instead of duplicating; a fresh
insert never carries credentials; and inactive or team-sourced records with
the same name are never hijacked. Also pin that an inbound persona echo
cannot resurrect a locally deactivated record — is_active is not a
projected field, so a stale relay echo leaves the local flag untouched.
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Save as template had no inverse: a saved template could never be removed
from the catalog. Add a Delete affordance to CreateAgentStartDialog for
saved templates — an outline button next to Use template, gated behind a
confirm AlertDialog matching TeamDeleteDialog. Deletion drives the
previously-unused useDeletePersonaMutation, which now also invalidates
agentTemplatesQueryKey so the catalog drops the row immediately; backend
validation errors (e.g. record still referenced by a team) surface in the
detail pane.
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
The agent-templates query pins staleTime: Infinity, so a saved template
created, edited, or tombstoned on another device never reached the New
Agent catalog until app restart. Invalidate agentTemplatesQueryKey in the
agents-data-changed listener alongside the other relay-backed queries.
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Clicking "Blank agent" or "Use template" froze the entire webview until
runtime discovery finished. The details dialog opens immediately, but on
mount it fires three Tauri commands that were synchronous — and Tauri 2
runs sync commands on the main thread, so the UI blocked while login
shells resolved each agent binary.
- desktop/src-tauri/src/commands/agent_discovery.rs: make
discover_acp_providers and discover_managed_agent_prereqs async and
move their shell-spawning work into tokio::task::spawn_blocking so
the main thread never blocks; both now return Result to surface a
panicked task instead of unwrapping
- desktop/src-tauri/src/commands/agent_providers.rs: same treatment
for discover_backend_providers, which scans every PATH directory on
disk for buzz-backend-* binaries
- desktop/src/features/agents/ui/CreateAgentDialog.tsx: show a spinner
in the submit button while discovery is pending, so the disabled
button reads as "loading" rather than broken
No frontend API changes needed — invokeTauri handles the Result return
transparently. Also fixes the same freeze anywhere these queries fire
(Edit Agent, Add Channel Bot, Settings > Doctor).
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Agents are now only ever minted explicitly through the Create Agent
wizard. Personas surface exclusively inside the New Agent catalog as
"saved templates" instead of rendering as cards on the Agents grid.
Remove the flatten/materialization migration:
- Delete managed_agents/flatten.rs and flatten_tests.rs — the boot-time
migration minted a fresh keypair for every active persona with no
linked agent, but keyed dedup on the persona_id link it erased itself,
so relay persona echoes from other builds (dev vs release, d-tag
drift) re-minted duplicate agents on every launch on both sides
- Remove the flatten_personas_into_agents boot hookup in lib.rs
- Remove materialize_pack_agents_locked from team pack install/sync in
commands/teams.rs — installing a pack now lands its personas in the
catalog without minting agents
Catalog = built-ins + saved templates:
- list_agent_templates merges static built-ins with active persona
records (store lock held, spawn_blocking), skipping records that
shadow a built-in id and sorting saved entries by display name
- AgentTemplate gains provider and source ("builtin" | "saved") on both
the Rust struct and the TS type; templateAgentDraft carries provider
through to the create form prefill
- CreateAgentStartDialog renders saved templates under a "Saved"
sidebar group; detail pane labels the type accordingly
"Save as template" on minted agents:
- New save_agent_as_template Tauri command maps an agent's pinned
config (name, instructions, avatar, runtime, model, provider — never
env_vars) onto a persona record; re-saving the same name updates the
existing template instead of duplicating; retained as kind:30175
pending relay sync so templates reach other devices
- AgentActionsMenu gains a "Save as template" entry wired through
UnifiedAgentsSection/AgentsView with success toast and
agent-templates/personas query invalidation
Tests:
- e2eBridge mocks the merged template list and save_agent_as_template
- agents.spec.ts covers the new menu entry and the save-as-template →
Saved group → detail pane flow
- Stale flatten references in persona/teams test comments cleaned up
873 Tauri unit tests, 69 Playwright tests, and the full just ci gate
pass.
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Restores the old Agent Catalog layout (PersonaCatalogDialog, removed in
24ff2034) for the New agent starting-point step, replacing the flat grid
of cards with a sidebar list + detail preview.
- CreateAgentStartDialog.tsx: rebuilt on ChooserDialogContent (h-168 /
max-w-4xl, bg-sidebar header). The left sidebar keeps "Blank agent"
and "Import from file" as immediate actions with their existing
testids, above a Templates list; clicking a template now selects it
for preview instead of advancing straight to the form. The right pane
shows the selected template's avatar, name, the Type / Preferred
model / Preferred runtime meta group, and the system prompt rendered
as non-interactive Markdown, with a floating "Use template" confirm
button (create-agent-start-use-template) over a gradient that hands
the template to the details step. Selection defaults to the first
template on open, list/detail skeletons cover loading, and the
drag-and-drop import overlay + hidden file input carry over from the
grid version. Props are unchanged so AgentsView needed no edits.
Tailwind classes use the current v4 lint forms (h-168, bg-linear-to-t)
instead of the old catalog's literals
- agents.spec.ts: the two template-selection tests click the template
row and then the new confirm button; blank/import flows in the other
suites are unchanged (all four affected suites pass)
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
- agents.spec.ts: rewritten around the new surface — wizard starting
points (blank / import / template), template prefill and submit,
duplicate prefill, agent card actions menu, team creation with agent
members, and the inactive-persona / team-referenced-persona guards via
the mock bridge
- mesh-compute.spec.ts, smoke.spec.ts: replace the retired
"New agent > Custom agent" menu path with the wizard's blank starting
point; the system prompt now fills the top-level agent-instructions
field instead of the Advanced section
- persona-env-vars.spec.ts: env-vars editor and model/provider tests
target the create-agent form (agent-runtime / agent-llm-provider ids)
- onboarding.spec.ts: the Fizz welcome guide is identified by name — no
persona_id backing record anymore
- config-bridge-screenshots.spec.ts: provenance copy is now
"Inherited from agent profile"
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Agents are now the only concept users touch. Persona records remain a
pack-internal primitive; nothing in the UI creates, lists, or edits them.
- Agents grid: UnifiedAgentsSection renders one card per managed agent in
a single flat grid with a new AgentActionsMenu (Edit, Duplicate, Add to
channel, Export, Remove). Persona-keyed grouping, persona cards, and
the persona profile-panel path are deleted (unifiedAgentGroups,
AgentGroupRows, ManagedAgentRow, PersonaActionsMenu, PersonaIdentity,
PersonaCatalog*, PersonaLibraryEntryPoints, usePersonaActions, and the
persona dialog state helpers)
- Create Agent wizard: new CreateAgentStartDialog (blank, built-in
template, or import from file) hands an AgentDraft to CreateAgentDialog;
submit only creates a managed agent — no persona record. PersonaDialog
is gone; batch import creates agents directly; the system prompt is a
top-level "Agent instructions" field with model/provider fields shared
via AgentModelProviderFields
- Duplicate opens the wizard prefilled from the source agent record's
pinned fields (prompt, model, provider, env vars, avatar, runtime)
- Teams: TeamDialog picks managed agents and stores pubkeys via the
unified TeamCardMember model (pack persona members render read-only);
TeamsSection, import/export, and AddTeamToChannelDialog resolve members
from agent_pubkeys plus pack persona_ids, deploying pack personas
through the existing persona path
- Channel deploy: AddChannelBotDialog lists managed agents
(AddChannelBotAgentsSection + useInChannelAgentPubkeys) and attaches
existing agents instead of spawning persona instances; QuickBotBar and
the persona section/runtime-override helpers are deleted. The dialog
also prevents open-autofocus: focus landing on the first agent chip
opened its tooltip, so the first Escape dismissed the tooltip layer
instead of closing the dialog
- Sharing: PersonaShareDialog, catalog-visibility localStorage, and the
standalone catalog dialog are removed — Export in the card menu is the
sharing path
- Copy sweep: remaining user-visible "persona" strings renamed (config
provenance is "Inherited from agent profile", delete/import/toast copy,
ModelPicker, EnvVarsEditor); profile panel actions are agent-centric
and the profilePersona route param is gone; channel templates resolve
agent pubkeys, persona ids, or builtin template ids polymorphically;
the Fizz welcome guide spawns from its AgentTemplate
- shared/api: AgentTemplate type, agentPubkeys on team types, provider on
CreateManagedAgentInput, listAgentTemplates/exportAgentToJson bindings;
e2eBridge mocks the new surface for the Playwright suites; colocated
unit tests (.test.mjs) updated alongside their sources
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Backend half of removing personas from the UI. User-created agents no
longer have a backing persona record; persona records are quarantined to
team packs, which genuinely need them for directory install/sync and
writeback.
- types.rs, team_events.rs: add agent_pubkeys to TeamRecord, the
create/update team inputs, and the kind:30176 payload. The field is
additive — events published by older clients parse with empty agent
membership (round-trip and tolerance tests included)
- commands/teams.rs: normalize and validate agent pubkeys on team
create/update; team export resolves agent members into the interchange
member shape alongside persona members; pack install/sync materialize
pack personas as stopped agents so they appear in the grid immediately
- commands/personas/mod.rs: inbound kind:30176 reconcile applies
agent_pubkeys from remote events
- managed_agents/flatten.rs (new): idempotent boot migration —
materialize a stopped agent for every active persona without one,
rewrite non-pack team persona members to agent pubkeys, pin persona
config onto linked agents and clear persona_id, then deactivate the
flattened non-pack personas (records stay on disk/relay for rollback).
flatten_tests.rs covers materialization, team rewrite, pack
quarantine, and re-run idempotency
- managed_agents/personas.rs: stop seeding built-in personas as records;
the same data is now a static AgentTemplate list, and merge_personas
only demotes stale is_builtin flags
- commands/agent_templates.rs (new): list_agent_templates and
export_agent_to_json — agent-record export to the .persona.json
interchange format (env vars excluded, matching persona export)
- commands/agents.rs: create_managed_agent accepts an explicit provider
so templates and duplicates can pin the LLM provider at create time
- lib.rs: run the flatten migration post-identity, before event sync, so
rewritten teams/personas are what get reconciled and published;
register the new template commands
- team_repair.rs, personas/writeback.rs, inbound_tests.rs,
personas/tests.rs: fixtures and merge-semantics tests updated for the
new fields and the removal of built-in seeding; the shared test UUID
constant avoids a digit run the secret scanner reads as a card number
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
These predate the agents-first work but fail desktop-tauri-clippy
(-D warnings) and therefore block `just ci`, so they land first as a
standalone mechanical cleanup.
- agent_models.rs: drop the vestigial preserve_first_separator parameter
from title_case_model_suffix — both branches were identical
(if_same_then_else)
- config_bridge/claude.rs: build RuntimeFileConfig via struct-literal
init in the test helper (field_reassign_with_default)
- config_bridge/reader.rs: annotate build_model_field with
too_many_arguments and resolve_with_override with type_complexity —
pre-existing shapes, allowed rather than refactored to keep this
change mechanical
- runtime.rs: use slice::contains instead of iter().any
(manual_contains)
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>