fix(desktop): ground agent workspace, migrate legacy nest, configurable repos_dir#1194
Merged
Merged
Conversation
af59c1a to
ffa3be7
Compare
Agents triggered macOS TCC prompts many times a day by running `find` over $HOME. Root cause: PR #960 renamed the nest `~/.sprout` -> `~/.buzz` with no migration, so agents booted into an empty nest with a base prompt that names a workspace layout but never its absolute root. Lacking an anchor, the model searched $HOME for files it "remembered". Phase 1 injects a `[Workspace]` section naming the absolute working directory ahead of the base prompt, skipping the `/` fallback (naming `/` as the workspace would itself invite a $HOME-wide scan) and persona-only agents (which never received the layout). Phase 2 migrates only the knowledge dirs from the stranded nest, deliberately skipping `REPOS/`: re-clonable checkouts measured 62 GB and would block startup for minutes on every cold launch. Phase 3 adds one belt line forbidding $HOME-wide `find`. Migration is non-fatal and idempotent with per-entry log-and-continue, so one failed entry never skips the rest or aborts boot. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Agents re-clone repositories into the nest's REPOS dir because they cannot reach the user's existing checkouts. Add a per-workspace `repos_dir` that points `~/.buzz/REPOS` at an external directory. `ensure_repos_symlink` is shared between nest setup (real-dir fallback when unset) and the live `apply_workspace` bridge. Re-pointing replaces an existing symlink (data-safe); a non-empty real REPOS refuses rather than destroying cloned repos. `apply_workspace` validates the path in its validate-first block so a bad path applies nothing, then runs the symlink as a non-fatal side-effect that surfaces failures via a `repos-dir-error` toast instead of failing silently. The backend rejects `~` paths; the dialogs expand them before save. Also emit `legacy-nest-migrated` so a successful ~/.sprout migration toasts a one-time delete hint, and reword the REPOS prompt line so agents prefer an existing local checkout over re-cloning. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
ffa3be7 to
381c1a7
Compare
Collaborator
|
@codex please review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 381c1a7bf4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
wesbillman
approved these changes
Jun 23, 2026
…e AGENTS.md Three Codex P2 review findings on the repos_dir/migration work: - Startup no longer clobbers a configured REPOS symlink. ensure_nest_at called ensure_repos_symlink(_, None), which post-symlink-revert removes an existing symlink and mints an empty real REPOS; async-restored agents write into it and the later FE re-point refuses the now-non-empty dir, silently breaking repos_dir on every restart. New ensure_repos_setup_default leaves an existing symlink untouched (apply_workspace remains the sole authority) and only lands the default real-dir when REPOS is absent or real. - useWorkspaceInit no longer marks a workspace ready after apply_workspace hard-rejects a bad repos_dir. apply_workspace validates repos_dir first and returns Err with relay/keys never applied; the catch then fell through to isReady:true, rendering workspace UI against the previous/default relay. The catch now parks on the loading gate (isReady:false, appliedKey:null). - Legacy AGENTS.md is no longer stranded on first-time migration. ensure_nest writes the generated default before migration runs, so the absent-only guard always skipped the legacy file. AGENTS.md migration now overwrites the destination only when it is still byte-equal to the embedded template, preserving any user-edited live file. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
This was referenced Jun 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
macOS agents trigger a TCC permission prompt many times a day. Root cause: #960 renamed the agent nest
~/.sprout->~/.buzzwith no migration. Agents boot into an empty~/.buzzwhose base prompt names a workspace layout (RESEARCH/,PLANS/, ...) but never its absolute root. Lacking an anchor for where they live, the model runsfindover$HOMEto locate files it "remembers" — and macOS attributes that access to Buzz.app, raising the prompt.A second cost compounds it: agents re-clone repositories into the nest's
REPOS/because they cannot reach the user's existing checkouts, so the same source tree exists twice and the prompt impliesREPOS/is the clone root.Fix
Ground the workspace
framed_system_promptreceivesctx.cwdand prepends a[Workspace]section naming the absolute working directory ahead of[Base], removing the reason the model searches$HOME. The section is omitted for the/fallback (naming/would itself invite a$HOME-wide scan), for relative/empty paths, and for persona-only agents that never received the layout it grounds.Migrate the stranded nest — knowledge only
migrate_legacy_nestcopies the knowledge entries (AGENTS.md,RESEARCH,PLANS,GUIDES,WORK_LOGS,OUTBOX,.scratch) from~/.sproutinto~/.buzzand deliberately skipsREPOS/— cloned repos are re-clonable, and a real strandedREPOS/measured 62 GB, which would block launch for minutes if copied on the startup thread. Migration runs afterensure_nest(), is non-fatal and idempotent, and uses per-entry log-and-continue so one failed entry never aborts boot. On a successful migration the backend emitslegacy-nest-migrated; the frontend shows a one-time toast suggesting the user delete the now-inert~/.sproutto reclaim disk.Configurable
repos_dirEach workspace gains an optional
repos_dir. When set,~/.buzz/REPOSbecomes a symlink to that external directory, so agents work in the user's existing checkouts instead of re-cloning.ensure_repos_symlinkis shared between nest setup (real-dir fallback when unset) and the liveapply_workspacebridge, so arepos_diredit takes effect on the next save without a restart.apply_workspacevalidatesrepos_dirin its validate-first block, so an invalid path applies nothing and rejects cleanly. The backend requires an existing absolute directory and rejects~-prefixed, relative, missing, and nest-ancestor paths; the dialogs expand~before save.REPOSsymlink is replaced (remove_file+ re-link); an empty realREPOSconverts; a non-empty realREPOSrefuses rather than deleting cloned repos. Clearing the field reverts a symlinkedREPOSto a real in-nest directory (the link is removed, never its target). The symlink step runs as a non-fatal side-effect — its failure (downgrade refused, external target renamed on a later launch) surfaces via arepos-dir-errortoast instead of failing the command silently.Prompt wording
The base prompt's
REPOS/line no longer implies the clone root: agents work in an existing local checkout when one exists and clone intoREPOS/only when none does. One machine-agnostic line keeps exploration in the working directory and neverfinds over$HOMEor/.Notes
REPOS/is excluded from migration on purpose; re-adding it would make a sentinel or off-thread copy mandatory.copy_dir_allrecurses withsymlink_metadata, bounded by the per-entry log-and-continue.[Workspace]prompt section emits the literal nestREPOS/path; grounding resolves through the symlink transparently, so the rendered prompt needs noreadlink.