Skip to content

upstream(sync): Tier 1 ACP harness — Claude config, Goose prompt, workspace scan - #311

Merged
oscarlehuu merged 5 commits into
mainfrom
devin/issue-282-acp-harness-tier1
Aug 23, 2026
Merged

upstream(sync): Tier 1 ACP harness — Claude config, Goose prompt, workspace scan#311
oscarlehuu merged 5 commits into
mainfrom
devin/issue-282-acp-harness-tier1

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 22, 2026

Copy link
Copy Markdown

Summary

Tier 1 of the Buzz 0.5.18 upstream sync (meta #285): ports the three ACP-harness changes in scope for #282, keeping Crew behaviour wherever upstream conflicts with it.

block#6261 — workspace scan guardrail. The base prompt and pool.rs::workspace_section() no longer forbid reading outside the working directory outright; they steer the agent to start there while explicitly allowing a path the user names:

- start there for your own files rather than scanning `$HOME` or `/`.
+ When the user names a specific path, read it.

block#5964 — Goose custom system prompt. _goose/unstable/session/system-prompt/set now sends "mode": "set" instead of "append", so Buzz's prompt replaces rather than accretes across sessions. Contract test renamed accordingly (goose_system_prompt_request_uses_set_contract).

block#4557 — Claude Code managed-agent config gaps. Five gaps, all spawn/session-scoped:

  1. Single startup model authority. For local claude agents the resolved effective model is written as ANTHROPIC_MODEL and BUZZ_ACP_MODEL is removed (managed_agents/claude_config), so BUZZ_ACP_MODEL means "live ACP switch" only. Remote deploys get the same authority through policy_env in agents_deploy.
  2. Persisted effort. ManagedAgentRecord.effort_level + persist_agent_effort_level command; injected at spawn as BUZZ_ACP_EFFORT_LEVEL after descriptor.env, so a canonical value cannot be shadowed by user env. SpawnConfigSnapshot carries exactly one representation (effort_level, env key stripped) so an authority handoff at the same value produces no phantom drift entry.
  3. Adapter-advertised thought_level. extract_thought_level_config_id() discovers the adapter's real configId from session/new (accepting both configId and id) instead of hardcoding "effort"; the config panel and picker render the adapter's option values.
  4. CLAUDE_CONFIG_DIR. Claude's MCP config path resolves to $CLAUDE_CONFIG_DIR/.claude.json when set, and the panel surfaces claude_config_dir_custom so the Keychain-namespace caveat is visible instead of silently logging the agent out.
  5. Honest live model-switch outcomes. ControlSignal::SwitchModel carries an opaque per-pick request_id that is echoed on every control_result frame, so a replayed or stale result cannot settle a later pick. Only a real switched frame is success; adapter rejection emits a terminal failure, and a timeout resolves pending rather than a false success. Busy-path switches emit their positive terminal at the deferred apply.

Divergences from upstream (Crew guardrails)

Related issue

Fixes #282. Part of the sync stack in #285; guardrails from #278.

Testing

TDD: tests committed first (c639197b0) and shown failing, then the implementation (b752fe9d4).

Gates run locally on the Hermit toolchain (Node 24.15.0 / pnpm 11.4.0):

gate result
pnpm --filter buzz check pass
pnpm --filter buzz typecheck pass
pnpm --filter buzz test pass — 5542 passed, 1 skipped
just check-compile pass
cargo test -p buzz-acp --lib pass — 1031 passed
desktop/src-tauri cargo test --workspace pass — 2832 passed, 15 ignored
just desktop-tauri-clippy pass
just test-unit pre-existing failures only (see below)

just test-unit fails on four tests unrelated to this change, verified identical on a clean origin/main worktree: buzz-cli tests::command_inventory_is_stable, tests::subcommand_counts_are_stable, tests::subcommand_names_are_stable, and buzz-db migration::tests::embedded_migrator_contains_consolidated_initial_schema. No buzz-cli/buzz-db files are touched here. just fmt-check / just clippy likewise fail only on pre-existing findings in untouched files (crew-wiki/src/publish.rs, buzz-acp/src/guided_handover.rs); neither gate runs in PR CI.

Full untruncated RED/GREEN/gate logs are attached to the session; UI evidence for the effort picker, model-picker outcomes and config panel follows in a comment.


UI evidence

Captured through the Playwright E2E mock bridge (build:e2e, full-app fullPage shots at 1560x1100). BEFORE comes from main in a scratch worktree using the identical temporary mock seed, so each pair differs only by product code. The shipped mock bridge does not advertise the new RuntimeConfigSurface fields (effortConfigId, effortOptions, claudeConfigDirCustom), so a throwaway flag-gated seed supplied them; it is not committed.

1. Effort ("thought level") picker in the managed-agent edit dialog. Preselects the configured adapter value High, lists exactly the adapter-advertised options plus the Adapter default sentinel, and picking Low calls persist_agent_effort_level {"pubkey":"953d…001f","effortLevel":"low"}; the config panel then re-reads low configured vs medium running.

AFTER — field present and preselected:

after edit dialog effort field

AFTER — options open:

after effort options open

AFTER — Low selected:

after effort selected low

BEFORE (main) — no Thinking effort field in the dialog:

before edit dialog

2. Claude CLAUDE_CONFIG_DIR caveat + MCP config-file attribution.

AFTER (caveat plus From config file (~/work/claude-isolated/.claude.json)):

after config panel caveat

BEFORE (main) — neither present:

before config panel

AFTER — panel re-read after the pick:

after config panel effort after pick

BEFORE — same view on main:

before config panel effort after pick

Two notes on this panel: the caveat renders twice (once under Model settings, once under MCP servers) — that is faithful to upstream block#4557, which mounts ClaudeConfigDirNotice in both sections; and the configured-vs-running effort facts already exist on main, so only the caveat and the config-file caption are new here.

3. ModelPicker live-switch outcomes — no UI screenshot. The correlated success / failure / pending states need an in-flight ACP switch producing real control_result frames, which the mock bridge cannot originate; they are covered by unit tests instead (liveSwitchOutcome.test.mjs — correlation by requestId, channel matching, duplicate results, adapter failure, pending on timeout, non-delivery — plus the Rust pool tests for the busy-path deferred terminal).


NOTES (handover)

DONE

All three ports in #282's scope are implemented, tested and pushed — the branch is in a coherent, complete state at f1fd9b6 (3 signed commits: tests → implementation → doc/gate fixups).

  • fix(buzz-acp): loosen workspace-scan guardrail to allow named paths block/buzz#6261 workspace-scan guardrail loosened in crates/buzz-acp/src/base_prompt.md and pool.rs::workspace_section() (start in the working dir, but read a path the user names).
  • fix(acp): replace Goose native system prompt block/buzz#5964 Goose _goose/unstable/session/system-prompt/set now sends "mode": "set"; contract test renamed to goose_system_prompt_request_uses_set_contract.
  • feat(managed-agents): close five Claude Code agent-config gaps block/buzz#4557 all five Claude Code config gaps: ANTHROPIC_MODEL as the single startup model authority (with BUZZ_ACP_MODEL stripped) for local and remote-deployed claude agents; persisted ManagedAgentRecord.effort_level + persist_agent_effort_level command injected at spawn as BUZZ_ACP_EFFORT_LEVEL after descriptor.env; adapter-advertised thought_level configId discovery (extract_thought_level_config_id) instead of a hardcoded "effort"; CLAUDE_CONFIG_DIR-aware MCP config path plus the Keychain caveat surfaced through claude_config_dir_custom; and requestId-correlated live model-switch outcomes where only a real switched frame is success (rejection → terminal failure, timeout → pending).

Tests were written first and shown failing before implementation (RED logs below), covering: the Goose set-contract, the named-path workspace wording, extract_thought_level_config_id (configId/id/absent), Claude model + effort env application, effective Claude config dir and effort-option discovery, effort persistence command, spawn-snapshot effort resolution, and the expanded liveSwitchOutcome matrix (correlation, channel matching, duplicate results, failure, pending, non-delivery).

Gates (Hermit toolchain, Node 24.15.0 / pnpm 11.4.0):

gate result
pnpm --filter buzz check pass
pnpm --filter buzz typecheck pass
pnpm --filter buzz test pass — 5542 passed, 1 skipped
just check-compile pass
cargo test -p buzz-acp --lib pass — 1031 passed
desktop/src-tauri cargo test --workspace pass — 2832 passed, 15 ignored
just desktop-tauri-clippy pass
just test-unit pre-existing failures only
just fmt-check, just clippy pre-existing findings only

just test-unit fails on buzz-cli tests::command_inventory_is_stable, tests::subcommand_counts_are_stable, tests::subcommand_names_are_stable and buzz-db migration::tests::embedded_migrator_contains_consolidated_initial_schema; all four reproduce identically on a clean origin/main worktree (baseline-main-test-unit.log) and no buzz-cli/buzz-db file is touched here. just fmt-check/just clippy fail only in untouched files (crew-wiki/src/publish.rs, buzz-acp/src/guided_handover.rs). None of those three gates run in PR CI.

Evidence — full untruncated logs and full-app before/after screenshots (also embedded above), all under /home/ubuntu/evidence-282/:

baseline.log, baseline-main-test-unit.log, red-buzz-acp.log, red-desktop-tauri.log, red-pnpm-test.log, green-buzz-acp.log, green-desktop-tauri.log, green-pnpm-test.log, gate-pnpm-check.log, gate-pnpm-typecheck.log, gate-check-compile.log, gate-test-unit.log, gate-desktop-tauri-clippy.log, gate-desktop-tauri-fmt-check.log, gate-fmt-check.log, gate-clippy.log, base-smoke-targeted.log, test-plan.md, and the UI pairs in evidence-282/ui/ (before-/after-A1..A4 edit dialog + effort picker, before-/after-B1, B1a, B1b, B2, B2a config panel). Screencast: /home/ubuntu/screencasts/issue-282-ui/issue-282-ui-edited.mp4.

IN PROGRESS

Nothing half-done in the code — the working tree is clean apart from four deliberately uncommitted evidence-capture scaffolds: desktop/tests/e2e/tmp-282-effort-evidence.spec.ts, desktop/tests/e2e/tmp-282-drive.spec.ts, desktop/playwright.tmp282.config.ts, desktop/playwright.tmp282drive.config.ts. Reproducing the evidence run also needs the reverted mock-bridge seed at /home/ubuntu/evidence-282/tmp-e2ebridge-effort-seed.patch re-applied (the shipped E2E bridge advertises none of the new RuntimeConfigSurface fields). These are intentionally not part of the PR.

TODO / NEXT

  • CI is not green, and none of it is a code failure. Desktop Rust (job 97012531807) failed before any build step: hermit bootstrap curl: (35) Recv failure: Connection reset by peer, exit 35 — pure infrastructure. NuncioCrew Gate (job 97012244444) failed with desktop-fast must be success when desktop=true, got cancelled, i.e. the gate observing the parent session's deliberate cancellation of the first run. The earlier Desktop Smoke E2E (1) failures (channel-mute opacity, channels description text, community-rail keyboard reorder, composer-selection-formatting theme colour) reproduce on a clean origin/main worktree — see base-smoke-targeted.log. Per instruction nothing under .github/ was touched and no fix was attempted; the run needs re-running by whoever owns CI serialization.
  • Two open decisions. The CLAUDE_CONFIG_DIR caveat renders twice in the config panel (under Model settings and under MCP servers). That is faithful to upstream feat(managed-agents): close five Claude Code agent-config gaps block/buzz#4557, which mounts ClaudeConfigDirNotice in both sections — decide whether Crew wants it deduped. And the ModelPicker live-switch success/failure/pending states have unit coverage but no screenshot: they need real control_result frames, which the E2E mock bridge cannot originate.
  • Merge-conflict risk with the sibling 0.5.18 sync PRs is concentrated in crates/buzz-acp/src/{acp.rs,pool.rs,lib.rs,config.rs}, desktop/src-tauri/src/managed_agents/{runtime.rs,types.rs,spawn_snapshot.rs,config_bridge/*} and desktop/src/shared/api/types.ts. Two deliberate divergences to preserve on any rebase: RelayMeshConfig stays inline in managed_agents/types.rs (upstream's extraction to types/relay_mesh.rs was not taken), and upstream's comment-shrinking churn is not ported. Channel-first IA per upstream(sync): Guardrail — preserve channel-first IA during 0.5.18 merge #278 is untouched — no Projects/Workbench/sidebar edits.
  • A skill-PR suggestion for .agents/skills/headless-evidence-capture/SKILL.md (whole-app before/after capture pitfalls) is pending in the requester's timeline; the local edit was reverted so it is not in this branch.

Link to Devin session: https://app.devin.ai/sessions/e34f622c9a324475a5ab8c0f9f33beb3
Requested by: @oscarlehuu

@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

devin-ai-integration Bot commented Aug 22, 2026

Copy link
Copy Markdown
Author

NOTES (handover)

DONE

All three ports in #282's scope are implemented, tested and pushed — the branch is in a coherent, complete state at f1fd9b6 (3 signed commits: tests → implementation → doc/gate fixups).

  • fix(buzz-acp): loosen workspace-scan guardrail to allow named paths block/buzz#6261 workspace-scan guardrail loosened in crates/buzz-acp/src/base_prompt.md and pool.rs::workspace_section() (start in the working dir, but read a path the user names).
  • fix(acp): replace Goose native system prompt block/buzz#5964 Goose _goose/unstable/session/system-prompt/set now sends "mode": "set"; contract test renamed to goose_system_prompt_request_uses_set_contract.
  • feat(managed-agents): close five Claude Code agent-config gaps block/buzz#4557 all five Claude Code config gaps: ANTHROPIC_MODEL as the single startup model authority (with BUZZ_ACP_MODEL stripped) for local and remote-deployed claude agents; persisted ManagedAgentRecord.effort_level + persist_agent_effort_level command injected at spawn as BUZZ_ACP_EFFORT_LEVEL after descriptor.env; adapter-advertised thought_level configId discovery (extract_thought_level_config_id) instead of a hardcoded "effort"; CLAUDE_CONFIG_DIR-aware MCP config path plus the Keychain caveat surfaced through claude_config_dir_custom; and requestId-correlated live model-switch outcomes where only a real switched frame is success (rejection → terminal failure, timeout → pending).

Tests were written first and shown failing before implementation (RED logs below), covering: the Goose set-contract, the named-path workspace wording, extract_thought_level_config_id (configId/id/absent), Claude model + effort env application, effective Claude config dir and effort-option discovery, effort persistence command, spawn-snapshot effort resolution, and the expanded liveSwitchOutcome matrix (correlation, channel matching, duplicate results, failure, pending, non-delivery).

Gates (Hermit toolchain, Node 24.15.0 / pnpm 11.4.0):

gate result
pnpm --filter buzz check pass
pnpm --filter buzz typecheck pass
pnpm --filter buzz test pass — 5542 passed, 1 skipped
just check-compile pass
cargo test -p buzz-acp --lib pass — 1031 passed
desktop/src-tauri cargo test --workspace pass — 2832 passed, 15 ignored
just desktop-tauri-clippy pass
just test-unit pre-existing failures only
just fmt-check, just clippy pre-existing findings only

just test-unit fails on buzz-cli tests::command_inventory_is_stable, tests::subcommand_counts_are_stable, tests::subcommand_names_are_stable and buzz-db migration::tests::embedded_migrator_contains_consolidated_initial_schema; all four reproduce identically on a clean origin/main worktree (baseline-main-test-unit.log) and no buzz-cli/buzz-db file is touched here. just fmt-check/just clippy fail only in untouched files (crew-wiki/src/publish.rs, buzz-acp/src/guided_handover.rs). None of those three gates run in PR CI.

Evidence — full untruncated logs and full-app before/after screenshots (also embedded above), all under /home/ubuntu/evidence-282/:

baseline.log, baseline-main-test-unit.log, red-buzz-acp.log, red-desktop-tauri.log, red-pnpm-test.log, green-buzz-acp.log, green-desktop-tauri.log, green-pnpm-test.log, gate-pnpm-check.log, gate-pnpm-typecheck.log, gate-check-compile.log, gate-test-unit.log, gate-desktop-tauri-clippy.log, gate-desktop-tauri-fmt-check.log, gate-fmt-check.log, gate-clippy.log, base-smoke-targeted.log, test-plan.md, and the UI pairs in evidence-282/ui/ (before-/after-A1..A4 edit dialog + effort picker, before-/after-B1, B1a, B1b, B2, B2a config panel). Screencast: /home/ubuntu/screencasts/issue-282-ui/issue-282-ui-edited.mp4.

IN PROGRESS

Nothing half-done in the code — the working tree is clean apart from four deliberately uncommitted evidence-capture scaffolds: desktop/tests/e2e/tmp-282-effort-evidence.spec.ts, desktop/tests/e2e/tmp-282-drive.spec.ts, desktop/playwright.tmp282.config.ts, desktop/playwright.tmp282drive.config.ts. Reproducing the evidence run also needs the reverted mock-bridge seed at /home/ubuntu/evidence-282/tmp-e2ebridge-effort-seed.patch re-applied (the shipped E2E bridge advertises none of the new RuntimeConfigSurface fields). These are intentionally not part of the PR.

TODO / NEXT

  • CI is not green, and none of it is a code failure. Desktop Rust (job 97012531807) failed before any build step: hermit bootstrap curl: (35) Recv failure: Connection reset by peer, exit 35 — pure infrastructure. NuncioCrew Gate (job 97012244444) failed with desktop-fast must be success when desktop=true, got cancelled, i.e. the gate observing the parent session's deliberate cancellation of the first run. The earlier Desktop Smoke E2E (1) failures (channel-mute opacity, channels description text, community-rail keyboard reorder, composer-selection-formatting theme colour) reproduce on a clean origin/main worktree — see base-smoke-targeted.log. Per instruction nothing under .github/ was touched and no fix was attempted; the run needs re-running by whoever owns CI serialization.
  • Two open decisions. The CLAUDE_CONFIG_DIR caveat renders twice in the config panel (under Model settings and under MCP servers). That is faithful to upstream feat(managed-agents): close five Claude Code agent-config gaps block/buzz#4557, which mounts ClaudeConfigDirNotice in both sections — decide whether Crew wants it deduped. And the ModelPicker live-switch success/failure/pending states have unit coverage but no screenshot: they need real control_result frames, which the E2E mock bridge cannot originate.
  • Merge-conflict risk with the sibling 0.5.18 sync PRs is concentrated in crates/buzz-acp/src/{acp.rs,pool.rs,lib.rs,config.rs}, desktop/src-tauri/src/managed_agents/{runtime.rs,types.rs,spawn_snapshot.rs,config_bridge/*} and desktop/src/shared/api/types.ts. Two deliberate divergences to preserve on any rebase: RelayMeshConfig stays inline in managed_agents/types.rs (upstream's extraction to types/relay_mesh.rs was not taken), and upstream's comment-shrinking churn is not ported. Channel-first IA per upstream(sync): Guardrail — preserve channel-first IA during 0.5.18 merge #278 is untouched — no Projects/Workbench/sidebar edits.
  • A skill-PR suggestion for .agents/skills/headless-evidence-capture/SKILL.md (whole-app before/after capture pitfalls) is pending in the requester's timeline; the local edit was reverted so it is not in this branch.

devin-ai-integration Bot and others added 3 commits August 22, 2026 23:28
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Oscar Le <oscar.lehuu@gmail.com>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Oscar Le <oscar.lehuu@gmail.com>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Oscar Le <oscar.lehuu@gmail.com>
@cursor
cursor Bot force-pushed the devin/issue-282-acp-harness-tier1 branch from f1fd9b6 to 5b60aee Compare August 22, 2026 23:30
cursoragent and others added 2 commits August 22, 2026 23:35
The rebase onto main picked up #312's observerRelayStore baseline (1031).
Tier 1 ACP harness control_result dispatch grows that file to 1054, which
is upstream-owned (block#4557), so the recorded baseline is bumped per D-033.

Keep discovery/tests.rs at main's grandfathered size: add effort_level
without wrapping the adjacent comment.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: oscarlehuu <oscarlehuu@users.noreply.github.com>
Project Relay on 35c4b28 failed during relay boot: git object-store
conformance probe (if_match_race) hit a MinIO transport drop and the
process exited before the Project contract test ran. Unrelated to the
ACP harness port. Cannot rerun failed jobs from this token.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: oscarlehuu <oscarlehuu@users.noreply.github.com>
@oscarlehuu
oscarlehuu merged commit 9658ed9 into main Aug 23, 2026
8 of 14 checks passed
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.

upstream(sync): Tier 1 ACP harness — Claude config, Goose prompt, workspace scan (#4557, #5964, #6261)

2 participants