upstream(sync): Tier 1 ACP harness — Claude config, Goose prompt, workspace scan - #311
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
NOTES (handover)DONEAll three ports in #282's scope are implemented, tested and pushed — the branch is in a coherent, complete state at
Tests were written first and shown failing before implementation (RED logs below), covering: the Goose set-contract, the named-path workspace wording, Gates (Hermit toolchain, Node 24.15.0 / pnpm 11.4.0):
Evidence — full untruncated logs and full-app before/after screenshots (also embedded above), all under
IN PROGRESSNothing half-done in the code — the working tree is clean apart from four deliberately uncommitted evidence-capture scaffolds: TODO / NEXT
|
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>
f1fd9b6 to
5b60aee
Compare
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>
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:block#5964 — Goose custom system prompt.
_goose/unstable/session/system-prompt/setnow 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:
claudeagents the resolved effective model is written asANTHROPIC_MODELandBUZZ_ACP_MODELis removed (managed_agents/claude_config), soBUZZ_ACP_MODELmeans "live ACP switch" only. Remote deploys get the same authority throughpolicy_envinagents_deploy.ManagedAgentRecord.effort_level+persist_agent_effort_levelcommand; injected at spawn asBUZZ_ACP_EFFORT_LEVELafterdescriptor.env, so a canonical value cannot be shadowed by user env.SpawnConfigSnapshotcarries exactly one representation (effort_level, env key stripped) so an authority handoff at the same value produces no phantom drift entry.thought_level.extract_thought_level_config_id()discovers the adapter's realconfigIdfromsession/new(accepting bothconfigIdandid) instead of hardcoding"effort"; the config panel and picker render the adapter's option values.CLAUDE_CONFIG_DIR. Claude's MCP config path resolves to$CLAUDE_CONFIG_DIR/.claude.jsonwhen set, and the panel surfacesclaude_config_dir_customso the Keychain-namespace caveat is visible instead of silently logging the agent out.ControlSignal::SwitchModelcarries an opaque per-pickrequest_idthat is echoed on everycontrol_resultframe, so a replayed or stale result cannot settle a later pick. Only a realswitchedframe is success; adapter rejection emits a terminalfailure, and a timeout resolvespendingrather than a false success. Busy-path switches emit their positive terminal at the deferred apply.Divergences from upstream (Crew guardrails)
RelayMeshConfigstays inline inmanaged_agents/types.rs; upstream's incidental extraction totypes/relay_mesh.rswas not taken (Crew-owned file, no behaviour change).enter_draining, resume-first acquisition, session ledger and rotation lineage, Cowork Projects: non-git folders with always-on shadow-git versioning (turn checkpoints, honest attribution, business-language restore) #188 CoworkTurnGuard, session load / elicitation / hooks / plan snapshots.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):
pnpm --filter buzz checkpnpm --filter buzz typecheckpnpm --filter buzz testjust check-compilecargo test -p buzz-acp --libdesktop/src-tauri cargo test --workspacejust desktop-tauri-clippyjust test-unitjust test-unitfails on four tests unrelated to this change, verified identical on a cleanorigin/mainworktree:buzz-clitests::command_inventory_is_stable,tests::subcommand_counts_are_stable,tests::subcommand_names_are_stable, andbuzz-dbmigration::tests::embedded_migrator_contains_consolidated_initial_schema. Nobuzz-cli/buzz-dbfiles are touched here.just fmt-check/just clippylikewise 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-appfullPageshots at 1560x1100). BEFORE comes frommainin 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 newRuntimeConfigSurfacefields (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 theAdapter defaultsentinel, and pickingLowcallspersist_agent_effort_level {"pubkey":"953d…001f","effortLevel":"low"}; the config panel then re-readslowconfigured vsmediumrunning.AFTER — field present and preselected:
AFTER — options open:
AFTER —
Lowselected:BEFORE (
main) — no Thinking effort field in the dialog:2. Claude
CLAUDE_CONFIG_DIRcaveat + MCP config-file attribution.AFTER (caveat plus
From config file (~/work/claude-isolated/.claude.json)):BEFORE (
main) — neither present:AFTER — panel re-read after the pick:
BEFORE — same view on
main: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
ClaudeConfigDirNoticein both sections; and the configured-vs-running effort facts already exist onmain, so only the caveat and the config-file caption are new here.3. ModelPicker live-switch outcomes — no UI screenshot. The correlated success /
failure/pendingstates need an in-flight ACP switch producing realcontrol_resultframes, which the mock bridge cannot originate; they are covered by unit tests instead (liveSwitchOutcome.test.mjs— correlation byrequestId, 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).crates/buzz-acp/src/base_prompt.mdandpool.rs::workspace_section()(start in the working dir, but read a path the user names)._goose/unstable/session/system-prompt/setnow sends"mode": "set"; contract test renamed togoose_system_prompt_request_uses_set_contract.ANTHROPIC_MODELas the single startup model authority (withBUZZ_ACP_MODELstripped) for local and remote-deployed claude agents; persistedManagedAgentRecord.effort_level+persist_agent_effort_levelcommand injected at spawn asBUZZ_ACP_EFFORT_LEVELafterdescriptor.env; adapter-advertisedthought_levelconfigId discovery (extract_thought_level_config_id) instead of a hardcoded"effort";CLAUDE_CONFIG_DIR-aware MCP config path plus the Keychain caveat surfaced throughclaude_config_dir_custom; and requestId-correlated live model-switch outcomes where only a realswitchedframe is success (rejection → terminalfailure, 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 expandedliveSwitchOutcomematrix (correlation, channel matching, duplicate results, failure, pending, non-delivery).Gates (Hermit toolchain, Node 24.15.0 / pnpm 11.4.0):
pnpm --filter buzz checkpnpm --filter buzz typecheckpnpm --filter buzz testjust check-compilecargo test -p buzz-acp --libdesktop/src-tauricargo test --workspacejust desktop-tauri-clippyjust test-unitjust fmt-check,just clippyjust test-unitfails onbuzz-clitests::command_inventory_is_stable,tests::subcommand_counts_are_stable,tests::subcommand_names_are_stableandbuzz-dbmigration::tests::embedded_migrator_contains_consolidated_initial_schema; all four reproduce identically on a cleanorigin/mainworktree (baseline-main-test-unit.log) and nobuzz-cli/buzz-dbfile is touched here.just fmt-check/just clippyfail 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 inevidence-282/ui/(before-/after-A1..A4edit dialog + effort picker,before-/after-B1, B1a, B1b, B2, B2aconfig 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.patchre-applied (the shipped E2E bridge advertises none of the newRuntimeConfigSurfacefields). These are intentionally not part of the PR.TODO / NEXT
Desktop Rust(job 97012531807) failed before any build step: hermit bootstrapcurl: (35) Recv failure: Connection reset by peer, exit 35 — pure infrastructure.NuncioCrew Gate(job 97012244444) failed withdesktop-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 earlierDesktop Smoke E2E (1)failures (channel-muteopacity,channelsdescription text,community-railkeyboard reorder,composer-selection-formattingtheme colour) reproduce on a cleanorigin/mainworktree — seebase-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.CLAUDE_CONFIG_DIRcaveat 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 mountsClaudeConfigDirNoticein both sections — decide whether Crew wants it deduped. And the ModelPicker live-switchsuccess/failure/pendingstates have unit coverage but no screenshot: they need realcontrol_resultframes, which the E2E mock bridge cannot originate.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/*}anddesktop/src/shared/api/types.ts. Two deliberate divergences to preserve on any rebase:RelayMeshConfigstays inline inmanaged_agents/types.rs(upstream's extraction totypes/relay_mesh.rswas 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..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