Issue
Two near-identical atomic-write implementations exist for app config files, and a security guard is present in only ONE copy:
src/apps/claude-desktop/config.ts:119 atomicWriteJson
src/apps/claude-code/config.ts:223 writeClaudeCodeSettings
Both do the same dance (mkdir, unlink stale .tmp, O_EXCL @0o600, write+fsync+rename). But the claude-code copy has an EEXIST symlink-attack guard (config.ts:245-251) that the claude-desktop copy LACKS — exactly the drift that maintaining two copies of security-sensitive code invites. Same story for the readers (readJsonObject vs readClaudeCodeSettings).
Fix
Consolidate to a single ~/lib/atomic-json (write + safe-read) used by both apps, carrying the symlink guard. Removes the drift and closes the missing-guard gap on the desktop path.
Found in the 2026-07 project health audit (docs/dev/project-health-audit-2026-07.md, A3).
Issue
Two near-identical atomic-write implementations exist for app config files, and a security guard is present in only ONE copy:
src/apps/claude-desktop/config.ts:119atomicWriteJsonsrc/apps/claude-code/config.ts:223writeClaudeCodeSettingsBoth do the same dance (mkdir, unlink stale
.tmp,O_EXCL @0o600, write+fsync+rename). But the claude-code copy has anEEXISTsymlink-attack guard (config.ts:245-251) that the claude-desktop copy LACKS — exactly the drift that maintaining two copies of security-sensitive code invites. Same story for the readers (readJsonObjectvsreadClaudeCodeSettings).Fix
Consolidate to a single
~/lib/atomic-json(write + safe-read) used by both apps, carrying the symlink guard. Removes the drift and closes the missing-guard gap on the desktop path.Found in the 2026-07 project health audit (docs/dev/project-health-audit-2026-07.md, A3).