{"id":51335791,"url":"https://github.com/thomasguillot/hosts-switchr","last_synced_at":"2026-07-02T02:30:50.288Z","repository":{"id":367607369,"uuid":"1281526383","full_name":"thomasguillot/hosts-switchr","owner":"thomasguillot","description":"A native macOS menu-bar app for managing /etc/hosts through switchable profiles. macOS 26 (Tahoe)+","archived":false,"fork":false,"pushed_at":"2026-06-26T17:11:38.000Z","size":215,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-26T19:09:11.728Z","etag":null,"topics":["blocklist","developer-tools","etc-hosts","hosts","hosts-file","macos","menu-bar","swift","swiftui","tahoe"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thomasguillot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-26T16:39:56.000Z","updated_at":"2026-06-26T17:11:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/thomasguillot/hosts-switchr","commit_stats":null,"previous_names":["thomasguillot/hosts-switchr"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/thomasguillot/hosts-switchr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasguillot%2Fhosts-switchr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasguillot%2Fhosts-switchr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasguillot%2Fhosts-switchr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasguillot%2Fhosts-switchr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thomasguillot","download_url":"https://codeload.github.com/thomasguillot/hosts-switchr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasguillot%2Fhosts-switchr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35030920,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-02T02:00:06.368Z","response_time":173,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blocklist","developer-tools","etc-hosts","hosts","hosts-file","macos","menu-bar","swift","swiftui","tahoe"],"created_at":"2026-07-02T02:30:49.633Z","updated_at":"2026-07-02T02:30:50.269Z","avatar_url":"https://github.com/thomasguillot.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hosts Switchr\n\nA native macOS menu-bar app for managing `/etc/hosts` through switchable profiles.\n\n**Requires macOS 26 (Tahoe) or later. Unsigned — no Apple Developer Program needed.**\n\n---\n\n## For users\n\n### What it does\n\n- **Profiles** — create, edit, and instantly switch named `/etc/hosts` configurations from the menu bar.\n- **Blocklist sources** — subscribe to hosts-format lists. Built in: **StevenBlack** (Unified, plus Fake News / Gambling / Porn / Social) and **HaGeZi** (Light → Normal → Pro → Pro++ → Ultimate). Sources auto-refresh with conditional-GET (ETag) caching, and you can add your own.\n- **Fragments** — reusable hosts snippets you toggle into any profile (e.g. a \"Docker\" fragment listing your local container hostnames, switched on only in your Dev profile).\n- **Import / export** — back up your whole setup to a JSON file, restore it on another machine, or import a plain hosts file as a profile or fragment.\n- **Launch at login** — runs quietly as a menu-bar-only app (no Dock icon), and can optionally show the active profile name next to the menu-bar icon.\n\n### Install\n\nThe app is unsigned (it deliberately uses no Apple Developer Program, signing, or privileged helper), so macOS blocks it on first launch. To allow it:\n\n1. Double-click **Hosts Switchr**; when macOS warns it \"can't verify the developer,\" click **Done** (*not* \"Move to Trash\").\n2. Open **System Settings → Privacy \u0026 Security** and scroll to the **Security** section.\n3. Click **Open Anyway** next to *\"Hosts Switchr\" was blocked to protect your Mac*, then authenticate and click **Open**.\n\nmacOS only asks once — after that it launches normally.\n\nIf you don't have a prebuilt app, build it from source — see [For developers](#for-developers).\n\n### Using it\n\n1. Launch the app — it lives in the **menu bar** (no Dock icon).\n2. **Profiles** — select a profile and click **Apply** to write it to `/etc/hosts`. You'll be asked for your admin password; this is the only privileged step. Switch the active profile anytime straight from the menu-bar menu.\n3. **Sources** — toggle built-in or custom blocklists on per profile. Right-click a source to refresh it, or use **Refresh All Sources** in the menu bar.\n4. **Fragments** — create reusable snippets and toggle them into any profile.\n5. **Settings** — enable Launch at login and the active-profile name in the menu bar.\n6. **Rename \u0026 delete** — new profiles and fragments open ready to rename; press **⌘⌫** (or right-click → Delete) to remove the selected item. The active profile and built-in sources can't be deleted.\n\nNew to it? See **Help → Hosts Switchr Help** for a built-in guide.\n\nYour data lives in `~/Library/Application Support/HostsSwitchr/`. `/etc/hosts` is only ever changed when you click **Apply**.\n\n---\n\n## For developers\n\n### Requirements\n\n- macOS 26 (Tahoe)+, Xcode 26+\n- [xcodegen](https://github.com/yonaskolb/XcodeGen) (`brew install xcodegen`)\n- [SwiftLint](https://github.com/realm/SwiftLint) (`brew install swiftlint`) — enforced in the build phase\n\n### Build\n\n```sh\n# Logic package (no Xcode needed)\ncd HostsKit \u0026\u0026 swift test\n\n# App — generate the project, then open or build\ncd App \u0026\u0026 xcodegen \u0026\u0026 open HostsSwitchr.xcodeproj\n```\n\nHeadless build:\n\n```sh\ncd App \u0026\u0026 xcodegen \u0026\u0026 xcodebuild \\\n  -project HostsSwitchr.xcodeproj \\\n  -scheme HostsSwitchr \\\n  -destination 'platform=macOS' \\\n  build\n```\n\n\u003e `App/HostsSwitchr.xcodeproj` is generated by xcodegen and git-ignored — edit `App/project.yml`, not the project file. Run SwiftLint from the repo **root**.\n\n### Packaging a release\n\n```sh\n./scripts/make-dmg.sh\n```\n\nBuilds the Release configuration and produces `dist/HostsSwitchr-\u003cversion\u003e.dmg`, a drag-to-Applications disk image. The version comes from `MARKETING_VERSION` in `App/project.yml`. Requires `create-dmg` (`brew install create-dmg`).\n\n### Architecture\n\n```\nhosts-switchr/\n├── HostsKit/          # Pure Swift package — all logic, zero UI, zero app framework\n│   └── Sources/HostsKit/\n│       ├── Profile, ProfileStore        # named /etc/hosts configs, ordered, persisted\n│       ├── LocalFragment, FragmentStore # reusable local snippets\n│       ├── RemoteSource, SourceCatalog  # blocklist subscriptions + built-in catalog\n│       ├── SourceFetcher, SourceRefresher # conditional-GET fetch + scheduling\n│       ├── MergedHostsComposer          # streams local → fragments → sources to a temp file\n│       ├── HostsApplier, PrivilegedRunner # atomic privileged write to /etc/hosts via osascript\n│       ├── ConfigBundle                 # import/export bundle model\n│       └── …validation, scanning, login-item protocol\n└── App/               # SwiftUI macOS app — thin UI layer over HostsKit\n    └── Sources/\n        ├── HostsSwitchrApp              # @main, MenuBarExtra, Window, Settings scenes\n        ├── AppModel                     # @Observable coordinator; owns all stores\n        └── …views\n```\n\n**Key invariants:**\n\n- All persistent state lives in `~/Library/Application Support/HostsSwitchr/`.\n- Writes to `/etc/hosts` go through a unique-named temp file → `cp` via `osascript` (no helper daemon, no signing required); the merged content is never interpolated into the shell command.\n- Remote sources require `https://`; imported URLs go through the same `SourceURLPolicy` guard.\n- Fail-closed everywhere: corrupt store files are preserved to a `.corrupt` path before any overwrite.\n\nFor the full agent/contributor guide (conventions, security invariants, build/test workflow), see [`AGENTS.md`](AGENTS.md).\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomasguillot%2Fhosts-switchr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthomasguillot%2Fhosts-switchr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomasguillot%2Fhosts-switchr/lists"}