# Contributor handoff — 2dust/v2rayN

> Canonical page: https://codevetter.com/unpack/v2rayn/agent-handoff

# Contributor handoff — 2dust/v2rayN

Scanned commit 28139853a8087d81e1ac7ffaf7013b937958f5d2 (2026-09-20). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

All logic changes belong in ServiceLib; the two shells should stay thin views over shared ViewModels. Read the order below before editing: Global.cs constants, ConfigHandler, CoreConfigContextBuilder, the relevant CoreConfig service, FmtHandler, and the target ViewModel. Build requires .NET 10 SDK (global.json) and a recursive submodule checkout for the Desktop project; test via 'dotnet test v2rayN/ServiceLib.Tests'. Respect the ConfigVersion migration chain, the {0} argument-template convention, embedded Sample resource names, and the LoadCore ordering (main config -> stop -> remove tun -> start -> wait for pre-socks port -> start pre-service).
- Read-first files for any change: v2rayN/ServiceLib/Global.cs (all constants/tag names/URL templates), ServiceLib/Handler/ConfigHandler.cs (config + profile persistence), ServiceLib/Manager/AppManager.cs (singleton state + SQLite query helpers), and ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs (node resolution pipeline). — [v2rayN/ServiceLib/Global.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Global.cs) [v2rayN/ServiceLib/Handler/ConfigHandler.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/ConfigHandler.cs) [v2rayN/ServiceLib/Manager/AppManager.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/AppManager.cs) [v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs)
- Conventions: managers are 'public sealed class X { private static readonly Lazy<X> _instance = new(() => new()); public static X Instance => _instance.Value; }'; handlers are static classes; string checks use IsNullOrEmpty/IsNotEmpty/TrimEx extension methods; user-facing text must come from ResUI.* generated from resx. — [v2rayN/ServiceLib/Manager/AppManager.cs#L7-11](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/AppManager.cs#L7-L11) [v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs#L41-42](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs#L41-L42) [v2rayN/ServiceLib/Common/Extension.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Common/Extension.cs)
- ReactiveUI conventions: ViewModels derive from MyReactiveObject, commands via ReactiveCommand.CreateFromTask, properties via [Reactive] partial properties from ReactiveUI.SourceGenerators, and UI-marshaling via RxSchedulers.MainThreadScheduler.Schedule or Signal.FromAsync(...).SubscribeOn(...).ToTask(). — [v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L71-84](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L71-L84) [v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L99-236](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L99-L236) [v2rayN/Directory.Packages.props](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/Directory.Packages.props)
- Never persist mutable config references into CoreConfigContext — it is an immutable record snapshot so the generated config and the process launch mode (e.g. sudo/TUN decision in ShouldRunAsSudo) agree even if settings change mid-reload; clone via JsonUtils.DeepCopy before mutating. — [v2rayN/ServiceLib/Manager/CoreManager.cs#L292-303](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/CoreManager.cs#L292-L303) [v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L100-135](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L100-L135)
- ProfileItem carries legacy flat fields plus JSON 'extra' blobs accessed via GetProtocolExtra/SetProtocolExtra/GetTransportExtra/SetTransportExtra; new fields must respect the ConfigVersion migration ladder (v2->v3 moved protocol extras, v3->v4 moved transport extras) — add a new migration step rather than reparsing inline. — [v2rayN/ServiceLib/Manager/AppManager.cs#L337-475](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/AppManager.cs#L337-L475) [v2rayN/ServiceLib/Models/Entities/ProfileItem.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Models/Entities/ProfileItem.cs) [v2rayN/ServiceLib/Models/Entities/ProtocolExtraItem.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Models/Entities/ProtocolExtraItem.cs)
- Build commands: 'dotnet build v2rayN/v2rayN.slnx' or per-project; WPF project targets net10.0-windows10.0.19041.0 and needs Windows or EnableWindowsTargeting; Desktop needs 'git submodule update --init --recursive' first or GlobalHotKeys.csproj is missing; tests: 'dotnet test v2rayN/ServiceLib.Tests -c Release'. — [v2rayN/v2rayN/v2rayN.csproj#L5](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/v2rayN/v2rayN.csproj#L5) [.github/workflows/build.yml](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/.github/workflows/build.yml) [.gitmodules](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/.gitmodules) [.github/workflows/test.yml#L45](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/.github/workflows/test.yml#L45)
- When changing share-URI parse/export, update both directions (Fmt Resolve + ToUri) and add a factory in FmtHandlerTests.ShareProfileFactories — the suite asserts parity with Global.ProtocolShares so a one-sided change fails CI. — [v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs#L10-43](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs#L10-L43) [v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs)
- Safe edit boundaries: new ViewModels/services in ServiceLib; per-shell code limited to Views, Converters, platform utils (WindowsUtils, MacAppUtils) and Managers like HotkeyManager/WindowDialog; do not add UI dependencies to ServiceLib (it must stay runnable by the test project on Linux CI). (inferred) — [v2rayN/v2rayN/Manager/HotkeyManager.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/v2rayN/Manager/HotkeyManager.cs) [v2rayN/ServiceLib/ServiceLib.csproj](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ServiceLib.csproj) [.github/workflows/test.yml#L33](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/.github/workflows/test.yml#L33)
- Known traps: generated config filenames are constants (config.json, configPre.json, configTest{0}.json) under binConfigs — TaskManager deletes files matching 'Test' older than 1h there; ports are derived as socksPort + (int)EInboundProtocol; sing-box updates are version-locked at <=1.14.x. — [v2rayN/ServiceLib/Global.cs#L13-15](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Global.cs#L13-L15) [v2rayN/ServiceLib/Manager/TaskManager.cs#L61-63](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/TaskManager.cs#L61-L63) [v2rayN/ServiceLib/Manager/AppManager.cs#L165-169](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/AppManager.cs#L165-L169) [v2rayN/ServiceLib/Manager/CoreInfoManager.cs#L232](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/CoreInfoManager.cs#L232)
- Core exe argument strings are string.Format templates where {0} is the config path (AbsolutePath flag controls quoting via GetBinConfigPath); keep the format-string contract when adding cores and provide env vars via CoreInfo.Environment (e.g. XRAY_LOCATION_ASSET). — [v2rayN/ServiceLib/Manager/CoreManager.cs#L334-350](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/CoreManager.cs#L334-L350) [v2rayN/ServiceLib/Manager/CoreInfoManager.cs#L149-171](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/CoreInfoManager.cs#L149-L171)
- Logging goes through Logging.SaveLog (NLog, guiLogs/) gated by config.GuiItem.EnableLog set in InitComponents; updateFunc callbacks carry (notify:bool, msg) where notify=true means surface a snackbar via NoticeManager.Enqueue. — [v2rayN/ServiceLib/Manager/AppManager.cs#L98-113](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/AppManager.cs#L98-L113) [v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L349-357](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L349-L357) [v2rayN/ServiceLib/Common/Logging.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Common/Logging.cs)
- Do not call ViewModel constructors expecting side effects in design mode: MainWindowViewModel.Init short-circuits on DesignMode, and design-time data lives in v2rayN.Desktop/DesignData; both shells share the same ServiceLib ViewModels so VM changes must remain toolkit-agnostic (use WindowDialog/Interactions, not dialogs). — [v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L319-326](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L319-L326) [v2rayN/v2rayN.Desktop/DesignData](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/v2rayN.Desktop/DesignData) [v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L5-8](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L5-L8)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
