Skip to content

feat(desktop): harness-agnostic config bridge#887

Draft
wpfleger96 wants to merge 2 commits into
mainfrom
wpfleger/phase4-config-bridge
Draft

feat(desktop): harness-agnostic config bridge#887
wpfleger96 wants to merge 2 commits into
mainfrom
wpfleger/phase4-config-bridge

Conversation

@wpfleger96

@wpfleger96 wpfleger96 commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Adds a harness-agnostic config bridge that reads agent configuration from all available sources and exposes it to the frontend with full provenance — where each value came from and how it can be written back.

Agent config was fragmented across four uncoordinated mechanisms with no single surface to see what a running agent would actually use. The silent failure mode was concrete: Wes's goose personas failed because active_provider in ~/.config/goose/config.yaml was invisible to Sprout and overrode our injected model. The bridge surfaces that ambient config, establishes a clear precedence order, and routes writes to the cheapest live mechanism.

  • New config_bridge module with per-runtime config file readers: YAML for goose (~/.config/goose/config.yaml), JSON for Claude Code (~/.claude/settings.json + ~/.claude.json), TOML for Codex (~/.codex/config.toml). 25 unit tests covering all formats, malformed files, and missing files.
  • Four-tier precedence: Sprout-explicit > ACP native (reserved for goose post goose#9197) > ACP configOptions from session/new > env vars > config file on disk. Pre-spawn surfaces tier 2 only; post-spawn adds ACP tiers.
  • session_config_captured observer event emitted after session/new; put_agent_session_config Tauri command populates SessionConfigCache in AppState. parse_models handles both the object shape ({currentModelId, availableModels}) and legacy array shape from session/new.
  • get_agent_config_surface and write_agent_config_field Tauri commands. Write mechanism is chosen per runtime and field: session/set_config_option (live, no restart) before env-var respawn. Single lock scope on the write path closes a TOCTOU race.
  • AgentConfigPanel component with origin badges (Sprout/ACP/ConfigFile/Env), collapsible advanced section, and sources footer showing all four tier statuses. Override/strikethrough rendering shows superseded config values inline — the overridden value appears crossed out next to the effective value, with both origin badges visible for at-a-glance provenance. Read-only fields display an info icon with tooltip rather than a lock icon.
  • ModelPicker shows provenance label when config surface data is available post-spawn (best-effort, non-blocking).
  • Playwright E2E screenshot spec covering 7 scenarios (goose, claude-code, codex, pre-spawn, overrides, advanced section, sources footer) for visual review.
  • Fixes codex.provider_locked to false — Codex supports [model_providers.<id>] custom provider tables. Fixes serde enum tagging on ConfigWriteMechanism, ConfigFieldType, and WriteConfigTarget to use #[serde(tag = "type")] matching the TypeScript discriminated union shapes (default external tagging made all write operations and TS type guards silently broken).

Stack: #794 → this PR

@wpfleger96 wpfleger96 force-pushed the wpfleger/phase3b-normalized-config branch 2 times, most recently from 66de98f to 60f95a2 Compare June 6, 2026 01:02
@wpfleger96 wpfleger96 changed the title feat(desktop): phase 4 — harness-agnostic config bridge feat(desktop): harness-agnostic config bridge Jun 6, 2026
@wpfleger96 wpfleger96 force-pushed the wpfleger/phase3b-normalized-config branch 6 times, most recently from de81ed1 to 0c44d4e Compare June 9, 2026 17:57
@wpfleger96 wpfleger96 force-pushed the wpfleger/phase4-config-bridge branch from 44cc07f to 678b871 Compare June 9, 2026 18:02
@wpfleger96 wpfleger96 force-pushed the wpfleger/phase3b-normalized-config branch from 0c44d4e to ba28ea0 Compare June 9, 2026 20:31
Base automatically changed from wpfleger/phase3b-normalized-config to main June 9, 2026 20:42
@wpfleger96 wpfleger96 force-pushed the wpfleger/phase4-config-bridge branch 2 times, most recently from c392c34 to 9939a10 Compare June 11, 2026 19:24
wpfleger96 pushed a commit that referenced this pull request Jun 11, 2026
wpfleger96 pushed a commit that referenced this pull request Jun 11, 2026
@wpfleger96 wpfleger96 force-pushed the wpfleger/phase4-config-bridge branch from 3228e7a to 139ada2 Compare June 11, 2026 20:16
wpfleger96 pushed a commit that referenced this pull request Jun 11, 2026
wpfleger96 pushed a commit that referenced this pull request Jun 11, 2026
@wpfleger96

Copy link
Copy Markdown
Collaborator Author

Config Bridge — AgentConfigPanel Screenshots (v4)

Updated screenshots with inline override rendering: overridden values appear with strikethrough next to the effective value, and overridden origin badges appear next to the effective badge.

1. Goose — Full Config Panel

Mixed-origin badges (Sprout/ACP/ConfigFile/Env), model/provider/mode fields with provenance tracking. Info icon on read-only fields with hover tooltip. Override value inline with strikethrough.

01-goose-full-config

2. Claude Code — ACP Config Options

ACP-sourced values with green badges, demonstrating the "one surface, multiple runtimes" approach.

02-claude-acp-config

3. Pre-Spawn State

Dimmed ACP fields showing "Available after agent starts" — config surface before runtime is active.

03-pre-spawn-state

4. Override Visibility

Effective value shown with overridden default crossed out inline, plus both origin badges side by side.

04-override-visibility

5. Advanced Section Expanded

Collapsible advanced section with runtime-specific extra fields (extensions, output style, etc.).

05-advanced-expanded

6. Sources Footer

Four-tier status indicators showing which config sources are active.

06-sources-footer

7. Codex — Dual-Mode Display

Codex's unique dual-axis mode (approval_policy × sandbox_mode).

07-codex-dual-mode

wpfleger96 pushed a commit that referenced this pull request Jun 11, 2026
@wpfleger96 wpfleger96 force-pushed the wpfleger/phase4-config-bridge branch 5 times, most recently from 69e6bc8 to fba912f Compare June 16, 2026 21:33
@wpfleger96 wpfleger96 force-pushed the wpfleger/phase4-config-bridge branch 2 times, most recently from 2357920 to ac3a45e Compare June 17, 2026 00:46
wpfleger96 and others added 2 commits June 17, 2026 00:19
Four-tier config bridge that reads agent configuration from config
files (goose YAML, claude JSON, codex TOML), ACP session data, env
vars, and Sprout-explicit overrides — surfacing a unified normalized
config surface to the desktop UI regardless of runtime.

Key changes:
- Config bridge module with per-runtime file readers
- ACP session config caching for post-spawn config visibility
- AgentConfigPanel component with origin badges and tier provenance
- Serde internally-tagged enums matching TypeScript discriminated unions
- TOCTOU-safe write path with single lock scope
- E2E mock handler for get_agent_config_surface with per-runtime
  fixtures and a Playwright screenshot spec covering 7 scenarios
- Info icon + tooltip on read-only fields; override/strikethrough
  rendering for superseded config values

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…place badges with provenance sentences

Persona-linked agents had their inherited model/prompt/provider invisible
in the config panel, and the source indicators (checkmark/hourglass icons,
colored badges, footer) were undecipherable.

Phase 1: Resolve all three persona fields (prompt, model, provider) in a
single resolve_config_surface helper called by both get_agent_config_surface
(read) and write_agent_config_field (write). The helper injects resolved
values into the record where absent, calls the reader, then re-tags the
injected fields from BuzzExplicit to PersonaDefault. The re-tag is triple-
gated so a value the user set explicitly in Buzz is never re-tagged. Sharing
the helper keeps the read and write surfaces identical, so plan_config_write
never returns "field not available" for a persona-sourced field. Reader stays
untouched (pure tier-merge function).

Phase 2: Add AgentConfigPanel to ProfileSummaryView in the profile pop-out,
gated on isBot && isOwner && managedAgent defined.

Phase 3: Remove SourcesFooter and colored OriginBadge pills. Replace with
gray inline provenance sentences below each value ("Set in Buzz", "Inherited
from persona", "From environment variable", etc). No action clauses.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
@wpfleger96 wpfleger96 force-pushed the wpfleger/phase4-config-bridge branch from ac3a45e to 69d2c4e Compare June 17, 2026 04:19
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.

1 participant