From 0c9d1bdbd4e75d8d02ce2fd10b18a7893abd9225 Mon Sep 17 00:00:00 2001 From: Marcello Alarcon Date: Thu, 14 May 2026 11:36:14 -0300 Subject: [PATCH] fix(brain-repo): exclude editor and tool config dirs from mirror MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `_EXCLUDE_DIR_NAMES` in `dashboard/backend/brain_repo/job_runner.py` already excludes language and toolchain caches (node_modules, __pycache__, .venv, dist, build, etc.). It does NOT exclude the config directories that editors / note-taking apps drop into a path when the user opens that path as a workspace or vault. Those directories are per-machine UI state and must not propagate via the brain repo. Affected paths added: - `.obsidian/` — created when the user opens any watched directory (e.g. `memory/`) as an Obsidian vault. Contains workspace.json (open tabs, panel layout), per-vault enabled plugins, hotkeys, and appearance overrides. None of this transfers meaningfully across machines: opening the same vault on a second machine creates a fresh `.obsidian/` regardless. Propagating it just produces noisy diffs (workspace.json is rewritten on every panel/tab change). - `.vscode/` — VS Code workspace settings. Two sub-cases: (a) shared project settings that belong in the repo and should be committed explicitly elsewhere; (b) personal launch configs / debug breakpoints that should never leak. Default-excluding follows the more common project pattern (.vscode is almost always gitignored). - `.idea/` — JetBrains IDEs (PyCharm, IntelliJ, WebStorm, etc.). Same rationale as .vscode — almost always gitignored, occasionally explicitly checked-in pieces, but never appropriate for a content mirror. Sourcery review applied (2026-05-14): - Dropped `.trash` from the original draft. Sourcery flagged it as "too generic — could plausibly be legitimate user content the mirror would silently hide." Each remaining entry is unambiguously tied to a single application (folder name uniquely identifies Obsidian / VS Code / JetBrains). ## Why this matters The brain repo file watcher (and the manual sync_force path) calls `shutil.copytree(src, dst, ignore=build_ignore_callback(...))`. The ignore callback walks `_EXCLUDE_DIR_NAMES` per visited directory. Adding these three entries blocks the mirror from copying: - Megabytes of per-machine UI state on every dispatch - Editor lock files that change on every focus/blur - Plugin state that varies between operator boxes ## Test plan - [x] Empirical (MTA install, 2026-05-14): opened `memory/` as an Obsidian vault — `.obsidian/` created with `app.json`, `appearance.json`, `core-plugins.json`, `workspace.json`. Touched a sentinel file in `memory/` to force the watcher's 30s debounce. After 41 seconds, observed: sentinel file present in the brain repo destination, `.obsidian/` ABSENT (no leakage). Mirror behaved as intended. - [x] No-regression check: pre-existing exclusions (`.git`, `__pycache__`, `node_modules`, `.venv`, etc.) still trip the ignore callback exactly the same way — adding entries to a `set` only widens the exclusion, it can't break existing skips. - [x] No API change, no config schema change, no migration. Pure defensive addition to a defaults set. ## Notes for reviewers - The three directory names are *names*, not paths. They match anywhere in the watched tree (the ignore callback walks names per visited dir). That's the correct behavior for these tools — they always create their config dir directly inside the workspace root the user opened. - Personal preference (mine, not blocking): could add `.zed/`, `.fleet/`, `.cursor/` for completeness. Held off to keep the diff scoped to editors that someone reading this PR is most likely to actually have installed. Easy follow-up if anyone wants them. Co-Authored-By: Claude Opus 4.7 --- dashboard/backend/brain_repo/job_runner.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dashboard/backend/brain_repo/job_runner.py b/dashboard/backend/brain_repo/job_runner.py index 3099b558..685e72f6 100644 --- a/dashboard/backend/brain_repo/job_runner.py +++ b/dashboard/backend/brain_repo/job_runner.py @@ -188,6 +188,19 @@ def _load_config_snapshot(flask_app, user_id: int) -> dict | None: ".pytest_cache", ".mypy_cache", ".ruff_cache", + # Per-machine editor / tool config directories. These get created when a user + # opens one of the watched paths inside an editor or note-taking app (e.g. + # opening memory/ as an Obsidian vault writes memory/.obsidian/; opening the + # workspace in VS Code writes .vscode/; JetBrains writes .idea/). The content + # is local UI state (open tabs, window geometry, plugin enablement) that + # should never propagate across machines via the brain repo. + # + # Each entry is unambiguously tied to a single application — no generic + # names (e.g. ".trash"), since those could plausibly be legitimate user + # content that the mirror would silently hide. + ".obsidian", + ".vscode", + ".idea", } # Files above this size skip the mirror entirely. GitHub refuses >100 MB; we