SaneHosts Development Guide (SOP)

May 5, 2026 · View on GitHub

README · ARCHITECTURE · DEVELOPMENT · PRIVACY · SECURITY

Version 1.0 | Last updated: 2026-01-20

SINGLE SOURCE OF TRUTH for all Developers and AI Agents.


Sane Philosophy

+-----------------------------------------------------+
|           BEFORE YOU SHIP, ASK:                     |
|                                                     |
|  1. Does this REDUCE fear or create it?             |
|  2. Power: Does user have control?                  |
|  3. Love: Does this help people?                    |
|  4. Sound Mind: Is this clear and calm?             |
|                                                     |
|  Grandma test: Would her life be better?            |
|                                                     |
|  "Not fear, but power, love, sound mind"            |
|  - 2 Timothy 1:7                                    |
+-----------------------------------------------------+

Full philosophy: ~/SaneApps/meta/Brand/NORTH_STAR.md


THIS HAS BURNED YOU

Real failures from past sessions. Don't repeat them.

MistakeWhat HappenedPrevention
Guessed APIAssumed API exists. It doesn't. 20 min wasted.verify_api first
Kept guessingSame error 4 times. Finally checked apple-docs MCP.Stop at 2, investigate
Separate ProfileStore instancesMenuBarProfileStore created separate ProfileStore - state never syncedUse ProfileStore.shared singleton
Hardcoded IP filterRemoteSyncService rejected valid IPs like 192.168.x.xUse HostsParser.isValidIPAddress()
Serial disk writesBulk operations wrote to disk per entry - severe lagUse bulkUpdateEntries() / bulkRemoveEntries()
Missing hardened runtimeNotarization rejected - missing entitlementAdd ENABLE_HARDENED_RUNTIME = YES to Shared.xcconfig
1-second polling for syncMenuBarProfileStore polled ProfileStore - wastefulUse NotificationCenter instead
OISD URLs 404OISD discontinued HOSTS format Jan 2024URL liveness preflight checks

The #1 differentiator: Skimming this SOP = 5/10 sessions. Internalizing it = 8+/10.

"If you skim you sin." - The answers are here. Read them.


Quick Start for AI Agents

New to this project? Start here:

  1. Read Rule #0 first (Section "The Rules") - It's about HOW to use all other rules
  2. All files stay in project - NEVER write files outside ~/SaneApps/apps/SaneHosts/ unless user explicitly requests it
  3. Use SaneMaster for builds/tests - never raw xcodebuild
  4. Self-rate after every task - Rate yourself 1-10 on SOP adherence (see Self-Rating section)

SaneMaster (DO THIS FIRST)

Key Commands:

# Build + Test
./scripts/SaneMaster.rb verify

# Build + Launch
./scripts/SaneMaster.rb test_mode

# Stream logs
./scripts/SaneMaster.rb logs --follow

The Rules

#0: NAME THE RULE BEFORE YOU CODE

DO: State which rules apply before writing code DON'T: Start coding without thinking about rules

RIGHT: "Uses Apple API -> Rule #2: VERIFY BEFORE YOU TRY"
RIGHT: "New file -> Rule #9: NEW FILE? GEN THAT PILE"
WRONG: "Let me just code this real quick..."

#1: STAY IN YOUR LANE

DO: Save all files inside ~/SaneApps/apps/SaneHosts/ DON'T: Create files outside project without asking

#2: VERIFY BEFORE YOU TRY

DO: Check API exists before using (apple-docs MCP, context7 MCP) DON'T: Assume an API exists from memory or web search

Critical APIs for SaneHosts:

  • NSAppleScript - privilege elevation for /etc/hosts writes
  • SMAppService and XPC helper interfaces
  • dscacheutil - DNS cache flush

#3: TWO STRIKES? INVESTIGATE

DO: After 2 failures -> stop, follow Research Protocol (see section below) DON'T: Guess a third time without researching

#4: GREEN MEANS GO

DO: Fix all test failures before claiming done DON'T: Ship with failing tests

#5: SANEMASTER OR DISASTER

DO: Use ./scripts/SaneMaster.rb for all build/test operations DON'T: Use raw xcodebuild commands

# Right
./scripts/SaneMaster.rb verify
./scripts/SaneMaster.rb test_mode

# Wrong
xcodebuild -workspace SaneHosts.xcworkspace ...

#6: BUILD, KILL, LAUNCH, LOG

DO: Run full sequence after every code change DON'T: Skip steps or assume it works

# Kill existing process
killall -9 SaneHosts 2>/dev/null; sleep 1

# Build + launch via SaneMaster
./scripts/SaneMaster.rb test_mode

#7: NO TEST? NO REST

DO: Every bug fix gets a test that verifies the fix DON'T: Use placeholder or tautology assertions (#expect(true))

Test location: SaneHostsPackage/Tests/SaneHostsFeatureTests/

#8: BUG FOUND? WRITE IT DOWN

DO: Document bugs in TodoWrite immediately DON'T: Try to remember bugs or skip documentation

#9: NEW FILE? UPDATE THE PACKAGE

DO: After creating new Swift files, ensure they're in the right SPM target DON'T: Create files and forget to add them to Package.swift if needed

Note: SaneHosts uses SPM package structure (SaneHostsPackage/). Files added to existing directories are auto-included. New directories may need Package.swift updates.

#10: FIVE HUNDRED'S FINE, EIGHT'S THE LINE

LinesStatus
<500Good
500-800OK if single responsibility
>800Must split

#11: TOOL BROKE? FIX THE YOKE

DO: If SaneMaster fails, debug the issue DON'T: Work around broken tools

#12: TALK WHILE I WALK

DO: Use subagents for heavy lifting, stay responsive to user DON'T: Block on long operations


Self-Rating (MANDATORY)

After each task, rate yourself. Format:

**Self-rating: 7/10**
Verified API before using, ran full test cycle
Forgot to run tests after first change
ScoreMeaning
9-10All rules followed
7-8Minor miss
5-6Notable gaps
1-4Multiple violations

Research Protocol (STANDARD)

This is the standard protocol for investigating problems. Used by Rule #3, Circuit Breaker, and any time you're stuck.

Tools to Use (ALL of them)

ToolPurposeWhen to Use
Task agentsExplore codebase, analyze patterns"Where is X used?", "How does Y work?"
apple-docs MCPVerify Apple APIs exist and usageAny Apple framework API
context7 MCPLibrary documentationThird-party packages
WebSearch/WebFetchSolutions, patterns, best practicesError messages, architectural questions
Grep/Glob/ReadLocal investigationFind similar patterns, check implementations
memory MCPPast bug patterns, architecture decisions"Have we seen this before?"

Research Output -> Plan

After research, present findings in this format:

## Research Findings

### What I Found
- [Tool used]: [What it revealed]
- [Tool used]: [What it revealed]

### Root Cause
[Clear explanation of why the problem occurs]

### Proposed Fix

[Rule #X: NAME] - specific action
[Rule #Y: NAME] - specific action
...

### Verification
- [ ] Tests pass (`./scripts/SaneMaster.rb verify`)
- [ ] Manual test: [specific check]

Circuit Breaker Protocol

The circuit breaker is an automated safety mechanism that blocks Edit/Bash/Write tools after repeated failures.

When It Triggers

ConditionThresholdMeaning
Same error 3x3 identicalStuck in loop, repeating same mistake
Total failures5 any errorsFlailing, time to step back

Recovery Flow

CIRCUIT BREAKER TRIPS
         |
         v
+---------------------------------------------+
|  1. READ ERRORS                             |
|     Check what failed and why               |
+---------------------------------------------+
|  2. RESEARCH (use ALL tools above)          |
|     - What API am I misusing?               |
|     - Has this bug pattern happened before? |
|     - What does the documentation say?      |
+---------------------------------------------+
|  3. PRESENT SOP-COMPLIANT PLAN              |
|     - State which rules apply               |
|     - Show what research revealed           |
|     - Propose specific fix steps            |
+---------------------------------------------+
|  4. USER APPROVES PLAN                      |
+---------------------------------------------+
         |
         v
    EXECUTE APPROVED PLAN

Key insight: Being blocked is not failure - it's the system working. The research phase often reveals the root cause that guessing would never find.


Plan Format (MANDATORY)

Every plan must cite which rule justifies each step. No exceptions.

Format: [Rule #X: NAME] - specific action with file:line or command

DISAPPROVED PLAN

## Plan: Fix Bug

### Steps
1. Clean build
2. Fix the issue
3. Rebuild and verify

Approve?

Why rejected:

  • No [Rule #X] citations - can't verify SOP compliance
  • No tests specified (violates Rule #7)
  • Vague "fix" without file:line references

APPROVED PLAN

## Plan: Fix [Bug Description]

### Bugs to Fix
| Bug | File:Line | Root Cause |
|-----|-----------|------------|
| [Description] | [File.swift:50] | [Root cause] |

### Steps

[Rule #5: USE SANEMASTER] - Clean build if needed

[Rule #7: TESTS FOR FIXES] - Create tests:
  - SaneHostsPackage/Tests/SaneHostsFeatureTests/[TestFile].swift

[Rule #6: FULL CYCLE] - Verify fixes:
  - ./scripts/SaneMaster.rb verify
  - ./scripts/SaneMaster.rb test_mode
  - Manual: [specific check]

[Rule #4: GREEN BEFORE DONE] - All tests pass before claiming complete

Approve?

Project Structure

SaneHosts/
+-- SaneHosts.xcworkspace         # OPEN THIS (workspace with app + SPM)
+-- SaneHosts/                    # App target (minimal entry point)
|   +-- SaneHostsApp.swift
|   +-- Assets.xcassets/
+-- SaneHostsPackage/             # SPM package with all feature code
|   +-- Sources/
|   |   +-- SaneHostsFeature/
|   |       +-- Models/           # Profile, HostEntry
|   |       +-- Services/         # HostsService, ProfileStore, DNSService
|   |       +-- Views/            # SwiftUI views
|   +-- Tests/
|       +-- SaneHostsFeatureTests/
+-- Config/                       # Build configurations
+-- scripts/                      # Release scripts
+-- docs/                         # Documentation
+-- website/                      # Landing page

Key Services

ServicePurpose
HostsServiceReads/writes /etc/hosts via AppleScript with admin privileges
ProfileStoreProfile CRUD and persistence (UserDefaults + JSON files)
DNSServiceFlushes DNS cache after hosts file changes
RemoteSyncServiceImports hosts from remote URLs (blocklists)
HostsParserParses hosts file format

Singleton Pattern: Use ProfileStore.shared for app-wide state sharing.


Security Considerations

AspectDetails
Admin AuthenticationHosts file modifications require admin password
AppleScript ElevationUses do shell script with administrator privileges
No SandboxRequired to write /etc/hosts (system file)
Hardened RuntimeRequired for notarization
Entitlementscom.apple.security.automation.apple-events for AppleScript

Data Locations

DataLocation
Profiles~/Library/Application Support/SaneHosts/Profiles/*.json
UserDefaultsStandard UserDefaults for settings
Derived Data~/Library/Developer/Xcode/DerivedData/SaneHosts-*/

MCP Tool Optimization (TOKEN SAVERS)

SaneMaster (Required)

Use the unified SaneMaster workflow for build/test:

./scripts/SaneMaster.rb verify
./scripts/SaneMaster.rb test_mode
./scripts/SaneMaster.rb logs --follow

Memory MCP 3-Layer Workflow (10x Token Savings)

1. search_nodes(query, project: "SaneHosts") -> Get index with node IDs
2. Use node IDs to fetch specific context
3. read_graph() -> Full graph only if needed

Always filter by project for isolation.

apple-docs Optimization

  • compact: true works on list_technologies, get_sample_code, wwdc (NOT on search_apple_docs)
  • analyze_api analysis="all" for comprehensive API analysis

context7 for Library Docs

  • resolve-library-id FIRST, then query-docs
  • SwiftUI ID: /websites/developer_apple_swiftui (13,515 snippets!)

Distribution

See docs/DISTRIBUTION.md for full release checklist.

Critical Credentials (DO NOT REGENERATE)

CredentialValue/Location
Sparkle Public Key7Pl/8cwfb2vm4Dm65AByslkMCScLJ9tbGlwGGx81qYU=
Sparkle Private KeymacOS Keychain (account: "EdDSA Private Key", service: "https://sparkle-project.org")
Notarytool Profilenotarytool (in system keychain)
Team IDM78L6FXD48

Release Scripts

# Preflight direct and App Store lanes
./scripts/SaneMaster.rb release_preflight
./scripts/SaneMaster.rb appstore_preflight

# Build, sign, notarize, upload, generate appcast, and deploy website
bash ~/SaneApps/infra/SaneProcess/scripts/release.sh \
  --project "$(pwd)" --full --version X.Y.Z --notes "..." --deploy

Toolbelt & Credentials (Available for Agents)

The following tools and API keys are configured in the environment. Use them.

ToolCapabilityKeychain LocationAccount / Key
ResendSend transactional/outreach emailsService: resendapi_key
LemonSqueezyQuery sales, orders, license keysService: lemonsqueezyapi_key
CloudflareDeploy sites, manage R2 storageService: cloudflare(Check specific item)
GitHubPRs, Issues, Outreach (gh CLI)Server: github.com(Auto-managed by gh)
NotarytoolSign & notarize macOS appsProfile: notarytool(Stored in system keychain)

How to Access in Scripts:

# Example: Fetch Resend Key
RESEND_KEY=$(security find-generic-password -s "resend" -a "api_key" -w)

Troubleshooting

ProblemFix
Ghost beeps / no launchEnsure workspace is open, rebuild
Phantom build errors./scripts/SaneMaster.rb clean --nuclear, delete DerivedData
"File not found" after new fileCheck SPM package includes the file
Tests failing mysteriouslyClean build, check for stale derived data
Password prompt not appearingCheck NSAppleScript entitlements
DNS not flushingCheck dscacheutil -flushcache works manually
State not syncingUse ProfileStore.shared singleton
Notarization failsCheck hardened runtime is enabled