ADR 0149: Точечные привязки settings.toml к переменным окружения (*_env)¶
Статус: Accepted · Implemented
Дата: 2026-05-24
Связанные ADR¶
| ADR | Роль |
|---|---|
| 0028 | settings.toml, snake_case, секреты отдельно |
| 0040 | LSP: executable_env / arguments_env в профилях |
| 0023 | readiness: какие env читаются, без дампа environ |
| 0144 | intercom.transport |
Контекст¶
Пользовательский settings.toml часто копируется между машинами или хранится в общем профиле разработчика. Абсолютные пути к бинарникам (LSP, Intercom service, cursor-agent) не должны быть единственным способом конфигурации. При этом подстановки $VAR внутри строк TOML не используем — хуже валидировать и показывать в Environment readiness (0040 §4).
Нужен явный парный ключ: литерал в TOML + опциональное имя переменной окружения.
Решение¶
1. Соглашение имён¶
Для строкового поля <field> в TOML добавляется опциональный ключ <field>_env (snake_case), в модели C# — <Field>Env (JsonPropertyName через общий snake_case сериализатор).
Пример:
[intercom.transport]
local_server_path = "tools/intercom-service/IntercomService.exe"
local_server_path_env = "CASCADE_INTERCOM_SERVER_EXE"
2. Приоритет резолва (SettingsEnvResolver)¶
На чтении (runtime), не при сохранении файла:
- Если
<field>_env— sentinelPATH(регистронезависимо) → для запуска процесса (LSPexecutable, ACPcursor_acp_path): эффективный путь пустой; дальше пресет + поиск команды в PATH (0040). Это не чтение переменной окруженияPATH. - Иначе, если
<field>_env— имя переменной иGetEnvironmentVariableвозвращает непустую строку → использовать её. - Иначе → литерал
<field>из TOML. - Дальше по домену — пресеты LSP, legacy defaults, fallback intercom-service и т.д.
Пустой *_env = привязки нет (для LSP с пресетом эквивалентно п.1–3 с пустым executable и поиском в PATH). Пустая именованная переменная не перекрывает литерал.
Environment.ExpandEnvironmentVariables для %VAR% внутри литерала не смешиваем с *_env; при необходимости — только в отдельных резолверах путей (как MCP JSON path).
3. Первая волна полей (v1)¶
| Секция | Поле | *_env |
Типичное значение |
|---|---|---|---|
[languages.*.*] профиль |
executable |
executable_env |
PATH (дефолт для OmniSharp/Marksman) или имя переменной с абсолютным путём |
| то же | arguments |
arguments_env |
имя переменной (sentinel PATH не используется) |
[intercom.transport] |
local_server_path |
local_server_path_env |
CASCADE_INTERCOM_SERVER_EXE |
[intercom.transport] |
base_url |
base_url_env |
CASCADE_INTERCOM_BASE_URL |
[ai.acp] |
cursor_acp_path |
cursor_acp_path_env |
CURSOR_ACP_AGENT_PATH |
[agent_notes] |
config_path |
config_path_env |
CASCADE_AGENT_NOTES_CONFIG |
[agent_notes] |
kb_base_overlay_path |
kb_base_overlay_path_env |
CASCADE_KB_BASE_OVERLAY |
Секреты (API keys, JWT) — по-прежнему только *-secrets.toml / 0028, не через *_env в основном файле.
Уже существующие process-wide переменные (AGENT_NOTES_FILE, NETCOREDBG_PATH) сохраняют приоритет там, где код читает их напрямую; config_path_env дополняет путь из [agent_notes], не заменяет AGENT_NOTES_FILE.
4. Отклонено¶
launch_from_environment(глобальный bool) — заменён точечными*_env(0040 §3 обновлён).- Inline-таблица
{ env = "...", fallback = "..." }— усложняет десериализацию и UI. - Универсальный
lookup_environment_variable_nameна все поляCascadeIdeSettings— вне scope v1.
Последствия¶
SettingsEnvResolver— единая точка резолва.ResolveForRuntime()LSP,IntercomTransportSettingshelpers,AgentNotesRuntimeLoader,KbBaseOverlayPathResolver,CursorAcpAgentPathполучают уже разрешённые строки или вызывают resolver в месте использования.- Environment readiness: при заданном
*_envи пустом env — явная подсказка в LSP-строках (имя переменной без значения). - Расширение на новые поля — новый ADR-подпункт или дополнение таблицы §3.
Статус реализации¶
| Элемент | Артефакт |
|---|---|
| Резолвер | Services/SettingsEnvResolver.cs |
| LSP | LanguageServerLaunchProfile, 0040 |
| Intercom / ACP / agent_notes | модели + call sites |
| Тесты | SettingsEnvResolverTests, deserialize samples |
| Дефолты | комментарии в Settings/defaults-settings.toml |