Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions crates/buzz-acp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,65 @@ Each channel has at most one prompt in flight. Multiple channels can be processe

> **Note:** On startup, the harness replays all unprocessed @mentions since the last run. Expect a burst of activity if there are stale events in the channel.

## Bring Your Own Harness (BYOH)

Buzz Desktop supports registering any ACP-speaking agent tool as a selectable runtime without a PR.

### How it works

**Tier-1 — compiled-in runtimes** (Goose, Claude Code, Codex, Buzz Agent): have auto-installers, auth probes, and first-class onboarding. Their IDs (`goose`, `claude`, `codex`, `buzz-agent`) are reserved and cannot be overridden.

**Tier-2 — preset catalog** (Cursor, Oh My Pi, Grok Build, OpenCode, Kimi Code, Amp, Hermes Agent, OpenClaw): static `HarnessDefinition` entries in `desktop/src-tauri/src/managed_agents/discovery.rs` (`PRESET_HARNESSES`). They are always present in the runtime catalog, PATH-probed for availability, not editable or deletable by the user. Displayed with bundled logos; if not installed, a docs link appears instead.

> **Note — OpenClaw:** `openclaw acp` is a Gateway-backed bridge; PATH availability shows "Available" even when the OpenClaw Gateway daemon is not running. This is expected tier-2 semantics (same class as a preset with unconfigured auth). The Gateway URL is configured via `OPENCLAW_GATEWAY_URL` (or the equivalent env var from OpenClaw's docs) — set it in the agent's **env vars** in Edit Agent, not in the definition env (the preset definition carries no env entries). Note that `openclaw acp` executes tools inside the Gateway daemon, not the Desktop process, so Desktop-injected `BUZZ_*` env vars do NOT reach the execution locus unless you also set them on the Gateway's own environment.

**Tier-3 — user custom harnesses**: JSON files in `<app-data>/custom_harnesses/` that the user can create from the Settings UI or drop in directly. Each file describes one harness — no install scripts.

### Custom harness JSON schema

```json
{
"id": "my-agent",
"label": "My Agent",
"command": "my-agent-bin",
"args": ["acp"],
"env": {
"MY_AGENT_MODE": "acp"
},
"installInstructionsUrl": "https://example.com/docs",
"installHint": "Download from example.com"
}
```

Fields:
- `id` — `[a-z0-9_][a-z0-9_-]*` (used as the runtime picker value and file name)
- `label` — human-readable name shown in the UI
- `command` — the executable name or absolute path (must be non-empty)
- `args` — optional default CLI arguments (array); instance-level args override this when non-empty
- `env` — optional environment variables injected at spawn time (definition env is a floor; user/persona/global env overrides it; Buzz-reserved keys like `BUZZ_MANAGED_AGENT` are always stripped and cannot be overridden)
- `installInstructionsUrl` / `installHint` — shown when the binary is not on PATH

Invalid files (bad JSON, unknown id, empty command) are skipped with a warning and do not break discovery for other entries.

### Security guarantees

- No install shell commands in preset or custom definitions — only the user's own PATH is consulted.
- `can_auto_install` is always `false` for preset and custom entries.
- No user-supplied icon URLs — icons are bundled assets keyed by id in `RuntimeIcon.tsx`.
- `BUZZ_MANAGED_AGENT` and other Buzz identity keys cannot be overridden by `env` in a custom definition; they are stripped before merging.

### Adding a preset (contributor guide)

To add a new runtime to the tier-2 gallery:

1. **Verify the ACP entrypoint** from the vendor's own documentation — do not rely on a PR description alone. Test with the actual binary.
2. **Add a `HarnessDefinition` entry** to the `PRESET_HARNESSES` slice in `desktop/src-tauri/src/managed_agents/discovery.rs`. Fill `id`, `label`, `command`, `args`, `install_instructions_url`, `install_hint`. Leave `env` empty unless the harness requires a specific env var to enable ACP mode.
3. **Add the preset id to `BUILTIN_IDS`** in `desktop/src-tauri/src/managed_agents/custom_harnesses.rs` so custom JSON files cannot shadow it.
4. **Add a bundled logo** (64×64 PNG or optimised SVG) to `desktop/public/harness-logos/<id>.png` and add a corresponding entry to `PRESET_LOGOS` in `desktop/src/features/onboarding/ui/RuntimeIcon.tsx`. Record the source and license in `desktop/public/harness-logos/CREDITS.md`. Only bundle a mark whose upstream license permits redistribution; skipping this step is caught by `presetLogos.test.mjs`, which asserts every `PRESET_HARNESSES` id has a mapped logo that exists on disk.
5. Run `cargo test --lib` and `just desktop-typecheck` to verify everything compiles.

The built-in `BUILTIN_IDS` set (`goose`, `claude`, `codex`, `buzz-agent`, and all current preset ids) is the reserved namespace; every other id is available for custom harnesses.

## Using Any ACP Agent

The harness works with any agent that implements the [ACP spec](https://agentclientprotocol.com/) over stdio. The requirements are:
Expand Down
1 change: 1 addition & 0 deletions desktop/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export default defineConfig({
"**/inbox-live-update.spec.ts",
"**/mesh-compute.spec.ts",
"**/observer-archive-policy.spec.ts",
"**/harness-management.spec.ts",
],
use: {
...devices["Desktop Chrome"],
Expand Down
22 changes: 22 additions & 0 deletions desktop/public/harness-logos/CREDITS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Preset harness logos — provenance

Third-party marks bundled to identify tier-2 preset harnesses in the runtime
gallery (`PRESET_LOGOS` in `desktop/src/features/onboarding/ui/RuntimeIcon.tsx`).
Nominative use only — each mark identifies its own vendor's harness.

Add a row here when adding a preset logo; only bundle marks whose upstream
license permits redistribution.

| File | Upstream | Commit | License | Source path | Modifications |
|---|---|---|---|---|---|
| `hermes.png` | [NousResearch/hermes-agent](https://github.com/NousResearch/hermes-agent) | `6ad632b` | MIT © 2025 Nous Research | `website/static/img/logo.png` | Cropped the baked-in border frame, padded to square, resized to 64×64, quantised to a 16-colour palette |
| `openclaw.svg` | [openclaw/openclaw](https://github.com/openclaw/openclaw) | `b06f40a` | MIT © 2026 OpenClaw Foundation | `ui/public/favicon.svg` | Removed the SMIL animation elements (renders the upstream rest pose statically — verified pixel-identical to the upstream frame at t=0); minified paths |
| `omp.svg` | [can1357/oh-my-pi](https://github.com/can1357/oh-my-pi) | `667111575ebba136dadfd6989379e7f67e0d40d9` | MIT © 2025 Mario Zechner; © 2025–2026 Can Bölük | `assets/icon.svg` | None |
| `kimi.png` | [MoonshotAI/kimi-cli](https://github.com/MoonshotAI/kimi-cli) | `4a550effdfcb29a25a5d325bf935296cc50cd417` | Apache-2.0; NOTICE: Kimi Code CLI © 2025 Moonshot AI | `web/public/logo.png` | None |
| `grok.svg` | [SpaceXAI brand guidelines](https://x.ai/legal/brand-guidelines) | Retrieved 2026-07-25 | xAI Brand Guidelines: marks may be used to accurately refer to xAI or its services; logos must be used exactly as provided | `SpaceXAI_Grok_Assets.zip` → `Grok_Logomark_Dark.svg` | None |

`amp.png` and `opencode.svg` predate this file; their provenance was not
recorded when they were added. Cursor intentionally uses the generic terminal
fallback: Cursor's official brand page offers downloadable assets, but neither
that page nor its Terms of Service grants third parties permission to
redistribute them. The previous unproven `cursor.png` was removed.
Binary file added desktop/public/harness-logos/amp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions desktop/public/harness-logos/grok.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desktop/public/harness-logos/hermes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desktop/public/harness-logos/kimi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions desktop/public/harness-logos/omp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions desktop/public/harness-logos/openclaw.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions desktop/public/harness-logos/opencode.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
85 changes: 76 additions & 9 deletions desktop/scripts/check-file-sizes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,20 @@ const overrides = new Map([
// record_provider param + applies persona_field_with_record_fallback. +5 lines.
// global-agent-config: spawn_agent_child loads global config and merges as
// lowest env layer (+8 lines). Queued to split.
["src-tauri/src/managed_agents/runtime.rs", 2216],
// +2: BYOH orphan-sweep fix — `!belongs && !has_buzz_marker` OR-gate replaces
// the old AND-gate so custom harness processes are not silently leaked on crash.
// +27: BYOH F4 fix — extract shared `buzz_sweep_owns_process` predicate, fix
// Linux AND-gate in sweep + orphan collectors, 4 production predicate tests.
// +12: BYOH F2 — record_agent_command / effective_agent_command check loaded
// harness registry for preset/custom ids after static-builtin lookup.
// +61: BYOH pass-2 — I2 (spawn_agent_child env+args from definition), I3
// (valid_agent_runtime_receipt uses buzz_sweep_owns_process marker-only),
// I6 (cross-platform buzz_sweep_owns_process, drop #[cfg(unix)]), +2 new
// receipt-path collector-decision tests.
// +2: BYOH Phase A — resolve_effective_harness_descriptor single typed resolver;
// C-9 injectable sweep predicates (kill_stale_tracked_processes_with +
// valid_agent_runtime_receipt_with) with 5 discriminating tests.
["src-tauri/src/managed_agents/runtime.rs", 2326],
// config-bridge setup-payload env-boundary fix adds readiness wiring in
// spawn_agent_child; load-bearing security fix, queued to split.
["src-tauri/src/managed_agents/config_bridge/reader.rs", 1016],
Expand Down Expand Up @@ -177,11 +190,15 @@ const overrides = new Map([
// Windows Doctor install fix: cli_install_commands_windows field added to test stubs.
// team-instructions-first-class: ManagedAgentRecord fixture gains the new
// team_id field (+1 line).
["src-tauri/src/managed_agents/readiness.rs", 1765],
["src-tauri/src/managed_agents/readiness.rs", 1863],
// Windows PATH-correctness fix: 3 #[cfg(windows)] test functions covering
// .cmd shim rejection, .bat shim rejection, and .exe acceptance for
// configure_runtime_cli (fix #2397). Test-only growth; queued to split.
["src-tauri/src/managed_agents/runtime/tests.rs", 1041],
// +34: BYOH custom-harness sweep condition unit tests — 3 tests validating
// the OR-gate fix for custom-binary orphan cleanup.
// +26: BYOH pass-2 I3 — 2 collector-decision tests for receipt path
// ownership (valid_agent_runtime_receipt uses buzz_sweep_owns_process).
["src-tauri/src/managed_agents/runtime/tests.rs", 1320],
// applyWorkspace reposDir parameter plus the validateReposDir binding,
// threaded through Tauri invokes for configurable repos_dir, plus the
// harness-persona-sync `harnessOverride` create-input bit — load-bearing
Expand Down Expand Up @@ -231,7 +248,12 @@ const overrides = new Map([
// doc comment) and AgentTeam/CreateTeamInput/UpdateTeamInput.instructions
// (+3) — the new team-id spawn link and the runtime-layered instructions
// field.
["src/shared/api/types.ts", 1047],
// byoh-env-roundtrip: AcpRuntimeCatalogEntry.definitionEnv field + JSDoc
// (+12 lines) so the edit form can read back existing env vars on save.
// Load-bearing correctness fix. Queued to split.
// +2: AcpRuntimeCatalogEntry.requiresExternalCli field added by main
// (#2680) to indicate runtimes that need a separate CLI install.
["src/shared/api/types.ts", 1051],
// readiness-gate: PersonaDialog.tsx threads computeLocalModeGate +
// requiredCredentialEnvKeys + RequiredFieldLabel so the "New agent" dialog
// shows required markers and credential amber rows (parity with
Expand Down Expand Up @@ -296,7 +318,37 @@ const overrides = new Map([
// Buzz-managed Node path helpers and resolution tests moved to
// managed_node_paths.rs and discovery/tests/managed_path_resolution.rs;
// ratcheting 1366 -> 1392 after adding the managed-path probes to discovery.
["src-tauri/src/managed_agents/discovery.rs", 1393],
// +17: BYOH custom harness catalog merge phase-3 — append custom definitions
// from custom_harnesses_dir with PATH-probe availability; source tagging.
// +148: BYOH F2/F3 — PRESET_HARNESSES static data (6 presets), Phase 2.5 in
// discover_acp_runtimes_from (PATH-probe each preset, build catalog entries,
// populate loaded-harness registry), record/effective command resolution now
// checks loaded registry for preset/custom ids. Queued to split presets out.
// +3: BYOH F5 — seen_ids rejects preset/builtin collisions from custom files.
// +79: BYOH pass-2 C1 — 4 registry lifecycle tests (warm→spawn, delete→
// dangling, immediate save+start, edit with rename); try_record_agent_command
// typed error for dangling ids wired into spawn; readiness/spawn_hash now
// include definition env floor.
// +7: BYOH pass-2 I2 env round-trip — definition_env field populated in
// custom catalog entries + 2 discriminating tests (custom env preserved,
// builtin env empty). Load-bearing edit round-trip fix.
// +16: BYOH scope addition — Hermes Agent + OpenClaw preset entries (two
// data-only PresetHarness structs; no new logic or test functions).
// +29: rebase over main (#2680) — discover_acp_runtime_phase1 extracted
// helper + discover_acp_runtime_availability; both load-bearing for
// post-install verification. Semantic composition with BYOH changes.
// +17: merge of main (#2767) — codex_adapter_is_outdated_with_path split out
// so Codex adapter planning takes an explicit PATH. Auto-merged cleanly; only
// the ceiling needed composing with the BYOH growth above.
["src-tauri/src/managed_agents/discovery.rs", 1732],
// BYOH — save_custom_harness_to_dir (backup-swap atomic write) + save_and_warm /
// delete_and_warm (persist-mutex serialization for concurrent-safe registry
// refresh, B-6). Also: id/collision/load/registry tests (from the file base) +
// B-4 real persistence tests (create, same-id edit, rename, backup cleanup) +
// B-3 env validation boundary tests (malformed key, reserved shape, NUL,
// size limit, ownership marker). Load-bearing correctness/security coverage;
// queued to extract helper module once the feature stabilizes.
["src-tauri/src/managed_agents/custom_harnesses.rs", 1045],
// rebase over codex-acp-package-swap: its version-probe tests union with the
// doctor-install-reliability nvm/login-shell/semver tests — each side alone
// stayed under the 1000 default; the union exceeds it.
Expand All @@ -307,7 +359,11 @@ const overrides = new Map([
// None regression, .cmd shim resolution, no-git-bash error hint.
// +32: deterministic .cmd resolver + no-registry + install_shell_from tests.
// Managed-path resolution test split to discovery/tests/managed_path_resolution.rs.
["src-tauri/src/managed_agents/discovery/tests.rs", 1273],
// +227: BYOH pass-2 C1 — 4 registry lifecycle tests (warm→spawn, delete→dangling,
// immediate save+start, edit with rename) added to discovery/tests.rs.
// +64: BYOH pass-2 I2 env round-trip — 2 discriminating tests proving custom
// catalog entries carry definition_env and builtins do not.
["src-tauri/src/managed_agents/discovery/tests.rs", 1576],
// identity-import-keyring: the identity resolution state machine's behavioral
// matrix (46 tests over FakeIdentityStore — probe × marker × file cells,
// adoption / read-back-corruption / marker-failure arms, recovery-mode
Expand Down Expand Up @@ -500,9 +556,20 @@ const overrides = new Map([
// Includes unit tests for detection, routing, and -Command body preservation.
// +16: test_powershell_command_goose_catalog_dequoted proves the \$→$ escape
// fix for the Goose Windows installer (PR #2680 interaction with #2750).
// +10: pass an explicit PATH through Codex adapter install planning so unit
// tests avoid the process-global login-shell PATH cache.
["src-tauri/src/commands/agent_discovery.rs", 1836],
// +126: BYOH — save_custom_harness (validate, atomic write, return entry) +
// delete_custom_harness (id-guard, builtin reject, remove file) commands;
// discover_acp_providers updated to pass AppHandle + custom_harnesses dir.
// +30: BYOH F5 — atomic-write-file dep, original_id rename/delete support.
// +13: BYOH pass-2 C1 — warm_harness_registry_from_dir call in save and
// delete commands now verifies transactional registry refresh.
// +2: BYOH pass-2 I2 env round-trip — definition_env carried through save
// return value so the frontend immediately has the updated env.
// +1: rebase over main (#2680) — requires_external_cli: false added to
// save_custom_harness catalog entry construction (new required field).
// +10: merge of main (#2767) — pass an explicit PATH through Codex adapter
// install planning so unit tests avoid the process-global login-shell PATH
// cache. Independent of the BYOH growth above; the two deltas compose.
["src-tauri/src/commands/agent_discovery.rs", 2048],
// draft-persistence predicate: submit-time `loadDraft` check + inline comment
// + deps-array entry in submitMessage closes the never-persisted-boundary
// defect (Thufir Pass-3 finding). Load-bearing correctness fix; queued to
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
/gen/schemas

# Sidecar binaries (built by scripts/bundle-sidecars.sh)
/binaries/
/binaries
1 change: 1 addition & 0 deletions desktop/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading