From 6e65d3e97ceb0c4bfdbf996eda3ae194ddc4890a Mon Sep 17 00:00:00 2001 From: Patrizio Rullo Date: Sun, 12 Jul 2026 15:07:43 +0200 Subject: [PATCH] feat: canonicalize teams and refresh Pi models --- .changeset/canonical-harness-foundation.md | 4 +- .changeset/fresh-pi-models.md | 6 + .codex/skills/bazilion-release/SKILL.md | 10 +- .codex/skills/refresh-pi-models/SKILL.md | 53 + .../refresh-pi-models/agents/openai.yaml | 4 + .../scripts/audit-pi-models.mjs | 61 ++ AGENTS.md | 62 +- CHANGELOG.md | 9 +- README.md | 42 +- apps/cli/CHANGELOG.md | 34 +- apps/cli/README.md | 36 +- apps/cli/package.json | 8 +- apps/cli/src/commands/agent.ts | 64 +- apps/cli/src/commands/approval.ts | 15 +- apps/cli/src/commands/doctor.ts | 2 +- apps/cli/src/commands/group.ts | 195 ---- apps/cli/src/commands/memory.ts | 32 +- apps/cli/src/commands/profile-group.ts | 268 ----- .../{group-policy.ts => team-policy.ts} | 119 +-- apps/cli/src/commands/team-template.ts | 216 ++++ apps/cli/src/commands/team.ts | 339 +++--- apps/cli/src/commands/telegram.ts | 4 +- apps/cli/src/commands/uninstall.ts | 11 +- apps/cli/src/index.ts | 21 +- ...ess-interchange.ts => team-interchange.ts} | 68 +- apps/cli/test/agent.test.ts | 22 +- apps/cli/test/completion.test.ts | 4 +- apps/cli/test/memory.test.ts | 8 +- apps/cli/test/server-fixture.ts | 34 +- ...hange.test.ts => team-interchange.test.ts} | 19 +- ...ess-policy.test.ts => team-policy.test.ts} | 55 +- apps/cli/test/{group.test.ts => team.test.ts} | 42 +- apps/daemon/package.json | 6 +- apps/daemon/src/app.ts | 10 +- apps/daemon/src/core/agent/delete.ts | 40 +- apps/daemon/src/core/agent/move.ts | 98 +- apps/daemon/src/core/agent/resolve.ts | 10 +- apps/daemon/src/core/agent/spawn.ts | 74 +- apps/daemon/src/core/availableModels.ts | 6 +- apps/daemon/src/core/db/migrate.ts | 19 - .../src/core/db/migrations/0001_init.sql | 406 ++++++-- .../db/migrations/0002_profile_groups.sql | 38 - .../db/migrations/0003_agent_telegram.sql | 40 - .../db/migrations/0004_agent_mirror_mode.sql | 17 - .../0005_group_topic_name_format.sql | 15 - .../core/db/migrations/0006_telegram_acl.sql | 18 - .../core/db/migrations/0007_mcp_servers.sql | 30 - .../core/db/migrations/0008_seed_user_md.sql | 39 - .../db/migrations/0009_canonical_harness.sql | 322 ------ .../db/migrations/0010_harness_blocks.sql | 29 - .../0011_harness_runtime_claims.sql | 5 - .../0012_communication_approvals.sql | 72 -- .../migrations/0013_harness_slot_layout.sql | 4 - apps/daemon/src/core/group/delete.ts | 60 -- apps/daemon/src/core/index.ts | 61 +- apps/daemon/src/core/paths.ts | 10 +- apps/daemon/src/core/profile-group/spawn.ts | 267 ----- apps/daemon/src/core/profile/delete.ts | 10 +- apps/daemon/src/core/profile/seed.ts | 30 +- apps/daemon/src/core/profile/templates.ts | 12 +- apps/daemon/src/core/repos/agents.ts | 48 +- .../src/core/repos/communicationApprovals.ts | 46 +- apps/daemon/src/core/repos/liveHarnesses.ts | 450 -------- .../repos/profileCommunicationDefaults.ts | 20 +- apps/daemon/src/core/repos/profileGroups.ts | 91 -- apps/daemon/src/core/repos/teamPolicies.ts | 354 +++++++ .../{harnessTemplates.ts => teamTemplates.ts} | 343 ++----- .../src/core/repos/{groups.ts => teams.ts} | 58 +- apps/daemon/src/core/services.ts | 10 +- .../core/{harness => team-policy}/adopt.ts | 114 +- .../{harness => team-policy}/authorization.ts | 99 +- .../rm-with-retry.ts | 2 +- .../core/{harness => team-policy}/source.ts | 122 +-- .../core/{harness => team-policy}/spawn.ts | 180 ++-- apps/daemon/src/core/team/delete.ts | 57 + .../src/core/{group => team}/register.ts | 36 +- apps/daemon/src/lib/communication.ts | 30 +- apps/daemon/src/lib/ctx.ts | 8 +- apps/daemon/src/lib/harness-contract.ts | 13 - apps/daemon/src/lib/scheduler.ts | 2 +- apps/daemon/src/lib/team-policy-contract.ts | 15 + apps/daemon/src/lib/telegram/activation.ts | 2 +- apps/daemon/src/lib/telegram/bot.ts | 2 +- apps/daemon/src/lib/telegram/commands/help.ts | 14 +- .../daemon/src/lib/telegram/commands/index.ts | 10 +- apps/daemon/src/lib/telegram/commands/list.ts | 14 +- .../src/lib/telegram/commands/rebind.ts | 8 +- .../src/lib/telegram/commands/spawn-team.ts | 78 +- .../daemon/src/lib/telegram/commands/spawn.ts | 38 +- apps/daemon/src/lib/telegram/commands/talk.ts | 14 +- .../telegram/commands/{groups.ts => teams.ts} | 14 +- apps/daemon/src/lib/telegram/directory.ts | 14 +- apps/daemon/src/lib/telegram/naming.ts | 74 +- .../daemon/src/lib/telegram/outbound-queue.ts | 2 +- .../daemon/src/lib/telegram/profile-emojis.ts | 2 +- apps/daemon/src/lib/telegram/resolve-agent.ts | 26 +- apps/daemon/src/lib/telegram/routing.ts | 16 +- .../src/lib/telegram/topic-autocreate.ts | 14 +- apps/daemon/src/lib/telegram/topic-rename.ts | 16 +- apps/daemon/src/lib/user-md-host.ts | 26 +- apps/daemon/src/routes/agents.ts | 282 +++-- apps/daemon/src/routes/approvals.ts | 2 +- apps/daemon/src/routes/config.ts | 4 +- apps/daemon/src/routes/misc.ts | 23 +- apps/daemon/src/routes/profile-groups.ts | 247 ----- apps/daemon/src/routes/profiles.ts | 12 +- ...harness-templates.ts => team-templates.ts} | 96 +- .../daemon/src/routes/{groups.ts => teams.ts} | 209 ++-- apps/daemon/src/runtime/pi/session.ts | 14 +- apps/daemon/src/runtime/pi/tools.ts | 4 +- apps/daemon/src/runtime/providers/catalog.ts | 2 +- .../src/runtime/providers/pi-adapter.ts | 2 +- apps/daemon/src/runtime/session/prompt.ts | 18 +- apps/daemon/src/runtime/tools/home.ts | 2 +- apps/daemon/src/runtime/tools/memory.ts | 8 +- apps/daemon/src/runtime/tools/messaging.ts | 2 +- apps/daemon/src/runtime/tools/user-md.ts | 14 +- apps/daemon/src/runtime/worker/entry.ts | 8 +- .../daemon/src/runtime/worker/ipc-protocol.ts | 12 +- apps/daemon/src/runtime/worker/spawn.ts | 4 +- .../test/core/agent-telegram-shape.test.ts | 6 +- apps/daemon/test/core/agents.test.ts | 59 +- .../daemon/test/core/available-models.test.ts | 6 +- .../test/core/communication-approvals.test.ts | 66 +- apps/daemon/test/core/groups.test.ts | 67 -- .../test/core/harness-migration.test.ts | 266 ----- .../test/core/harness-persistence.test.ts | 282 ----- apps/daemon/test/core/helpers.ts | 14 +- .../core/migration-0008-seed-user-md.test.ts | 53 - apps/daemon/test/core/migrations.test.ts | 75 +- .../test/core/profile-group-spawn.test.ts | 312 ------ apps/daemon/test/core/profile-group.test.ts | 187 ---- apps/daemon/test/core/provider-models.test.ts | 2 +- .../test/core/runtime-boundaries.test.ts | 99 +- apps/daemon/test/core/skills.test.ts | 4 +- ...ion.test.ts => team-authorization.test.ts} | 137 +-- ....test.ts => team-template-cleanup.test.ts} | 2 +- apps/daemon/test/core/teams.test.ts | 67 ++ apps/daemon/test/core/triggers.test.ts | 4 +- apps/daemon/test/lib/ctx-bootstrap.test.ts | 34 +- ...t.test.ts => team-policy-contract.test.ts} | 12 +- .../test/lib/telegram-directory.test.ts | 16 +- apps/daemon/test/lib/telegram-mirror.test.ts | 86 +- apps/daemon/test/lib/telegram-naming.test.ts | 52 +- .../test/lib/telegram-preflight.test.ts | 2 +- .../test/lib/telegram-resolve-agent.test.ts | 58 +- apps/daemon/test/lib/telegram-routing.test.ts | 86 +- .../lib/telegram-topic-autocreate.test.ts | 28 +- .../lib/telegram-topic-name-format.test.ts | 48 +- apps/daemon/test/lib/user-md-host.test.ts | 44 +- apps/daemon/test/routes/agent-skills.test.ts | 6 +- apps/daemon/test/routes/communication.test.ts | 72 +- .../test/routes/harness-compatibility.test.ts | 158 --- apps/daemon/test/routes/misc.test.ts | 20 +- ...mplates.test.ts => team-templates.test.ts} | 277 +++-- apps/daemon/test/runtime/messaging.test.ts | 12 +- .../test/runtime/provider-catalog.test.ts | 8 + apps/daemon/test/runtime/providers.test.ts | 2 +- apps/daemon/test/runtime/session-head.test.ts | 4 +- .../daemon/test/runtime/tools-user-md.test.ts | 12 +- apps/mobile/README.md | 2 +- apps/mobile/app/agents/[id]/index.tsx | 6 +- apps/web/src/components/AgentTabs.tsx | 6 +- apps/web/src/components/ChatPane.tsx | 74 +- ...teGroupDialog.tsx => CreateTeamDialog.tsx} | 16 +- apps/web/src/components/Sidebar.tsx | 74 +- apps/web/src/components/SpawnDialog.tsx | 48 +- apps/web/src/components/SpawnTeamModal.tsx | 44 +- .../{GroupTabs.tsx => TeamTabs.tsx} | 6 +- apps/web/src/components/TemplatesTabs.tsx | 2 +- apps/web/src/components/TopNav.tsx | 6 +- .../src/components/harness/HarnessBuilder.tsx | 657 ------------ .../harness/HarnessBuilderDialogs.tsx | 397 ------- .../src/components/harness/HarnessDialogs.tsx | 401 -------- .../components/harness/HarnessSidePanel.tsx | 663 ------------ .../harness/LocalHarnessMigration.tsx | 66 -- .../src/components/harness/PrototypeBadge.tsx | 18 - .../ProductionTeamPolicyEditor.tsx} | 92 +- .../ProfileCommunicationEditor.tsx | 22 +- .../TeamPolicyFlow.tsx} | 76 +- .../TeamPolicyMatrix.tsx} | 42 +- .../TeamPolicyOperations.tsx} | 48 +- apps/web/src/components/ui/button.tsx | 10 +- apps/web/src/components/ui/card.tsx | 10 +- apps/web/src/components/ui/checkbox.tsx | 2 +- apps/web/src/components/ui/label.tsx | 2 +- apps/web/src/components/ui/radio-group.tsx | 8 +- apps/web/src/components/ui/select.tsx | 2 +- apps/web/src/components/ui/tabs.tsx | 10 +- apps/web/src/hooks/use-harness-prototype.ts | 69 -- ...canonical-harness.ts => canonical-team.ts} | 105 +- apps/web/src/lib/daemon-client.ts | 2 +- apps/web/src/lib/harness-prototype.ts | 971 ------------------ ...-presenter.ts => team-policy-presenter.ts} | 34 +- apps/web/src/lib/team-policy.ts | 381 +++++++ apps/web/src/lib/wire-constants.ts | 4 +- apps/web/src/routeTree.gen.ts | 372 +++---- apps/web/src/routes/__root.tsx | 4 +- apps/web/src/routes/agents/$id/index.tsx | 146 +-- apps/web/src/routes/agents/index.tsx | 71 +- apps/web/src/routes/api/$.ts | 2 +- apps/web/src/routes/approvals/index.tsx | 4 +- apps/web/src/routes/config/index.tsx | 9 +- .../routes/config/integrations/telegram.tsx | 12 +- apps/web/src/routes/config/services.tsx | 20 +- apps/web/src/routes/harnesses/$id.tsx | 49 - apps/web/src/routes/harnesses/index.tsx | 165 --- apps/web/src/routes/index.tsx | 20 +- apps/web/src/routes/profile-groups/$id.tsx | 7 - apps/web/src/routes/profile-groups/index.tsx | 7 - apps/web/src/routes/profiles/$id.tsx | 7 - apps/web/src/routes/profiles/index.tsx | 7 - .../routes/{groups => teams}/$id/activity.tsx | 24 +- .../routes/{groups => teams}/$id/context.tsx | 22 +- .../routes/{groups => teams}/$id/index.tsx | 110 +- .../routes/{groups => teams}/$id/members.tsx | 18 +- .../routes/{groups => teams}/$id/memory.tsx | 46 +- .../routes/{groups => teams}/$id/policy.tsx | 39 +- .../src/routes/{groups => teams}/index.tsx | 101 +- .../src/routes/templates/agents/$id/index.tsx | 10 +- .../web/src/routes/templates/agents/index.tsx | 10 +- .../src/routes/templates/teams/$id/index.tsx | 14 +- apps/web/src/routes/templates/teams/index.tsx | 8 +- apps/web/src/routes/welcome.tsx | 4 +- apps/web/src/styles.css | 2 +- ...harness.test.ts => canonical-team.test.ts} | 80 +- apps/web/test/harness-prototype.test.ts | 581 ----------- docs/adr/0001-production-harness-domain.md | 276 +---- docs/agent-engine.md | 26 +- docs/architecture.md | 86 +- docs/backlog/README.md | 23 +- docs/backlog/done/BAZ-002-profile-groups.md | 164 +-- .../done/BAZ-005-agent-templates-refresh.md | 40 +- .../BAZ-007-simple-installer-and-dashboard.md | 2 +- .../BAZ-009-configurable-agent-harness.md | 158 +-- .../done/BAZ-010-harness-persistence-api.md | 130 +-- .../BAZ-011-harness-runtime-enforcement.md | 36 +- .../done/BAZ-012-production-harness-web.md | 99 +- .../done/BAZ-013-harness-cli-policy-tools.md | 28 +- ...BAZ-014-harness-communication-approvals.md | 6 +- .../BAZ-015-harness-policy-lifecycle-api.md | 111 +- .../BAZ-016-harness-runtime-boundaries.md | 25 +- .../BAZ-017-harness-web-editor-migration.md | 39 +- .../done/BAZ-018-canonical-teams-cleanup.md | 69 ++ .../draft/BAZ-001-a2a-federation-spike.md | 26 +- .../draft/BAZ-003-hermes-self-learning.md | 24 +- .../todo/BAZ-006-skill-execution-security.md | 18 +- docs/harness-policy-handoff.md | 369 +------ docs/openclaw-reference.md | 2 +- docs/telegram-v2.md | 81 +- docs/telegram.md | 62 +- packages/api-types/CHANGELOG.md | 29 +- packages/api-types/README.md | 2 +- packages/api-types/src/entities.ts | 145 +-- packages/api-types/src/index.ts | 181 ++-- packages/api-types/src/memory.ts | 2 +- packages/client/CHANGELOG.md | 29 +- pnpm-lock.yaml | 793 ++++++-------- 258 files changed, 6010 insertions(+), 13225 deletions(-) create mode 100644 .changeset/fresh-pi-models.md create mode 100644 .codex/skills/refresh-pi-models/SKILL.md create mode 100644 .codex/skills/refresh-pi-models/agents/openai.yaml create mode 100755 .codex/skills/refresh-pi-models/scripts/audit-pi-models.mjs delete mode 100644 apps/cli/src/commands/group.ts delete mode 100644 apps/cli/src/commands/profile-group.ts rename apps/cli/src/commands/{group-policy.ts => team-policy.ts} (68%) create mode 100644 apps/cli/src/commands/team-template.ts rename apps/cli/src/{harness-interchange.ts => team-interchange.ts} (86%) rename apps/cli/test/{harness-interchange.test.ts => team-interchange.test.ts} (88%) rename apps/cli/test/{harness-policy.test.ts => team-policy.test.ts} (75%) rename apps/cli/test/{group.test.ts => team.test.ts} (51%) delete mode 100644 apps/daemon/src/core/db/migrations/0002_profile_groups.sql delete mode 100644 apps/daemon/src/core/db/migrations/0003_agent_telegram.sql delete mode 100644 apps/daemon/src/core/db/migrations/0004_agent_mirror_mode.sql delete mode 100644 apps/daemon/src/core/db/migrations/0005_group_topic_name_format.sql delete mode 100644 apps/daemon/src/core/db/migrations/0006_telegram_acl.sql delete mode 100644 apps/daemon/src/core/db/migrations/0007_mcp_servers.sql delete mode 100644 apps/daemon/src/core/db/migrations/0008_seed_user_md.sql delete mode 100644 apps/daemon/src/core/db/migrations/0009_canonical_harness.sql delete mode 100644 apps/daemon/src/core/db/migrations/0010_harness_blocks.sql delete mode 100644 apps/daemon/src/core/db/migrations/0011_harness_runtime_claims.sql delete mode 100644 apps/daemon/src/core/db/migrations/0012_communication_approvals.sql delete mode 100644 apps/daemon/src/core/db/migrations/0013_harness_slot_layout.sql delete mode 100644 apps/daemon/src/core/group/delete.ts delete mode 100644 apps/daemon/src/core/profile-group/spawn.ts delete mode 100644 apps/daemon/src/core/repos/liveHarnesses.ts delete mode 100644 apps/daemon/src/core/repos/profileGroups.ts create mode 100644 apps/daemon/src/core/repos/teamPolicies.ts rename apps/daemon/src/core/repos/{harnessTemplates.ts => teamTemplates.ts} (62%) rename apps/daemon/src/core/repos/{groups.ts => teams.ts} (52%) rename apps/daemon/src/core/{harness => team-policy}/adopt.ts (67%) rename apps/daemon/src/core/{harness => team-policy}/authorization.ts (77%) rename apps/daemon/src/core/{profile-group => team-policy}/rm-with-retry.ts (95%) rename apps/daemon/src/core/{harness => team-policy}/source.ts (72%) rename apps/daemon/src/core/{harness => team-policy}/spawn.ts (56%) create mode 100644 apps/daemon/src/core/team/delete.ts rename apps/daemon/src/core/{group => team}/register.ts (57%) delete mode 100644 apps/daemon/src/lib/harness-contract.ts create mode 100644 apps/daemon/src/lib/team-policy-contract.ts rename apps/daemon/src/lib/telegram/commands/{groups.ts => teams.ts} (55%) delete mode 100644 apps/daemon/src/routes/profile-groups.ts rename apps/daemon/src/routes/{harness-templates.ts => team-templates.ts} (81%) rename apps/daemon/src/routes/{groups.ts => teams.ts} (68%) delete mode 100644 apps/daemon/test/core/groups.test.ts delete mode 100644 apps/daemon/test/core/harness-migration.test.ts delete mode 100644 apps/daemon/test/core/harness-persistence.test.ts delete mode 100644 apps/daemon/test/core/migration-0008-seed-user-md.test.ts delete mode 100644 apps/daemon/test/core/profile-group-spawn.test.ts delete mode 100644 apps/daemon/test/core/profile-group.test.ts rename apps/daemon/test/core/{harness-authorization.test.ts => team-authorization.test.ts} (58%) rename apps/daemon/test/core/{rm-with-retry.test.ts => team-template-cleanup.test.ts} (97%) create mode 100644 apps/daemon/test/core/teams.test.ts rename apps/daemon/test/lib/{harness-contract.test.ts => team-policy-contract.test.ts} (76%) delete mode 100644 apps/daemon/test/routes/harness-compatibility.test.ts rename apps/daemon/test/routes/{harness-templates.test.ts => team-templates.test.ts} (67%) create mode 100644 apps/daemon/test/runtime/provider-catalog.test.ts rename apps/web/src/components/{CreateGroupDialog.tsx => CreateTeamDialog.tsx} (90%) rename apps/web/src/components/{GroupTabs.tsx => TeamTabs.tsx} (83%) delete mode 100644 apps/web/src/components/harness/HarnessBuilder.tsx delete mode 100644 apps/web/src/components/harness/HarnessBuilderDialogs.tsx delete mode 100644 apps/web/src/components/harness/HarnessDialogs.tsx delete mode 100644 apps/web/src/components/harness/HarnessSidePanel.tsx delete mode 100644 apps/web/src/components/harness/LocalHarnessMigration.tsx delete mode 100644 apps/web/src/components/harness/PrototypeBadge.tsx rename apps/web/src/components/{harness/ProductionHarnessEditor.tsx => team-policy/ProductionTeamPolicyEditor.tsx} (64%) rename apps/web/src/components/{harness => team-policy}/ProfileCommunicationEditor.tsx (86%) rename apps/web/src/components/{harness/HarnessFlow.tsx => team-policy/TeamPolicyFlow.tsx} (83%) rename apps/web/src/components/{harness/HarnessMatrix.tsx => team-policy/TeamPolicyMatrix.tsx} (76%) rename apps/web/src/components/{harness/GroupPolicyOperations.tsx => team-policy/TeamPolicyOperations.tsx} (69%) delete mode 100644 apps/web/src/hooks/use-harness-prototype.ts rename apps/web/src/lib/{canonical-harness.ts => canonical-team.ts} (54%) delete mode 100644 apps/web/src/lib/harness-prototype.ts rename apps/web/src/lib/{harness-presenter.ts => team-policy-presenter.ts} (59%) create mode 100644 apps/web/src/lib/team-policy.ts delete mode 100644 apps/web/src/routes/harnesses/$id.tsx delete mode 100644 apps/web/src/routes/harnesses/index.tsx delete mode 100644 apps/web/src/routes/profile-groups/$id.tsx delete mode 100644 apps/web/src/routes/profile-groups/index.tsx delete mode 100644 apps/web/src/routes/profiles/$id.tsx delete mode 100644 apps/web/src/routes/profiles/index.tsx rename apps/web/src/routes/{groups => teams}/$id/activity.tsx (73%) rename apps/web/src/routes/{groups => teams}/$id/context.tsx (64%) rename apps/web/src/routes/{groups => teams}/$id/index.tsx (77%) rename apps/web/src/routes/{groups => teams}/$id/members.tsx (73%) rename apps/web/src/routes/{groups => teams}/$id/memory.tsx (87%) rename apps/web/src/routes/{groups => teams}/$id/policy.tsx (58%) rename apps/web/src/routes/{groups => teams}/index.tsx (60%) rename apps/web/test/{canonical-harness.test.ts => canonical-team.test.ts} (64%) delete mode 100644 apps/web/test/harness-prototype.test.ts create mode 100644 docs/backlog/done/BAZ-018-canonical-teams-cleanup.md diff --git a/.changeset/canonical-harness-foundation.md b/.changeset/canonical-harness-foundation.md index 9f71b1d..e1a99cb 100644 --- a/.changeset/canonical-harness-foundation.md +++ b/.changeset/canonical-harness-foundation.md @@ -2,4 +2,6 @@ 'bazilion': patch --- -Add the canonical Team-template and one-policy-per-Group persistence foundation, atomically migrate legacy Profile Groups, and preserve their CLI/API behavior through deprecated compatibility adapters. +Complete the breaking alpha cleanup to canonical Teams, Team Templates, and Team Policy. Remove +Group, Profile Group, Harness prototype, compatibility API/URL, and incremental migration +surfaces; consolidate fresh installs into the final `0001_init.sql` schema. diff --git a/.changeset/fresh-pi-models.md b/.changeset/fresh-pi-models.md new file mode 100644 index 0000000..aabae73 --- /dev/null +++ b/.changeset/fresh-pi-models.md @@ -0,0 +1,6 @@ +--- +"bazilion": minor +--- + +Update the bundled Pi agent packages to 0.80.6 and refresh provider examples for the GPT-5.6 +Luna, Terra, and Sol model family. diff --git a/.codex/skills/bazilion-release/SKILL.md b/.codex/skills/bazilion-release/SKILL.md index a06b98d..2d979f2 100644 --- a/.codex/skills/bazilion-release/SKILL.md +++ b/.codex/skills/bazilion-release/SKILL.md @@ -7,7 +7,8 @@ description: Bazilion release workflow for the rullopat/bazilion monorepo. Use w ## Scope -Use this workflow in `/home/patri/coding/bazilion` for the `rullopat/bazilion` monorepo. +Use this workflow from the root of the `rullopat/bazilion` monorepo. Confirm the root with +`git rev-parse --show-toplevel`; do not rely on a machine-specific absolute path. Public release packages are fixed together by `.changeset/config.json`: @@ -58,8 +59,15 @@ Run validation before committing a release: ```sh pnpm typecheck pnpm test +pnpm --filter @bazilion/web typecheck +pnpm --filter @bazilion/web build ``` +Because Bazilion currently has a clean-install-only alpha database contract, also bootstrap a +fresh temporary `BAZILION_HOME` whenever the release changes the schema, canonical Team APIs, or +filesystem layout. Verify that `schema_migrations` contains only `0001_init` and that no removed +Group, Profile Team, Harness, or compatibility route is advertised by current docs or CLI help. + If sandbox loopback/process restrictions cause failures such as `listen EPERM 127.0.0.1` or empty CLI subprocess output, rerun the same test command outside the sandbox with escalation. Treat the sandbox failure as environmental only after the escalated run passes. For dependency/provider releases, also verify pi provider coverage when relevant: diff --git a/.codex/skills/refresh-pi-models/SKILL.md b/.codex/skills/refresh-pi-models/SKILL.md new file mode 100644 index 0000000..9f04d92 --- /dev/null +++ b/.codex/skills/refresh-pi-models/SKILL.md @@ -0,0 +1,53 @@ +--- +name: refresh-pi-models +description: Update Bazilion to current @earendil-works Pi packages and reconcile its provider catalog, curated model examples, setup copy, tests, lockfile, and release notes. Use when Pi publishes a release, new model families appear, model examples become stale, provider catalogs change, or a Bazilion dependency refresh is requested. +--- + +# Refresh Pi Models + +Refresh the engine and the user-visible model guidance from upstream evidence. Do not guess model +ids or update examples merely because a model was announced elsewhere. + +## Workflow + +1. Read repository `AGENTS.md` and inspect the worktree. Preserve unrelated changes. +2. Query npm for the latest versions of `@earendil-works/pi-ai`, `pi-agent-core`, and + `pi-coding-agent`. Treat npm package metadata and the installed Pi catalog as authoritative. +3. Record the current dependency declarations in `apps/daemon/package.json`, + `apps/cli/package.json`, and `pnpm-lock.yaml`. Keep all three Pi packages on one compatible + release unless upstream explicitly publishes a supported mixed set. +4. Update both the daemon and published CLI workspace dependencies with pnpm. Never hand-edit the + lockfile. +5. Inspect upstream release/API changes. Fix Bazilion imports and adapters instead of pinning an + old release. In particular, verify whether catalog helpers still live at the root or require + `@earendil-works/pi-ai/compat`/the provider collection API. +6. Run `node .codex/skills/refresh-pi-models/scripts/audit-pi-models.mjs`. Use its exact catalog + output to update: + - `apps/web/src/routes/config/index.tsx` examples and its Pi-version comment; + - first-run examples in `apps/web/src/routes/welcome.tsx`; + - root and CLI README model examples/provider text; + - current AGENTS.md model examples when stale. +7. Prefer a current generally useful tool-capable model per provider. Do not rewrite historical + changelogs or tests whose ids are deliberate fixtures. For OAuth `openai-codex`, confirm the + model exists in that provider's catalog rather than copying an `openai` API model id. +8. Add or update focused catalog tests so key newly added families and example ids are proven to + exist. Add a Changeset for the published `bazilion` package when the bundled engine changes. +9. Validate in order: + + ```sh + node .codex/skills/refresh-pi-models/scripts/audit-pi-models.mjs + pnpm vitest run apps/daemon/test/runtime/providers.test.ts apps/daemon/test/core/provider-models.test.ts + pnpm typecheck + pnpm --filter @bazilion/web typecheck + pnpm test + pnpm lint + pnpm build + git diff --check + ``` + +10. Audit the final diff: dependency versions agree, advertised examples are present in the + installed catalog (or explicitly identified live/local aliases), and no unrelated files were + staged or reverted. + +If network or subprocess tests fail only because of the sandbox, rerun the same command with the +required approval. Report upstream versions, notable new models, API adaptations, and validation. diff --git a/.codex/skills/refresh-pi-models/agents/openai.yaml b/.codex/skills/refresh-pi-models/agents/openai.yaml new file mode 100644 index 0000000..f78cc51 --- /dev/null +++ b/.codex/skills/refresh-pi-models/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Refresh Pi Models" + short_description: "Update Pi packages and Bazilion model examples" + default_prompt: "Use $refresh-pi-models to update Bazilion to the latest Pi packages and refresh its model examples." diff --git a/.codex/skills/refresh-pi-models/scripts/audit-pi-models.mjs b/.codex/skills/refresh-pi-models/scripts/audit-pi-models.mjs new file mode 100755 index 0000000..d05ac96 --- /dev/null +++ b/.codex/skills/refresh-pi-models/scripts/audit-pi-models.mjs @@ -0,0 +1,61 @@ +#!/usr/bin/env node + +import { existsSync, readFileSync } from 'node:fs' + +const piDist = new URL( + '../../../../apps/daemon/node_modules/@earendil-works/pi-ai/dist/', + import.meta.url, +) +const compat = new URL('compat.js', piDist) +const pi = await import(existsSync(compat) ? compat.href : new URL('index.js', piDist).href) +const { getModels, getProviders } = pi +if (typeof getModels !== 'function' || typeof getProviders !== 'function') { + throw new Error('installed pi-ai exposes neither the compat nor legacy catalog helpers') +} + +const source = readFileSync('apps/web/src/routes/config/index.tsx', 'utf8') +const examples = new Map() +for (const match of source.matchAll(/case '([^']+)':\s+return '([^']+)'/g)) { + examples.set(match[1], match[2]) +} + +const aliases = new Map([ + ['bedrock', 'amazon-bedrock'], + ['azure-openai', 'azure-openai-responses'], +]) +const providers = getProviders() +const report = [] +const full = process.argv.includes('--full') + +for (const provider of providers) { + const models = (getModels(provider) ?? []).map((model) => model.id) + report.push({ provider, count: models.length, models }) +} + +const failures = [] +for (const [provider, example] of examples) { + const piProvider = aliases.get(provider) ?? provider + if (!providers.includes(piProvider)) continue // dynamic/local Bazilion provider + const models = (getModels(piProvider) ?? []).map((model) => model.id) + if (models.length > 0 && !models.includes(example)) { + failures.push(`${provider}: example '${example}' is absent from Pi provider '${piProvider}'`) + } +} + +for (const entry of report) { + console.log(`${entry.provider}: ${entry.count}`) + if (full) console.log(entry.models.map((model) => ` ${model}`).join('\n')) +} + +const newOpenAI = report + .find((entry) => entry.provider === 'openai') + ?.models.filter((model) => /^gpt-5\.\d/.test(model)) +console.log(`\nRecent OpenAI families: ${(newOpenAI ?? []).slice(-12).join(', ')}`) + +if (failures.length > 0) { + console.error('\nStale catalog-backed examples:') + for (const failure of failures) console.error(`- ${failure}`) + process.exitCode = 1 +} else { + console.log('\nAll catalog-backed web examples resolve in the installed Pi catalog.') +} diff --git a/AGENTS.md b/AGENTS.md index 9b5c54a..6d6a81c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,9 +38,9 @@ Three invariants: 1. **Nothing outside `apps/daemon` imports daemon-internal code at runtime.** Clients talk to the daemon over HTTP via `@bazilion/client` + `@bazilion/api-types`. The CLI's tests are the one pragmatic exception: they reach into `apps/daemon/src/...` via relative imports for setup/inspection. No other consumer should follow that pattern. 2. **The daemon owns the DB, scheduler, agent-cancel registry, secrets table, and the bootstrap token in auth.json.** Other processes are stateless clients. -3. **The daemon self-bootstraps on first `bazilion serve`** — there is no `bazilion init` command. `apps/daemon/src/lib/ctx.ts:bootstrap()` runs idempotently at startup: creates `~/.bazilion/{profiles,agents,skills,groups,logs}`, opens the DB, runs migrations, and (if `auth.json` is missing) mints a bootstrap web_tokens row + writes the plaintext to `auth.json`. +3. **The daemon self-bootstraps on first `bazilion serve`** — there is no `bazilion init` command. `apps/daemon/src/lib/ctx.ts:bootstrap()` runs idempotently at startup: creates `~/.bazilion/{profiles,agents,skills,teams,logs}`, opens the DB, runs migrations, and (if `auth.json` is missing) mints a bootstrap web_tokens row + writes the plaintext to `auth.json`. -- **`packages/api-types`** — **hermetic** wire-shape package. Owns the canonical type definitions for everything that crosses the HTTP/IPC wire: entity shapes (`Agent`, `Group`, `Profile`, `Message`, `WebToken`, `AgentTrigger`, `ResolvedAgent`, `LoadedProfile`, `OpenAICodexStatus`, …) in `entities.ts`, chat/provider events (`ChatFrame`, `SessionEvent`, `ProviderMessage`, `ToolCall`, `ToolDef`) in `events.ts`, memory wire types in `memory.ts`, and request/response envelopes + `PROFILE_FILES` in `index.ts`. **Zero deps** — no node-only modules, no daemon code. The daemon imports its entity/wire types FROM here; that's what keeps `apps/web`, `apps/mobile`, and `@bazilion/client` from ever reaching Node-only code (`node:sqlite`, undici, pi-ai, the worker spawner). +- **`packages/api-types`** — **hermetic** wire-shape package. Owns the canonical type definitions for everything that crosses the HTTP/IPC wire: entity shapes (`Agent`, `Team`, `Profile`, `Message`, `WebToken`, `AgentTrigger`, `ResolvedAgent`, `LoadedProfile`, `OpenAICodexStatus`, …) in `entities.ts`, chat/provider events (`ChatFrame`, `SessionEvent`, `ProviderMessage`, `ToolCall`, `ToolDef`) in `events.ts`, memory wire types in `memory.ts`, and request/response envelopes + `PROFILE_FILES` in `index.ts`. **Zero deps** — no node-only modules, no daemon code. The daemon imports its entity/wire types FROM here; that's what keeps `apps/web`, `apps/mobile`, and `@bazilion/client` from ever reaching Node-only code (`node:sqlite`, undici, pi-ai, the worker spawner). - **`packages/client`** — HTTP client for **cross-origin consumers that need explicit auth headers**: the CLI today, a future React Native / mobile app tomorrow. Exports `createClient({ serverUrl, token })`, `ApiClientError`, `BazilionClient`. Pure `fetch` + `TextDecoder` + NDJSON stream async generator — no `node:*` imports, no node-only deps. `token` is `string | (() => string | Promise)` so rotating credentials (OAuth refresh, mobile keychain reads) plug in without rebuilding the client; the package builds `Authorization: Bearer ` + `Origin: ` headers internally. `apps/cli/src/client.ts` wraps it with the Node-specific `loadClientConfig()` (reads `~/.bazilion/auth.json` + `BAZILION_SERVER`/`BAZILION_TOKEN` env via the CLI's local `apps/cli/src/{paths,auth-file}.ts` helpers). **Not used by `apps/web` browser-side code**: the web UI hits its own server same-origin with relative URLs, so the `bz_token` cookie auto-attaches. ### Auth model @@ -70,11 +70,11 @@ Expo SDK 54 + Expo Router 6 (file-based), React 19, RN 0.81, new-architecture-en - **`apps/daemon`** — Hono on `@hono/node-server`, binds `127.0.0.1:4321` by default (`HOST`/`PORT` env override). Owns all server-side code under one roof: - `src/index.ts` — entry: eagerly calls `getCtx()` so the bootstrap message + auth.json land before the port binds, then starts Hono. - `src/lib/` — daemon-only glue: `ctx.ts` (singleton + self-bootstrap), `middleware-auth.ts`, `auth.ts`, `agent-cancel.ts`, `agent-id.ts`, `agent-turn.ts`, `api-key.ts`, `cron.ts`, `messaging-host.ts`, `scheduler.ts`. - - `src/routes/` — HTTP routes by resource family: `agents.ts` (CRUD + group + skills + triggers + messages + sessions + chat NDJSON + `/cancel`), `groups.ts` (CRUD + USER.md + per-group shared memory at `/api/groups/:slug/memory*`), `profiles.ts`, `skills.ts`, `triggers.ts`, `messages.ts`, `config.ts`, `auth-login.ts` (ChatGPT OAuth + `/providers/test` + `/login`), `misc.ts` (`/health`, `/backup`, `/tokens`). - - `src/core/` — what used to be `packages/core`: SQLite schema + migrations (`db/`), repos (`repos/`), domain ops (`agent/`, `group/`, `profile/`, `skills/`), `paths.ts`, `secrets.ts`, `services.ts`, `availableModels.ts`. Barrel export at `src/core/index.ts`. + - `src/routes/` — HTTP routes by resource family: `agents.ts` (CRUD + team + skills + triggers + messages + sessions + chat NDJSON + `/cancel`), `teams.ts` (CRUD + USER.md + per-team shared memory at `/api/teams/:slug/memory*`), `profiles.ts`, `skills.ts`, `triggers.ts`, `messages.ts`, `config.ts`, `auth-login.ts` (ChatGPT OAuth + `/providers/test` + `/login`), `misc.ts` (`/health`, `/backup`, `/tokens`). + - `src/core/` — what used to be `packages/core`: SQLite schema + migrations (`db/`), repos (`repos/`), domain ops (`agent/`, `team/`, `profile/`, `skills/`), `paths.ts`, `secrets.ts`, `services.ts`, `availableModels.ts`. Barrel export at `src/core/index.ts`. - `src/runtime/` — what used to be `packages/runtime`: pi-coding-agent integration (`pi/`), provider adapters (`providers/`), memory backends (`memory/`), Bazilion-specific tools (`tools/`), per-turn worker subprocess (`worker/{entry,spawn,ipc-protocol}.ts`), heartbeat helpers (`auto-reply/`), OpenAI Codex OAuth (`auth/`). Barrel export at `src/runtime/index.ts`. - Auth + first-run middleware (`src/lib/middleware-auth.ts`) gates every route; public paths whitelisted inside the middleware. The daemon installs its own SIGINT/SIGTERM handlers and shuts the HTTP server gracefully. -- **`apps/web`** — TanStack Start (React 19 + Vite 8) frontend, **daemon-only client**. The canonical end-user UI. Canonical navigation is Templates, Agents, Groups, Approvals, Skills, and Config. Agent templates live under `/templates/agents`; Team templates under `/templates/teams`; each Group owns its production policy, membership, activity, memory, and context surfaces under `/groups/:id`; `/approvals` owns the communication-approval queue. Legacy `/profiles` and `/profile-groups` URLs are compatibility redirects. Tailwind v4 (CSS-first) + shadcn/ui. SSR loaders use `apps/web/src/lib/daemon-client.ts` (server-only) inside `createServerFn` handlers; that helper reads the request's `bz_token` cookie and forwards it as `Authorization: Bearer …` to `http://127.0.0.1:4321` (overridable via `BAZILION_DAEMON`). Browser fetches hit relative `/api/*` URLs that pass through the catch-all reverse proxy. The dev server binds `WEB_PORT` (default 4322) — pair with `bazilion serve` on 4321. **CLI/web parity is mandatory**: every HTTP endpoint must have both a CLI surface and a web UI surface. Chat markdown is rendered via `marked` + DOMPurify; styles for the `.md-content` class live in `apps/web/src/styles.css`. +- **`apps/web`** — TanStack Start (React 19 + Vite 8) frontend, **daemon-only client**. The canonical end-user UI. Canonical navigation is Templates, Agents, Teams, Approvals, Skills, and Config. Agent templates live under `/templates/agents`; Team templates under `/templates/teams`; each Team owns its production policy, membership, activity, memory, and context surfaces under `/teams/:id`; `/approvals` owns the communication-approval queue. Tailwind v4 (CSS-first) + shadcn/ui. SSR loaders use `apps/web/src/lib/daemon-client.ts` (server-only) inside `createServerFn` handlers; that helper reads the request's `bz_token` cookie and forwards it as `Authorization: Bearer …` to `http://127.0.0.1:4321` (overridable via `BAZILION_DAEMON`). Browser fetches hit relative `/api/*` URLs that pass through the catch-all reverse proxy. The dev server binds `WEB_PORT` (default 4322) — pair with `bazilion serve` on 4321. **CLI/web parity is mandatory**: every HTTP endpoint must have both a CLI surface and a web UI surface. Chat markdown is rendered via `marked` + DOMPurify; styles for the `.md-content` class live in `apps/web/src/styles.css`. ### SQLite driver @@ -88,10 +88,10 @@ State lives in `~/.bazilion/` (overridable via `$BAZILION_HOME`): ~/.bazilion/ bazilion.db # ALL DB state: entities + secrets + config (encrypted) + tokens auth.json # {token, remote?} — bootstrap bearer + optional CLI remote target - groups// # collaboration root, mounted as cwd; may be a symlink (--link) - memory/ # group-shared qmd index (.qmd-index.sqlite + markdown notes) + teams// # collaboration root, mounted as cwd; may be a symlink (--link) + memory/ # team-shared qmd index (.qmd-index.sqlite + markdown notes) ... project files / work product ... - agents// # agent's PRIVATE home — strictly outside the group tree + agents// # agent's PRIVATE home — strictly outside the team tree SOUL.md / IDENTITY.md / AGENTS.md / TOOLS.md / HEARTBEAT.md / [BOOTSTRAP.md] sessions/.jsonl # pi's append-only transcript agent.json @@ -100,15 +100,15 @@ State lives in `~/.bazilion/` (overridable via `$BAZILION_HOME`): logs/ ``` -Path resolution is centralized in `apps/daemon/src/core/paths.ts`. The `Paths` struct has `home`, `db`, `authFile`, `profilesDir`, `agentsDir`, `groupsDir`, `skillsDir`, `logsDir`, plus `agentDir(id)` / `groupDir(slug)` / `profileDir(id)` / `skillDir(name)` computed helpers. The CLI has its own minimal `apps/cli/src/paths.ts` (`resolveCliPaths` returns just `{home, authFile}`) for the filesystem-level commands (`uninstall`, `backup`, `login`, `token show-local`) — they don't need the full struct. **There is no longer a `configFile` field — `config.json` and `secrets.enc` were collapsed into the DB.** `bazilion uninstall` mirrors this layout as a two-tier teardown: data tier = DB + `profiles/` + `agents/` + `groups/`; full wipe adds `auth.json`, `logs/`, `skills/`. Symlinked groups (registered with `--link`) only have the slot under `~/.bazilion/groups/` removed; the symlink target is never touched. +Path resolution is centralized in `apps/daemon/src/core/paths.ts`. The `Paths` struct has `home`, `db`, `authFile`, `profilesDir`, `agentsDir`, `teamsDir`, `skillsDir`, `logsDir`, plus `agentDir(id)` / `teamDir(slug)` / `profileDir(id)` / `skillDir(name)` computed helpers. The CLI has its own minimal `apps/cli/src/paths.ts` (`resolveCliPaths` returns just `{home, authFile}`) for the filesystem-level commands (`uninstall`, `backup`, `login`, `token show-local`) — they don't need the full struct. **There is no longer a `configFile` field — `config.json` and `secrets.enc` were collapsed into the DB.** `bazilion uninstall` mirrors this layout as a two-tier teardown: data tier = DB + `profiles/` + `agents/` + `teams/`; full wipe adds `auth.json`, `logs/`, `skills/`. Symlinked teams (registered with `--link`) only have the slot under `~/.bazilion/teams/` removed; the symlink target is never touched. -### Group registration +### Team registration -Groups always live at `~/.bazilion/groups//`. The CLI (`bazilion group add [--link ]`) and the web `/groups` create form pass only the slug + optional name + optional link target; the daemon decides where the slot goes. `--link ` materializes the slot as a symlink to an existing directory (the "agents working on my existing project tree" path); the target must exist and be a directory. Without `--link`, a fresh real directory is created. `groupRepo.get/list/insert(db, ..., paths)` derive `Group.path` from `paths.groupDir(id)` at read time — there is no `path` column anymore. +Teams always live at `~/.bazilion/teams//`. The CLI (`bazilion team add [--link ]`) and the web `/teams` create form pass only the slug + optional name + optional link target; the daemon decides where the slot goes. `--link ` materializes the slot as a symlink to an existing directory (the "agents working on my existing project tree" path); the target must exist and be a directory. Without `--link`, a fresh real directory is created. `teamRepo.get/list/insert(db, ..., paths)` derive `Team.path` from `paths.teamDir(id)` at read time — there is no `path` column anymore. ### Memory model -Memory is **per-group**, shared across every agent in the group. The qmd backend lives at `/memory/`; each turn's worker calls `qmdBackend(join(agent.group.path, 'memory'))`. The `memory_*` tool descriptions explicitly tell the LLM the store is shared and direct personal notes (persona quirks, preferences) to `home_write IDENTITY.md` instead. The schema's per-agent memory dir is gone — `spawnAgent` only creates `agents//sessions/`. External surfaces match the ownership: HTTP at `/api/groups/:slug/memory*`, web UI at `/groups/:slug/memory`, CLI at `bazilion memory ...`. There are no `/api/agents/:id/memory*` routes — clients always address the group. +Memory is **per-team**, shared across every agent in the team. The qmd backend lives at `/memory/`; each turn's worker calls `qmdBackend(join(agent.team.path, 'memory'))`. The `memory_*` tool descriptions explicitly tell the LLM the store is shared and direct personal notes (persona quirks, preferences) to `home_write IDENTITY.md` instead. The schema's per-agent memory dir is gone — `spawnAgent` only creates `agents//sessions/`. External surfaces match the ownership: HTTP at `/api/teams/:slug/memory*`, web UI at `/teams/:slug/memory`, CLI at `bazilion memory ...`. There are no `/api/agents/:id/memory*` routes — clients always address the team. ### Worker subprocess + IPC @@ -146,21 +146,24 @@ API in `apps/daemon/src/core/`: `openSecrets(db, password)` and `openConfig(db)` - Biome formatter: single quotes, no semicolons, trailing commas, 2-space indent, 100-col width. - TS is strict with `noUncheckedIndexedAccess` and `verbatimModuleSyntax`. `.ts` extensions are required on all relative imports (`allowImportingTsExtensions: true`) — `tsx` and Vite both handle it. - `apps/web/` is excluded from the root `tsconfig.json` and from biome (it has its own Vite/TanStack-managed tooling). Run `pnpm --filter @bazilion/web typecheck` for web-only TS checks. The whole-tree `typecheck` intentionally skips it. -- Migrations are numbered SQL files in `apps/daemon/src/core/db/migrations/`. The schema is consolidated into a single `0001_init.sql` (the project is alpha; we wiped the DB and collapsed the prior chain on every shape change rather than maintaining an ALTER chain). Add new migrations as new numbered files going forward; the runner is idempotent and runs from the daemon's self-bootstrap (`apps/daemon/src/lib/ctx.ts:bootstrap()`) on every startup. Existing installs pick new files up automatically. +- **The alpha database contract is clean-install only.** The complete canonical schema lives in + `apps/daemon/src/core/db/migrations/0001_init.sql`. Until a stable migration contract is + announced, schema changes edit that file directly and require wiping/rebootstrapping + `~/.bazilion`; do not add ALTER migrations, legacy-table importers, or API/URL/filesystem + compatibility adapters. The bootstrap runner remains idempotent for an already-current schema. ## Already-shipped invariants (don't re-implement) - **Daemon = sole owner of `~/.bazilion`** — the worker subprocess delegates anything DB-backed (messaging tools, provider gate, agent resolution, secrets) back to the daemon over Node IPC + stdin. There is no per-worker SQLite handle. -- **Groups = single filesystem root + USER.md + roster + shared memory.** One agent → one group. `groups.user_md` is a DB column (agents can't clobber it via `write`/`edit`). Groups always live under `~/.bazilion/groups//` (real dir or symlink via `--link`). -- **Memory is group-shared.** `qmdBackend(group.path/memory)` — every member writes to and reads from the same store. Personal notes go to `IDENTITY.md` via `home_write`. -- **Canonical production harness model.** Agent templates are reusable Profiles. Team templates - (`harness_templates`) own one revisioned, stable-slot roster and directed policy. A live - Group owns exactly one effective revisioned policy; Agents are permanent resources with - exactly one Group membership. Do not create a second Team roster or detached live-harness - identity. Canonical HTTP surfaces are `/api/harness-templates` and - `/api/groups/:id/harness`; legacy Profile Group surfaces are compatibility adapters. -- **Harness enforcement covers every communication boundary.** With - `BAZILION_HARNESS_ENFORCEMENT=on`, the shared authorizer gates user/peer/cross-Group, +- **Teams = single filesystem root + USER.md + roster + shared memory.** One agent → one team. `teams.user_md` is a DB column (agents can't clobber it via `write`/`edit`). Teams always live under `~/.bazilion/teams//` (real dir or symlink via `--link`). +- **Memory is team-shared.** `qmdBackend(team.path/memory)` — every member writes to and reads from the same store. Personal notes go to `IDENTITY.md` via `home_write`. +- **Canonical production Team Policy model.** Agent templates are reusable Profiles. Team templates + (`team_templates`) own one revisioned, stable-slot roster and directed policy. A live + Team owns exactly one effective revisioned policy; Agents are permanent resources with + exactly one Team membership. Do not create a second Team roster or detached live Team Policy + identity. Canonical HTTP surfaces are `/api/team-templates` and `/api/teams/:id/policy`. +- **Team Policy enforcement covers every communication boundary.** With + `BAZILION_TEAM_POLICY_ENFORCEMENT=on`, the shared authorizer gates user/peer/cross-Team, scheduler, inbox, HTTP/worker turn, and Telegram ingress/egress boundaries. Missing edges deny. Durable block events contain policy evidence but never message payloads. The compiled management contract is version 1; do not add a bypass or a second authorization path. @@ -172,19 +175,22 @@ API in `apps/daemon/src/core/`: `openSecrets(db, password)` and `openConfig(db)` assignment engines. - **No runs/events tables, no stats CLI.** The runs/events audit layer was dropped in favor of pi's session JSONL files (which are the authoritative transcript). There is no `bazilion run list/show/cancel/prune` and no `bazilion stats`. Cancel is `bazilion agent cancel ` (keyed by agentId). - **Bootstrap auth lives in `auth.json`.** The daemon reads it once at startup (`getCtx().authToken`) and uses it as the PBKDF2 seed for the secrets table. The CLI reads it as its loopback bearer. The `bootstrap` row in `web_tokens` cannot be revoked — `DELETE /api/tokens/:id` rejects a hash match against the auth token. -- **First-run gate** — `isSetupComplete(db)` returns true iff at least one enabled provider has ≥1 curated model. Web middleware redirects non-API routes to `/welcome` while the gate is closed; API routes return 409. Allowed prefixes during setup: `/welcome`, `/login`, `/config`, `/api/config`, `/api/auth`, `/api/health`, `/api/login`. Crossing the threshold triggers `ensureSetupSeeded(db, paths)` which creates the `default` profile (skillsMode: `'all'`) + `default` group (at `~/.bazilion/groups/default/`). +- **First-run gate** — `isSetupComplete(db)` returns true iff at least one enabled provider has ≥1 curated model. Web middleware redirects non-API routes to `/welcome` while the gate is closed; API routes return 409. Allowed prefixes during setup: `/welcome`, `/login`, `/config`, `/api/config`, `/api/auth`, `/api/health`, `/api/login`. Crossing the threshold triggers `ensureSetupSeeded(db, paths)` which creates the `default` profile (skillsMode: `'all'`) + `default` team (at `~/.bazilion/teams/default/`). - **Spawn-time skill override is gone.** Skills come from the profile only — `skillsMode: 'all'` attaches every installed skill at spawn, `'selected'` uses `profile_default_skills`. Per-agent tweaks happen post-spawn via `bazilion agent skill add/rm` (or the per-agent skills card on the detail page). -- **Web client constants live in `apps/web/src/lib/wire-constants.ts`** (`DEFAULT_GROUP_ID`, `DEFAULT_PROFILE_ID`, `REASONING_LEVELS`). `apps/web/src/lib/daemon-client.ts` is server-only — Vite's import-protection rejects it from any client-bundled module. +- **Web client constants live in `apps/web/src/lib/wire-constants.ts`** (`DEFAULT_TEAM_ID`, `DEFAULT_PROFILE_ID`, `REASONING_LEVELS`). `apps/web/src/lib/daemon-client.ts` is server-only — Vite's import-protection rejects it from any client-bundled module. - **OpenClaw skill model: prompt-only.** Skills under `~/.bazilion/skills//` get their SKILL.md body injected into the system prompt of every agent they're attached to; helper scripts run via the agent's generic `bash` tool. No framework `entry:` extension, no trust gate. -- **qmd memory backend** (`apps/daemon/src/runtime/memory/qmd.ts`) — wraps `@tobilu/qmd`'s `searchLex` (BM25) for all memory routes. One `.qmd-index.sqlite` per group. Hybrid/vector paths are intentionally not enabled (pulls `node-llama-cpp` and multi-GB GGUF models; excluded in `pnpm.onlyBuiltDependencies`). +- **qmd memory backend** (`apps/daemon/src/runtime/memory/qmd.ts`) — wraps `@tobilu/qmd`'s `searchLex` (BM25) for all memory routes. One `.qmd-index.sqlite` per team. Hybrid/vector paths are intentionally not enabled (pulls `node-llama-cpp` and multi-GB GGUF models; excluded in `pnpm.onlyBuiltDependencies`). - **Heartbeats / cron triggers** (`agent_triggers` table; `apps/daemon/src/lib/scheduler.ts`) — in-process tick loop (default 5s, `BAZILION_SCHEDULER_TICK_MS`; disable with `BAZILION_SCHEDULER=off`) pinned to `globalThis[Symbol.for('bazilion.scheduler')]`. Interval kind uses `last_fired_at + every ≤ now` with `created_at` as baseline; cron kind parses 5-field expressions via `apps/daemon/src/lib/cron.ts`. Firing reuses `runAgentTurn`; `last_fired_at` is updated *before* the run kicks off so a restart mid-fire doesn't double-trigger. CLI: `bazilion trigger add|list|rm|enable|disable`. - **Inbox / messaging surfaces** — the `send_message` / `read_inbox` / `wait_for_reply` tools (`apps/daemon/src/runtime/tools/messaging.ts`) are wired with `MessagingHost` injection: in the daemon (compact/context routes) the host is `createDbMessagingHost(db)`; in the worker the host is `createIpcMessagingHost()` which proxies every method through Node IPC. Outside-the-loop surfaces: `GET /api/agents/:id/messages?unread=1` (list), `POST /api/agents/:id/messages` (now accepts `replyTo`), `GET|PATCH /api/messages/:id` (detail + mark-read). CLI: `bazilion inbox list [--unread]`, `inbox show `, `inbox read `. Web: `/agents/:id/inbox`. - **`web_fetch` hardening: Readability + markdown + cache + SSRF guard** — `@mozilla/readability` over `linkedom`, output as markdown (or text via `extract_mode`). SSRF guard at `apps/daemon/src/runtime/tools/web-ssrf.ts` blocks loopback/private/link-local + DNS rebinding (re-validates resolved IPs, pins them into undici's `Agent.connect.lookup`). 15-min in-memory LRU per `${mode}|${url}` (100-entry cap). UA spoofs desktop Safari. 20s default timeout, 3 max redirects. - **ChatGPT OAuth / `openai-codex` provider** — credentials in `secrets:OPENAI_CODEX_OAUTH`. CLI runs the loopback flow (port 1455) client-side and PUTs credentials to `/api/auth/openai`; web `/config` has a "Connect ChatGPT" card. `apps/daemon/src/lib/api-key.ts:resolveAgentApiKey` is the single helper every session-creating call site uses to pre-fetch the access token; for daemon-side sessions it also wires a refresher for mid-turn JWT swaps. Worker turns don't get the refresher today (they'd need a new IPC method). -- **Profile Groups — preconfigured team templates** (`profile_groups` + `profile_group_members` tables, migration `0002_profile_groups.sql`; shipped in v0.2.0). A profile group is an ordered list of *members*, each pointing at a profile with optional per-member overrides (`agent_name`, `model_override`, `reasoning_level`). `apps/daemon/src/core/profile-group/spawn.ts:spawnProfileGroup` is one transactional call that materializes the whole team — pre-flight validates every `profileId`, snapshots both `agents/` and `groups/` dirs before the tx, and on any failure cleans the dir-diff with `rmWithRetry` (100/500/2000 ms backoff, extracted into `core/profile-group/rm-with-retry.ts` for testability). Name collisions auto-suffix `-2`, `-3`, … against agents already in the target group. Target group is auto-created if its slug doesn't exist; `userMd` from the request seeds USER.md only on a freshly-created group. HTTP: `/api/profile-groups[/:id[/members|spawn]]`. CLI: `bazilion profile-group create|list|show|update|edit|delete|spawn`. Web: top-nav `templates` tab (shared with profiles via `apps/web/src/components/TemplatesTabs.tsx`), `/profile-groups` list + detail, sidebar `+ new ▾` two-section dropdown (spawn agent from template / spawn group from template), empty-group CTA on `/groups/:id`. Wire types `ProfileGroup`, `ProfileGroupMember`, `ProfileGroupDetail`, `ProfileGroupWithCount` in `@bazilion/api-types`. Strictly additive — the single-profile `POST /api/agents` spawn path is untouched. +- **Team Templates are the only reusable Team roster.** `team_templates` owns revisioned + stable slots and policy edges. HTTP uses `/api/team-templates`, CLI uses + `bazilion team-template`, and web uses `/templates/teams`. Do not add a second roster model + or compatibility alias. - **Shared web ` )} - {prototypeInputBlocked && ( -
- Composer disabled: this harness denies direct user input to {agentName}. -
- )} ) } @@ -1102,7 +1054,7 @@ function Bubble({ entry, isLastUser, isWillDrop, onEdit }: BubbleProps) { ) } return ( -
+
you {entry.images && entry.images.length > 0 && (
@@ -1140,7 +1092,7 @@ function Bubble({ entry, isLastUser, isWillDrop, onEdit }: BubbleProps) { type="button" onClick={onEdit} title="edit and resend — replaces the last turn" - className="absolute left-1 top-1 rounded-sm border border-fawn bg-ivory px-2 py-0.5 text-[0.78em] font-medium text-mocha opacity-65 transition hover:border-sapphire hover:bg-sapphire-glow hover:text-sapphire hover:opacity-100 group-hover:opacity-100 group-focus-within:opacity-100" + className="absolute left-1 top-1 rounded-sm border border-fawn bg-ivory px-2 py-0.5 text-[0.78em] font-medium text-mocha opacity-65 transition hover:border-sapphire hover:bg-sapphire-glow hover:text-sapphire hover:opacity-100 team-hover:opacity-100 team-focus-within:opacity-100" > edit diff --git a/apps/web/src/components/CreateGroupDialog.tsx b/apps/web/src/components/CreateTeamDialog.tsx similarity index 90% rename from apps/web/src/components/CreateGroupDialog.tsx rename to apps/web/src/components/CreateTeamDialog.tsx index c6954fb..b78386b 100644 --- a/apps/web/src/components/CreateGroupDialog.tsx +++ b/apps/web/src/components/CreateTeamDialog.tsx @@ -1,6 +1,6 @@ -// Quick-create a group from the sidebar's spawn dropdown. POSTs to -// /api/groups with the current shape: { id, name?, link? }. The daemon -// puts the slot under ~/.bazilion/groups// — a fresh directory by +// Quick-create a team from the sidebar's spawn dropdown. POSTs to +// /api/teams with the current shape: { id, name?, link? }. The daemon +// puts the slot under ~/.bazilion/teams// — a fresh directory by // default, or a symlink to `link` if provided. import { useRouter } from '@tanstack/react-router' @@ -10,7 +10,7 @@ interface Props { onClose: () => void } -export function CreateGroupDialog({ onClose }: Props) { +export function CreateTeamDialog({ onClose }: Props) { const router = useRouter() const [id, setId] = useState('') const [name, setName] = useState('') @@ -30,7 +30,7 @@ export function CreateGroupDialog({ onClose }: Props) { const body: Record = { id: id.trim() } if (name.trim()) body.name = name.trim() if (link.trim()) body.link = link.trim() - const res = await fetch('/api/groups', { + const res = await fetch('/api/teams', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body), @@ -59,10 +59,10 @@ export function CreateGroupDialog({ onClose }: Props) { onClick={(e) => e.stopPropagation()} className="w-full max-w-md rounded-2xl border bg-card p-6 shadow-lg" > -

Create a new group

+

Create a new team

- A group is a collaboration context — one filesystem root, one USER.md, one roster. The - slot lives at ~/.bazilion/groups/<slug>/. + A team is a collaboration context — one filesystem root, one USER.md, one roster. The + slot lives at ~/.bazilion/teams/<slug>/.

{err &&

{err}

} - {preview &&

Creating this Agent advances Group revision {preview.currentRevision} → {preview.resultingRevision} and adds {preview.addedEdges.length} directed edges to the existing {preview.existingEdges.length}.

    {preview.addedEdges.map((edge,index)=>
  • ${edge.targetKind}:${edge.targetId??''}:${index}`}>{edge.sourceKind}{edge.sourceId?`:${edge.sourceId}`:''} → {edge.targetKind}{edge.targetId?`:${edge.targetId}`:''}
  • )}
{preview.addedEdges.length===0&&

The new Agent starts isolated.

}
} + {preview &&

Creating this Agent advances Team revision {preview.currentRevision} → {preview.resultingRevision} and adds {preview.addedEdges.length} directed edges to the existing {preview.existingEdges.length}.

    {preview.addedEdges.map((edge,index)=>
  • ${edge.targetKind}:${edge.targetId??''}:${index}`}>{edge.sourceKind}{edge.sourceId?`:${edge.sourceId}`:''} → {edge.targetKind}{edge.targetId?`:${edge.targetId}`:''}
  • )}
{preview.addedEdges.length===0&&

The new Agent starts isolated.

}
}