Fix: never persist runtime config overrides during project registration

Bug: `serena start-mcp-server --language-backend X --project <newdir>` silently rewrote the global
serena_config.yml's language_backend to X. Cause: a not-yet-registered --project is auto-registered, and
SerenaConfig.save() rewrote the WHOLE file from the in-memory config — which by then carried the CLI
--language-backend override (and would equally carry --log-level / --tool-timeout / etc.).

Fix: project (de)registration now persists ONLY the projects list. add_registered_project / remove_project go
through a new _persist_projects(), which re-loads the on-disk config, copies in the current project list, and
saves that — so a transient runtime override of any field can never be written back.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael PanchenkoandClaude Opus 4.8 authored and Dominik Jain committed 2026-06-08 11:35:58 +02:00
1 parent b5b9cc4ffc
commit 34e7c93f78
2 files changed
+20 -3

No files matched your search

+1
View File
@@ -8,6 +8,7 @@ Status of the `main` branch. Changes prior to the next official version change w
or a `.git`, including worktree/submodule pointer files), instead of preferring an ancestor's
`.serena/project.yml` over a closer `.git`. This previously bound CLI agents (Claude Code, Codex,
Gemini) launched from inside a worktree to the parent repo, causing stale reads and misdirected edits.
- Fix: some CLI flags on start-mcp-server modified the global config (notably, language-backend).
* Language Servers:
- `typescript_vts`: Add `initialization_options` setting in `ls_specific_settings.typescript_vts`.
+19 -3
View File
@@ -1035,10 +1035,10 @@ class SerenaConfig(SharedConfig, ModeSelectionDefinitionWithBaseModes):
def add_registered_project(self, registered_project: RegisteredProject) -> None:
"""
Adds a registered project, saving the configuration file.
Adds a registered project, persisting only the updated project list (see :meth:`_persist_projects`).
"""
self.projects.append(registered_project)
self.save()
self._persist_projects()
def add_project_from_path(self, project_root: Path | str) -> "Project":
"""
@@ -1083,7 +1083,23 @@ class SerenaConfig(SharedConfig, ModeSelectionDefinitionWithBaseModes):
break
else:
raise ValueError(f"Project '{project_name}' not found in Serena configuration; valid project names: {self.project_names}")
self.save()
self._persist_projects()
def _persist_projects(self) -> None:
"""
Persist ONLY the registered-projects list, leaving every other setting at its on-disk value.
Project (de)registration can happen while a session is running with transient runtime overrides applied
to this in-memory instance (e.g. ``start-mcp-server --language-backend`` / ``--log-level``). A full
:meth:`save` would write those overrides back to the global config, silently clobbering the user's
settings. Instead we re-load the persisted config, copy in the current project list, and save that — so
only ``projects`` is ever mutated on disk.
"""
if self.config_file_path is None:
return
persisted = SerenaConfig.from_config_file()
persisted.projects = list(self.projects)
persisted.save()
def save(self) -> None:
"""