README · ARCHITECTURE · DEVELOPMENT · PRIVACY · SECURITY
Version 1.0 | Last updated: 2026-01-20
SINGLE SOURCE OF TRUTH for all Developers and AI Agents.
+-----------------------------------------------------+
| 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
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.
New to this project? Start here:
- Read Rule #0 first (Section "The Rules") - It's about HOW to use all other rules
- All files stay in project - NEVER write files outside
~/SaneApps/apps/SaneHosts/unless user explicitly requests it - Use SaneMaster for builds/tests - never raw
xcodebuild - Self-rate after every task - Rate yourself 1-10 on SOP adherence (see Self-Rating section)
Key Commands:
# Build + Test
./scripts/SaneMaster.rb verify
# Build + Launch
./scripts/SaneMaster.rb test_mode
# Stream logs
./scripts/SaneMaster.rb logs --followDO: 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..."
DO: Save all files inside ~/SaneApps/apps/SaneHosts/
DON'T: Create files outside project without asking
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 writesSMAppServiceand XPC helper interfacesdscacheutil- DNS cache flush
DO: After 2 failures -> stop, follow Research Protocol (see section below) DON'T: Guess a third time without researching
DO: Fix all test failures before claiming done DON'T: Ship with failing tests
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 ...
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_modeDO: Every bug fix gets a test that verifies the fix
DON'T: Use placeholder or tautology assertions (#expect(true))
Test location: SaneHostsPackage/Tests/SaneHostsFeatureTests/
DO: Document bugs in TodoWrite immediately DON'T: Try to remember bugs or skip documentation
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.
| Lines | Status |
|---|---|
| <500 | Good |
| 500-800 | OK if single responsibility |
| >800 | Must split |
DO: If SaneMaster fails, debug the issue DON'T: Work around broken tools
DO: Use subagents for heavy lifting, stay responsive to user DON'T: Block on long operations
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 |
This is the standard protocol for investigating problems. Used by Rule #3, Circuit Breaker, and any time you're stuck.
| 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 |
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]
The circuit breaker is an automated safety mechanism that blocks Edit/Bash/Write tools after repeated failures.
| Condition | Threshold | Meaning |
|---|---|---|
| Same error 3x | 3 identical | Stuck in loop, repeating same mistake |
| Total failures | 5 any errors | Flailing, time to step back |
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.
Every plan must cite which rule justifies each step. No exceptions.
Format: [Rule #X: NAME] - specific action with file:line or command
## 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
## 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?
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
| 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.
| 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 | Location |
|---|---|
| Profiles | ~/Library/Application Support/SaneHosts/Profiles/*.json |
| UserDefaults | Standard UserDefaults for settings |
| Derived Data | ~/Library/Developer/Xcode/DerivedData/SaneHosts-*/ |
Use the unified SaneMaster workflow for build/test:
./scripts/SaneMaster.rb verify
./scripts/SaneMaster.rb test_mode
./scripts/SaneMaster.rb logs --follow
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.
compact: trueworks onlist_technologies,get_sample_code,wwdc(NOT onsearch_apple_docs)analyze_api analysis="all"for comprehensive API analysis
- Use WebSearch. The context7 plugin is currently toggled off, so
mcp__context7__*is not callable. For Apple frameworks useapple-docsinstead.
See docs/DISTRIBUTION.md for full release checklist.
| 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 |
# 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 "..." --deployThe 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)| 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 |