Skip to content

Latest commit

 

History

History
485 lines (349 loc) · 14.8 KB

File metadata and controls

485 lines (349 loc) · 14.8 KB

SaneHosts Development Guide (SOP)

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.

Mistake What Happened Prevention
Guessed API Assumed API exists. It doesn't. 20 min wasted. verify_api first
Kept guessing Same error 4 times. Finally checked apple-docs MCP. Stop at 2, investigate
Separate ProfileStore instances MenuBarProfileStore created separate ProfileStore - state never synced Use ProfileStore.shared singleton
Hardcoded IP filter RemoteSyncService rejected valid IPs like 192.168.x.x Use HostsParser.isValidIPAddress()
Serial disk writes Bulk operations wrote to disk per entry - severe lag Use bulkUpdateEntries() / bulkRemoveEntries()
Missing hardened runtime Notarization rejected - missing entitlement Add ENABLE_HARDENED_RUNTIME = YES to Shared.xcconfig
1-second polling for sync MenuBarProfileStore polled ProfileStore - wasteful Use NotificationCenter instead
OISD URLs 404 OISD discontinued HOSTS format Jan 2024 URL 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; WebSearch for third-party) 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

Lines Status
<500 Good
500-800 OK if single responsibility
>800 Must 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
Score Meaning
9-10 All rules followed
7-8 Minor miss
5-6 Notable gaps
1-4 Multiple 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)

Tool Purpose When to Use
Task agents Explore codebase, analyze patterns "Where is X used?", "How does Y work?"
apple-docs MCP Verify Apple APIs exist and usage Any Apple framework API
WebSearch/WebFetch Solutions, patterns, best practices, third-party library docs Error messages, architectural questions, non-Apple packages
Grep/Glob/Read Local investigation Find similar patterns, check implementations
AgentMemory Shared bug patterns and architecture decisions memory_recall / memory_smart_search

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

Condition Threshold Meaning
Same error 3x 3 identical Stuck in loop, repeating same mistake
Total failures 5 any errors Flailing, 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

Service Purpose
HostsService Reads/writes /etc/hosts via AppleScript with admin privileges
ProfileStore Profile CRUD and persistence (UserDefaults + JSON files)
DNSService Flushes DNS cache after hosts file changes
RemoteSyncService Imports hosts from remote URLs (blocklists)
HostsParser Parses hosts file format

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


Security Considerations

Aspect Details
Admin Authentication Hosts file modifications require admin password
AppleScript Elevation Uses do shell script with administrator privileges
No Sandbox Required to write /etc/hosts (system file)
Hardened Runtime Required for notarization
Entitlements com.apple.security.automation.apple-events for AppleScript

Data Locations

Data Location
Profiles ~/Library/Application Support/SaneHosts/Profiles/*.json
UserDefaults Standard 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

AgentMemory Recall Workflow

1. mcp__agentmemory__memory_smart_search(query: "SaneHosts ...")
2. Expand only relevant observation IDs when more detail is needed
3. Use mcp__agentmemory__memory_recall for broader session context

Use Serena for project-scoped long-form notes. Graph extraction is optional and intentionally off; do not use the retired mcp__memory__* namespace.

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

Library docs (third-party packages)

  • Use WebSearch. The context7 plugin is currently toggled off, so mcp__context7__* is not callable. For Apple frameworks use apple-docs instead.

Distribution

See docs/DISTRIBUTION.md for full release checklist.

Critical Credentials (DO NOT REGENERATE)

Credential Value/Location
Sparkle Public Key 7Pl/8cwfb2vm4Dm65AByslkMCScLJ9tbGlwGGx81qYU=
Sparkle Private Key macOS Keychain (account: "EdDSA Private Key", service: "https://sparkle-project.org")
Notarytool Profile notarytool (in system keychain)
Team ID M78L6FXD48

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.

Tool Capability Keychain Location Account / Key
Resend Send transactional/outreach emails Service: resend api_key
LemonSqueezy Query sales, orders, license keys Service: lemonsqueezy api_key
Cloudflare Deploy sites, manage R2 storage Service: cloudflare (Check specific item)
GitHub PRs, Issues, Outreach (gh CLI) Server: github.com (Auto-managed by gh)
Notarytool Sign & notarize macOS apps Profile: 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

Problem Fix
Ghost beeps / no launch Ensure workspace is open, rebuild
Phantom build errors ./scripts/SaneMaster.rb clean --nuclear, delete DerivedData
"File not found" after new file Check SPM package includes the file
Tests failing mysteriously Clean build, check for stale derived data
Password prompt not appearing Check NSAppleScript entitlements
DNS not flushing Check dscacheutil -flushcache works manually
State not syncing Use ProfileStore.shared singleton
Notarization fails Check hardened runtime is enabled