SPB Git

spb/zyquo-atlas Public License

The AI-native macOS web browser — every surface, intelligent.

Swift 75.2% JavaScript 22% Shell 2% Makefile 0.9%

phase1: SPM project setup — Package.swift, Makefile (SDK 26 pin), browser Info.plist, @main SwiftUI app launches; Phase 1 gate PASSED

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
simon-pierre boucher committed 11 days ago (Jul 30, 2026) parent f71178c

Showing 16 changed files with +889 and −0

modified .gitignore +3 −0
@@ -16,3 +16,6 @@ dist/
16 16
17 17 # Temporary
18 18 *.log
19 +
20 +# SwiftPM
21 +.swiftpm/
added CLAUDE.md +330 −0
@@ -0,0 +1,330 @@
1 +# CLAUDE.md — Zyquo Atlas
2 +
3 +## Project Identity
4 +
5 +**Zyquo Atlas** is the web-browser member of the **Zyquo** family: a legendary, native macOS **web browser** written in **Swift + SwiftUI**, built **without the Xcode IDE** (Swift Package Manager + command-line toolchain). It is designed to **pulverize Safari** — a faster, radically more customizable, AI-native browser where artificial intelligence is woven into *every* surface, not bolted on as a sidebar afterthought.
6 +
7 +Zyquo Atlas rests on three pillars:
8 +1. **Massive display & theme customization** — the user can reshape almost everything: layout, chrome, colors, themes, fonts, density, tab styles, backgrounds. It should feel like *their* browser.
9 +2. **First-class favorites & history management** — powerful, searchable, organizable, beautiful.
10 +3. **AI everywhere, done legendarily** — summarize, chat-with-page, ask about selection, AI search, compose/rewrite in any text field, translate, extract, automate reading, and more — powered by **the exact same providers and models as Zyquo Cloud** (all of them).
11 +
12 +Zyquo Atlas reuses Zyquo Cloud's provider/API layer and encrypted key vault, and must match the family's premium native design quality.
13 +
14 +**Naming conventions (use consistently everywhere):**
15 +- Display name / product name: `Zyquo Atlas`
16 +- App bundle: `Zyquo Atlas.app`
17 +- Bundle identifier: `com.zyquo.atlas`
18 +- Executable / SPM target: `ZyquoAtlas` (no space)
19 +- Data folder: `~/Library/Application Support/ZyquoAtlas/`
20 +- Profiles/browsing data: `~/Library/Application Support/ZyquoAtlas/Profiles/`
21 +- Repo module prefix in file headers: `Zyquo Atlas`
22 +
23 +---
24 +
25 +## 📋 MANDATORY FILE HEADER — EVERY CODE FILE
26 +
27 +**Every single code file you write** (all `.swift` files, plus `Makefile`, shell scripts, `Package.swift`, verification scripts — anything containing code) **MUST begin with this header comment**, adapted to the file's comment syntax:
28 +
29 +```swift
30 +//
31 +// <FileName>.swift
32 +// Zyquo Atlas
33 +//
34 +// Author: Simon-Pierre Boucher
35 +// Mail: contact@spboucher.ai
36 +//
37 +```
38 +
39 +For shell scripts / Makefiles:
40 +
41 +```bash
42 +#
43 +# <filename>
44 +# Zyquo Atlas
45 +#
46 +# Author: Simon-Pierre Boucher
47 +# Mail: contact@spboucher.ai
48 +#
49 +```
50 +
51 +No exceptions. If you ever create or refactor a file and the header is missing, add it. Before declaring the project done, run a sweep over the repository to verify every code file carries the header.
52 +
53 +---
54 +
55 +## 🧭 METHODOLOGY — WORK METHODICALLY, KEEP EVERYTHING COHERENT
56 +
57 +You must execute this project **strictly in phase order (0 → 8)**. Do not jump ahead, do not interleave phases, do not build AI features before a real tab can load and render a page, and do not write any code before Phase 0 research + Zyquo Cloud study are complete.
58 +
59 +**Working rules:**
60 +
61 +1. **One phase at a time.** At the start of each phase, write a checklist into `docs/PLAN.md`; check items off as you go. At the end of each phase, run a **phase checkpoint**: build (`swift build`), run what's runnable, fix all warnings/errors, write a 3–5 line phase summary in `docs/PLAN.md` before moving on.
62 +2. **Phase gates:** Phase 0 is complete only when `docs/AI-BROWSER-RESEARCH.md` and `docs/PROVIDER-REUSE.md` are complete. Phase 2 is complete only when a WKWebView-based tab can navigate, show progress, handle back/forward, and the multi-tab model works. Phase 3 is complete only when page content can be reliably extracted and fed to a model, and one AI action (summarize page) works end-to-end with streaming. Phase 4 spec is the contract for all UI in Phase 6. Phase 7 is complete only when browser + AI verification passes with real keys. Phase 8 is complete only when `spctl` says "Notarized Developer ID".
63 +3. **Single source of truth, everywhere:**
64 + - Provider/model behavior → ported from Zyquo Cloud's client layer (Phase 0.B); never re-invent request formats. **All Zyquo Cloud models are available in Atlas.**
65 + - Colors, fonts, spacing, radii → base values from `ZyquoTheme` tokens; user themes override via the theming engine (Phase 4). Zero raw hex values or magic numbers in views.
66 + - Web engine, content extraction, and AI orchestration → live in the `Browser/`, `Content/`, and `AI/` layers; never leak WKWebView or network guts into unrelated views.
67 + - Product naming → per the conventions above. Never `Zyquo` alone, never `ZyquoAtlas` in user-facing text.
68 +4. **Coherence sweeps:** after Phases 3, 6, and 8, do a consistency pass (uniform naming — always `Tab`, `AIAction`, `PageContext`, `ProviderClient`; no dead code; headers present; folders match Phase 2).
69 +5. **Compile early, compile often.** Never accumulate more than one file of unbuilt changes.
70 +6. **Commit discipline:** one logical unit per commit, phase-prefixed message. Never commit secrets or user browsing data.
71 +7. **Privacy is a design constraint, not a feature bullet:** page content only leaves the machine when the user invokes an AI action (or has explicitly enabled an auto action), always to the user's chosen provider via their own key, never to Zyquo. This must hold from the first AI code written.
72 +
73 +---
74 +
75 +## ⚠️ PHASE 0 — MANDATORY RESEARCH + ZYQUO CLOUD STUDY (DO THIS FIRST, BEFORE ANY CODE)
76 +
77 +Two mandatory research tracks, each producing a document. No Swift until both are done.
78 +
79 +### 0.A — `docs/AI-BROWSER-RESEARCH.md` — how to integrate AI into a browser, legendarily (INTENSIVE WEB RESEARCH)
80 +
81 +Do NOT rely on training data. Perform **several intensive web research sessions** studying how the best AI browsers and browser-AI products actually work, and synthesize a concrete, functional design. Research at minimum:
82 +
83 +1. **The landscape.** Study current AI browsers and AI browsing features for patterns worth stealing and pitfalls to avoid: **Arc / Arc Max & Dia (Browser Company), Perplexity Comet, Brave Leo, Microsoft Edge Copilot, Opera Aria, SigmaOS, and Chrome's built-in AI**. Document what each does well: page summarization, chat-with-page, AI search/answers, tab organization, "ask about this", command bars, writing assistance, agentic browsing. Extract the *functional* interaction patterns, not marketing.
84 +2. **Page content extraction for LLMs.** The hard part. Research how to reliably turn a live web page into clean, model-ready text: **readability/DOM extraction** (Mozilla Readability-style main-content extraction), stripping nav/ads/boilerplate, preserving structure/headings/links, handling article vs. app pages, extracting the user's **current text selection**, capturing visible viewport vs. full document, and handling very long pages (chunking + map-reduce summarization). Document how to inject JavaScript into WKWebView (`WKUserScript`, `evaluateJavaScript`) to get this content out.
85 +3. **Chunking, context, and long pages.** How to summarize/answer over pages that exceed the context window: chunking strategies, map-reduce and refine summarization, embedding-free relevance selection (keyword/heuristic) vs. optional local embeddings, and citing which part of the page an answer came from.
86 +4. **AI surfaces & UX patterns.** Where AI lives in a legendary browser: an **AI command bar / omnibox** (ask vs. navigate vs. search intent detection), a **contextual sidebar chat** bound to the current page/tab, **inline selection actions** (select text → floating "Ask / Explain / Translate / Rewrite"), **AI-assisted writing in any web text field**, **AI search** (answer + sources instead of just links), **tab & session summarization**, **auto-summaries on hover/open**, and lightweight **agentic actions** (e.g., "find and open the docs page for X"). Document keyboard-driven flows.
87 +5. **Streaming & responsiveness.** How to stream AI output into browser UI without blocking navigation, run AI per-tab, cancel on navigation, and keep everything at 60fps.
88 +6. **Multi-tab / multi-page reasoning.** Patterns for "summarize these 5 tabs", "compare these pages", chat that can reference multiple open tabs.
89 +7. **Safety/privacy & correctness.** Clear consent before sending page data, on-screen indication when content leaves the device, avoiding hallucinated citations, and grounding answers in extracted content.
90 +
91 +Write it into `docs/AI-BROWSER-RESEARCH.md`. Every AI feature in later phases must trace to a pattern documented here.
92 +
93 +### 0.B — `docs/PROVIDER-REUSE.md` — study the Zyquo Cloud repo and reuse its providers
94 +
95 +**Before writing provider code, read and study the Zyquo Cloud repository** (sibling project). Locate it on disk (check the user's projects folder; if not found, ask the user for its path). Document and reuse:
96 +
97 +1. **Exactly how each provider's API is called** in Zyquo Cloud: base URLs, auth headers, request/response `Codable` models, the shared `OpenAICompatibleClient`, native `AnthropicClient` / `GeminiClient`, and the streaming (SSE) handling. Atlas must call models the **exact same way** — port or factor the code so it is identical to Cloud's.
98 +2. **The complete model catalog** Zyquo Cloud ships (`ModelCatalog` / `docs/PROVIDERS.md`). **Include ALL of these models in Zyquo Atlas** — every provider, every model available in Cloud is available in Atlas. The user picks a default AI model for browsing and can override per feature (e.g., a fast cheap model for hover-summaries, a strong model for deep chat).
99 +3. **The secure key vault** from Cloud (custom AES-256-GCM encryption, **NO Keychain**). Atlas reuses the same `SecureKeyStore` design and vault format.
100 +4. Any provider-specific streaming quirks so Atlas handles all uniformly behind the `ProviderClient` protocol.
101 +
102 +**Outcome:** Atlas's AI layer speaks to the identical providers/models as Zyquo Cloud, with the same keys and behavior.
103 +
104 +---
105 +
106 +## PHASE 1 — Project Setup (No Xcode IDE)
107 +
108 +- **Toolchain:** Swift Package Manager. `Package.swift`, executable target `ZyquoAtlas`. Build `swift build -c release`.
109 +- **Web engine:** **WebKit / `WKWebView`** (the system web engine) — the correct, supported path for a native macOS browser without bundling Chromium. Use `WKWebViewConfiguration`, `WKUserContentController`, `WKWebsiteDataStore` (persistent + non-persistent for private tabs), and process pooling for multi-tab.
110 +- **App bundle:** `Makefile` builds release, assembles `Zyquo Atlas.app` (`Contents/MacOS/ZyquoAtlas`, `Info.plist`, `Resources/AppIcon.icns`), signs (Phase 8; ad-hoc for `make dev`).
111 +- **Info.plist:** `CFBundleDisplayName` = `Zyquo Atlas`, bundle ID `com.zyquo.atlas`, `LSMinimumSystemVersion` (macOS 13.0+), `NSHighResolutionCapable`, `LSApplicationCategoryType` (`public.app-category.productivity`), and `NSAppTransportSecurity` configured appropriately for a browser loading arbitrary sites (a browser needs to load HTTP/arbitrary content — document the correct ATS posture; the WKWebView content itself is the exception surface, keep app's own API calls HTTPS-only). Register as a candidate default browser (`CFBundleURLTypes` for `http`/`https`, and handle `NSUserActivityTypes`/default-browser APIs). Universal (arm64 + x86_64) for release.
112 +- **Entry point:** `@main` SwiftUI `App`; proper activation from terminal launch.
113 +- **Dependencies:** Foundation + SwiftUI + WebKit + CryptoKit; Apple `swift-markdown` acceptable. Reuse Zyquo Cloud's URLSession networking — no external HTTP libs.
114 +
115 +---
116 +
117 +## PHASE 2 — Architecture + Browser Core
118 +
119 +```
120 +Sources/ZyquoAtlas/
121 +├── App/ # @main, window/scene, menu bar, default-browser handling
122 +├── DesignSystem/ # ZyquoTheme tokens + ThemeEngine (user themes)
123 +├── Models/ # Tab, TabGroup, Bookmark, HistoryEntry, Profile, AIAction, PageContext…
124 +├── Browser/
125 +│ ├── WebView.swift # NSViewRepresentable wrapper over WKWebView
126 +│ ├── TabManager.swift # tabs, tab groups/spaces, ordering, suspension
127 +│ ├── NavigationController.swift # url handling, back/forward, reload, progress
128 +│ ├── ProfileStore.swift # data stores, cookies, private/persistent
129 +│ └── DownloadManager.swift # file downloads
130 +├── Content/
131 +│ ├── ContentExtractor.swift # injected JS → clean readable text, selection, metadata
132 +│ ├── Readability.js # bundled main-content extraction script
133 +│ └── PageContext.swift # normalized page representation for the model (title, url, text, selection, chunks)
134 +├── AI/
135 +│ ├── AIService.swift # orchestrates provider calls for browser actions (streaming)
136 +│ ├── AIActions.swift # summarize, chat-with-page, ask-selection, translate, rewrite, AI-search, compare-tabs…
137 +│ ├── Summarizer.swift # chunking + map-reduce/refine for long pages
138 +│ └── OmniIntent.swift # omnibox intent: navigate vs. search vs. ask
139 +├── Providers/ # PORTED FROM ZYQUO CLOUD (all models)
140 +│ ├── ProviderProtocol.swift
141 +│ ├── OpenAICompatibleClient.swift
142 +│ ├── AnthropicClient.swift
143 +│ └── GeminiClient.swift
144 +├── Features/
145 +│ ├── BookmarksService.swift # favorites: folders, tags, search
146 +│ ├── HistoryService.swift # full-text searchable history
147 +│ └── ReadingList.swift
148 +├── Services/
149 +│ ├── SecureKeyStore.swift # reused from Zyquo Cloud (no Keychain)
150 +│ └── PersistenceService.swift # SQLite or JSON for bookmarks/history/sessions
151 +├── ViewModels/
152 +└── Views/
153 +```
154 +
155 +- **Tabs:** real multi-tab with process reuse, lazy loading, background-tab **suspension** to save memory, restore-on-launch, tab groups / "spaces". Each tab owns a `WKWebView` + navigation state + its own AI context.
156 +- **PHASE GATE:** a tab must navigate to a URL, show a determinate progress bar, support back/forward/reload/stop, open links in new tabs, and the omnibox must resolve URL vs. search — before any AI work.
157 +
158 +---
159 +
160 +## PHASE 3 — AI EVERYWHERE (THE DEFINING LAYER)
161 +
162 +Build the content pipeline first, then the AI actions on top. **PHASE GATE:** "Summarize this page" works end-to-end with streaming, grounded in extracted content, on a long real article, using a Zyquo Cloud model.
163 +
164 +### 3.A — Content extraction (`ContentExtractor` + `Readability.js`)
165 +- Inject JavaScript into the active `WKWebView` to extract: page title, URL, **clean main-content text** (Readability-style, boilerplate stripped), headings/structure, links, meta description, and the **user's current selection**. Handle article vs. app pages; fall back gracefully.
166 +- Produce a normalized `PageContext`; for long pages, **chunk** it (with overlap) for map-reduce summarization per the research. Cache per tab; invalidate on navigation.
167 +
168 +### 3.B — AI actions (`AIService` + `AIActions`) — all streaming, all cancel-on-navigation
169 +Implement, at minimum, these **legendary, functional** AI surfaces (from `docs/AI-BROWSER-RESEARCH.md`):
170 +- **AI Command Bar / smart omnibox:** typing detects intent — **navigate** (URL), **search** (web), or **ask** (AI answer with sources). Asking returns a streamed answer plus source links, without leaving the page.
171 +- **Chat-with-page sidebar:** a per-tab contextual chat bound to the current `PageContext`; ask follow-ups about the page; answers cite the section they came from; model picker in the sidebar (all Cloud models).
172 +- **Selection actions:** select text on any page → floating toolbar with **Explain / Summarize / Translate / Rewrite / Ask**; result appears in a popover or the sidebar.
173 +- **Summarize page / TL;DR:** one keystroke; long-page map-reduce; key points + optional full summary.
174 +- **AI writing assist in web text fields:** in any editable field (`<textarea>`, contenteditable), offer improve/rewrite/expand/shorten/fix-grammar/translate via a small inline affordance.
175 +- **Translate page / selection** to a chosen language.
176 +- **Multi-tab reasoning:** "summarize/compare these open tabs" — gather several tabs' `PageContext` and answer across them.
177 +- **Optional auto-actions (opt-in):** auto-summary on opening long articles, hover-preview summaries of links — always user-toggleable.
178 +- **Privacy:** before any page content is sent, respect the consent model (Phase 0.B / global privacy rule); show a clear indicator when content leaves the device; per-site and global toggles.
179 +
180 +### 3.C — Orchestration
181 +- `AIService` routes each action to the chosen provider/model via the ported client layer, streams tokens into the relevant UI, cancels in-flight requests when the user navigates or hits Stop, and lets the user choose different default models per action class (fast/cheap for hovers, strong for deep chat).
182 +
183 +---
184 +
185 +## PHASE 4 — DESIGN SYSTEM, THEMING ENGINE & UI (LIGHT THEME + MASSIVE CUSTOMIZATION)
186 +
187 +Two things at once: a **flawless flagship light theme** (family standard) AND a **massive customization engine** that lets users transform the browser. Build both properly.
188 +
189 +### 4.1 — Base light theme (family standard, must be perfect)
190 +
191 +Base tokens in `ZyquoTheme` — Atlas identity is a **balanced teal-indigo "map/atlas" story** (explorer, cartography):
192 +
193 +| Token | Value (light) | Usage |
194 +|---|---|---|
195 +| `background` | `#FAFBFC` (crisp cool off-white) | Chrome / canvas |
196 +| `surface` | `#FFFFFF` | Toolbars, panels, cards |
197 +| `surfaceSecondary` | `#F1F4F6` | Hover, inactive tabs |
198 +| `accent` | `#1FA9A0` → paired with indigo `#4E63E0` (atlas teal-indigo) | Active tab, selection, AI actions, omnibox focus |
199 +| `accentSubtle` | `#E6F5F3` | Active tab tint, selected rows |
200 +| `textPrimary` `#1A1D22` · `textSecondary` `#6B7280` · `textTertiary` `#9CA3AF` · `border` `#E5E9EC` | | |
201 +| `success`/`warning`/`danger` | `#2FA36B`/`#D9822B`/`#D64545` | Status |
202 +
203 +Family rules apply (no pure black on white, 0.5pt hairlines, ultra-soft shadows on floating panels only, dark theme derived, light theme is flagship). Typography/spacing/radii identical to the family (`body` 13.5pt/1.45; scale 4–32; radii 6/10/14). Chrome must be quiet and refined so web content is the star.
204 +
205 +### 4.2 — THE THEMING & CUSTOMIZATION ENGINE (a headline feature)
206 +Users can massively customize display and themes. Implement a real `ThemeEngine` where user settings override base tokens live:
207 +- **Color themes:** ship 8–12 gorgeous built-in themes (light & dark variants) + a **custom theme editor** (pick accent, background, chrome tint, toolbar color, active-tab color) with live preview; import/export themes as small JSON files.
208 +- **Backgrounds:** solid, gradient, or image/wallpaper behind the chrome / new-tab page; subtle translucency (`NSVisualEffectView`) toggles.
209 +- **Layout & chrome:** **tab bar position** (top horizontal OR left vertical sidebar like Arc), compact/comfortable **density**, show/hide toolbar elements, address bar centered vs. left, tab shape/rounding, separators on/off.
210 +- **Typography & display:** UI font choice and size; default web page zoom; per-site zoom memory; optional reader-mode typography controls (font, width, theme) for articles.
211 +- **New Tab / Start page:** fully customizable — background, greeting, favorites grid, quick AI ask box, recent history, widgets; user chooses what appears.
212 +- **Spaces/profiles:** multiple profiles (work/personal) each with their own theme, tabs, favorites, and data store.
213 +All customization is persisted per profile and applied without restart, at 60fps.
214 +
215 +### 4.3 — Core browser UI (exact spec)
216 +- **Window chrome:** unified toolbar — back/forward, reload/stop, the **AI omnibox** (rounded, accent-focus ring; shows security indicator, reader-mode button, AI-ask button, and a page-AI status glyph), profile switcher, extensions/downloads, new-tab (+), and an **AI panel toggle**. Respects the tab-bar-position setting (top or left).
217 +- **Tabs:** smooth open/close/reorder animations; drag to reorder and into groups; hover previews; audible-tab indicator; pinned tabs; suspended-tab dimming; middle-click close; keyboard tab switching.
218 +- **AI sidebar (right, collapsible ~360pt):** the chat-with-page surface — model chip (all Cloud models), streamed answers with page-section citations, quick-action buttons (Summarize, Key points, Translate, Ask selection), and a history of AI interactions for this tab/session.
219 +- **Selection floating toolbar:** appears on text selection in-page (Explain/Summarize/Translate/Rewrite/Ask), positioned near the selection, dismisses on click-away.
220 +- **Favorites (Bookmarks) manager:** dedicated view — folders, tags, drag-and-drop organization, full-text search, favicon grid or list, edit title/url/notes, import/export (HTML bookmarks). Bookmarks bar (toggleable) under the toolbar.
221 +- **History:** full-text searchable history view grouped by day/site, with filters, delete-range, and "ask AI about my history" (e.g., "find that article about X I read last week"). Clear-data controls per profile.
222 +- **Reading list & Reader mode:** clean, themeable reader view with AI summary at the top.
223 +- **Downloads:** toolbar popover with progress, reveal, and open.
224 +- **Empty/new-tab state:** a stunning customizable start page with a prominent AI ask box.
225 +
226 +### 4.4 — Motion & quality gate
227 +Family motion standard (smooth streaming, 150ms fades, 80ms hovers, `.snappy` popovers, 60fps, lazy rendering). Browser-specific: buttery tab animations, no jank while a page loads AND AI streams simultaneously, theme changes apply instantly. **Quality gate before done:** review every screen and state (loading, error page, no-network, private mode, AI streaming, AI consent prompt, long-page summarizing, empty favorites/history, custom theme applied, vertical vs. top tabs). If it looks "developer-made", iterate.
228 +
229 +---
230 +
231 +## PHASE 5 — APP ICON: ULTRA-LEGENDARY "ATLAS" ICON, DESIGNED IN SVG
232 +
233 +Designed in SVG first (`assets/icon/zyquo-atlas.svg`) → `.icns`. Visual sibling of Cloud, Local & Agent: same squircle, same Z-monogram DNA, same premium quality — telling the **browser / atlas / exploration** story.
234 +
235 +**Creative direction — the Z that explores.** Two directions (render both, keep the best):
236 +1. *Z-globe:* the bold "Z" monogram integrated with a minimal **globe / meridian** motif — thin latitude/longitude arcs curving behind or through the Z, suggesting the web and cartography; the Z's diagonal reads like a route across the globe.
237 +2. *Z-compass:* the Z centered within a refined **compass / atlas** mark — a subtle compass rose or orbiting ring, evoking navigation and discovery.
238 +
239 +- **Canvas:** Big Sur–style rounded **squircle** (Apple curvature).
240 +- **Palette (mirrors the app):** smooth vertical gradient blending **teal into indigo** (`#22C3B8 → #1FA9A0 → #4E63E0` territory, tune for depth — an explorer's teal-to-deep-indigo, like sea into sky), the Z and globe lines in white to near-white with subtle inner luminosity and one soft top light. Distinct from Cloud's sky-blue, Local's silicon-green, and Agent's violet, while unmistakably the same family: same squircle, same Z, same lighting, same finish.
241 +- **Precision & iteration:** clean paths, `viewBox="0 0 1024 1024"`, optical centering, thin arcs that survive downscaling (thicken or drop the finest meridians for 16/32px). Render 16→1024, inspect, refine.
242 +
243 +**Pipeline (Makefile):** SVG → PNGs (16→1024 incl. `@2x`) via `rsvg-convert` or a CoreGraphics rasterizer → `AppIcon.iconset``iconutil -c icns`. SVG stays as source of truth. Derive the monochrome **menu bar/toolbar template glyph** and the in-app wordmark from the same SVG.
244 +
245 +---
246 +
247 +## PHASE 6 — Features (This is where Zyquo Atlas becomes LEGENDARY)
248 +
249 +### Browser core
250 +- Fast multi-tab WKWebView browsing: tab groups/spaces, pinning, suspension, session restore, hover previews, drag-reorder
251 +- Smart AI omnibox (navigate / search / ask intent), security indicators, reader mode
252 +- Multiple **profiles** with isolated data, themes, favorites; private/incognito tabs (non-persistent data store)
253 +- Downloads, find-in-page, per-site zoom & settings, basic content-blocking hooks
254 +- Full **favorites** management (folders, tags, search, import/export, bookmarks bar) and **full-text history** (search, filters, ask-AI-about-history)
255 +
256 +### AI everywhere (all models from Zyquo Cloud)
257 +- AI answers in the omnibox with sources; per-tab **chat-with-page** with section citations
258 +- **Selection actions** (Explain/Summarize/Translate/Rewrite/Ask) anywhere on a page
259 +- **Summarize / TL;DR** any page incl. long-page map-reduce; **translate** page or selection
260 +- **AI writing assist** in web text fields; **multi-tab** summarize/compare
261 +- Opt-in auto-summaries and link hover-summaries; per-action default model selection (fast vs. strong)
262 +- Reused encrypted key vault (no Keychain); clear privacy indicators when content leaves the device
263 +
264 +### Massive customization (headline)
265 +- Theme engine: built-in themes + custom theme editor, backgrounds/wallpapers, translucency
266 +- Layout: top or left vertical tabs, density, chrome element toggles, tab shapes
267 +- Fully customizable new-tab/start page; UI font & size; per-profile persistence, live apply
268 +
269 +### Native polish & shortcuts
270 +- ⌘T new tab, ⌘W close tab, ⌘L focus omnibox, ⌘⇧A open AI sidebar, ⌘F find, ⌘D bookmark, ⌘Y history, ⌘⇧N private window, ⌘1–9 tab switch, ⌥Space Quick AI ask
271 +- Toggleable menu bar extra (quick AI ask / open Atlas); handoff as default browser
272 +
273 +---
274 +
275 +## PHASE 7 — VERIFICATION (MANDATORY)
276 +
277 +The user will provide **real API keys** (same providers as Zyquo Cloud). You MUST:
278 +
279 +1. **Browser correctness:** verify navigation, back/forward, tab lifecycle (open/suspend/restore/close), downloads, private-mode data isolation, profile switching, bookmark import/export, and full-text history search — on a set of real sites.
280 +2. **Content extraction quality:** on a suite of varied real pages (news article, docs page, blog, JS-heavy app, very long article, page with a user selection), verify `ContentExtractor` returns clean, correct main-content text and correct selection; verify chunking on long pages.
281 +3. **AI verification across ALL Cloud models:** for **every provider/model** in the shared catalog, run each core AI action (omnibox ask, summarize page, chat-with-page follow-up, selection explain/translate, rewrite in a text field, multi-tab compare) and confirm streaming works and answers are grounded in the extracted content. Produce a table: provider → model → action → ✅/❌ → notes. Fix every failure until green.
282 +4. **Privacy & cancellation:** confirm page content is sent only on user-invoked AI actions (or opt-in autos), the on-screen "content leaving device" indicator fires correctly, and navigating/Stop cancels in-flight AI requests.
283 +5. Never commit, log, or embed the user's keys or any browsing data; keys live only in the encrypted vault or env vars during testing.
284 +
285 +---
286 +
287 +## PHASE 8 — SIGNING & NOTARIZATION (REAL, NOT AD-HOC)
288 +
289 +The user has an existing, working signing/notarization setup for another project. **Before doing anything, read and inspect the folder:**
290 +
291 +```
292 +/Users/simon-pierreboucher/Desktop/other/OTHER/zyquo-term
293 +```
294 +
295 +Locate the **Developer ID Application identity name**, **Team ID**, **notarytool keychain profile (or Apple ID + app-specific password)**, entitlements, and any config there. **Reuse the exact same identity, Team ID, and notarytool credentials/profile for Zyquo Atlas.** Never invent placeholders, never print secrets, never commit them.
296 +
297 +Then implement `make release`:
298 +1. Build universal release (arm64 + x86_64, `lipo`), assemble `Zyquo Atlas.app`.
299 +2. `entitlements.plist` with **Hardened Runtime**; include what a WebKit browser needs — network client, and (if you adopt App Sandbox for a browser) the appropriate network-client + files/downloads entitlements; WebKit uses XPC/child processes, so verify the correct posture and test. Prefer the **minimal** set that lets WKWebView, downloads, and the app's own HTTPS API calls work; document the choice.
300 +3. `codesign --force --options runtime --timestamp --entitlements entitlements.plist --sign "Developer ID Application: <identity from zyquo-term>" "Zyquo Atlas.app"` — sign nested code (WebKit helper content, frameworks) first.
301 +4. `ditto -c -k --keepParent``xcrun notarytool submit "Zyquo Atlas.zip" --keychain-profile "<profile from zyquo-term>" --wait`.
302 +5. `xcrun stapler staple "Zyquo Atlas.app"`; verify `spctl -a -vv` = "accepted, source=Notarized Developer ID" and `stapler validate`.
303 +6. Optional signed+stapled DMG (`hdiutil`).
304 +7. On failure: `notarytool log`, fix (nested-code signing is the classic WebKit culprit), resubmit until it passes. Keep `make dev` (ad-hoc) for iteration.
305 +
306 +---
307 +
308 +## Engineering Standards
309 +
310 +- Swift 5.9+ (Swift 6 mode if the toolchain allows); zero warnings
311 +- `AIService` and network types as needed with structured concurrency; all provider and content types `Codable`
312 +- WKWebView work correctly off/on the main actor as required; never block the main thread during load or AI streaming; cancel AI on navigation
313 +- Robust, human-readable errors for every failure class (page failed to load, extraction failed on a hostile page, model/key missing, rate limited, network down); graceful error pages
314 +- Provider layer identical to Zyquo Cloud with ALL models; base design tokens + user ThemeEngine overrides; UI strings centralized
315 +- `README.md` (build) + `docs/` (AI-BROWSER-RESEARCH, PROVIDER-REUSE, PLAN); never commit secrets or browsing data
316 +- Commit in logical, phase-prefixed increments
317 +
318 +## Definition of Done
319 +
320 +- `make release` produces a **Developer ID–signed, notarized, stapled** `Zyquo Atlas.app` (verified by `spctl`), built without the Xcode IDE
321 +- A fast, stable multi-tab WKWebView browser with profiles, private mode, favorites, and full-text history — genuinely nicer to use than Safari
322 +- **AI everywhere** works: omnibox ask-with-sources, chat-with-page with citations, selection actions, summarize/translate, writing assist, multi-tab reasoning — all streaming, all grounded in extracted content, using **every provider/model from Zyquo Cloud** (Phase 7 table green)
323 +- The theming/customization engine delivers massive display & theme control (themes, backgrounds, top/left tabs, density, custom start page) applied live, per profile
324 +- Privacy model holds: page content leaves the device only on user-invoked (or opt-in) AI actions, with a clear indicator; keys in the reused encrypted vault (no Keychain)
325 +- The teal-indigo "atlas" SVG icon exists, is striking at all sizes, embedded as `.icns` + template glyph; clearly a sibling of the Cloud, Local, and Agent icons
326 +- The light theme matches the Phase 4 base spec and passes the design quality gate; dark theme derived and correct
327 +- Naming coherent everywhere: `Zyquo Atlas` user-facing, `com.zyquo.atlas`, `ZyquoAtlas` target/data folder
328 +- **Every code file starts with the mandatory Author/Mail header** (verified by a repo-wide sweep)
329 +- `docs/PLAN.md` shows every phase completed; `docs/AI-BROWSER-RESEARCH.md` and `docs/PROVIDER-REUSE.md` are complete and traceable to the implementation
330 +- Zyquo Atlas feels like a polished, legendary, AI-native macOS browser — it pulverizes Safari
added Makefile +99 −0
@@ -0,0 +1,99 @@
1 +#
2 +# Makefile
3 +# Zyquo Atlas
4 +#
5 +# Author: Simon-Pierre Boucher
6 +# Mail: contact@spboucher.ai
7 +#
8 +# make / make dev → release build, assemble dist/Zyquo Atlas.app, ad-hoc sign (fast local iteration)
9 +# make run → make dev, then launch the app
10 +# make release → universal binary, Developer ID sign, notarize, staple (Phase 8)
11 +# make icon → regenerate AppIcon.icns from assets/icon/zyquo-atlas.svg (Phase 5)
12 +# make verify → Phase 7 API verification with real keys (source .env.keys)
13 +# make test → swift test
14 +# make clean → remove build products
15 +#
16 +
17 +# CLT-only toolchain: the default SDK (macOS 27 beta) declares @State & co. as
18 +# macros whose SwiftUIMacros plugin ships only with Xcode, so every SwiftUI
19 +# build fails. SDK 26 keeps the property-wrapper forms — pin all builds to it.
20 +export SDKROOT := /Library/Developer/CommandLineTools/SDKs/MacOSX26.sdk
21 +
22 +APP_NAME := Zyquo Atlas
23 +EXEC_NAME := ZyquoAtlas
24 +BUNDLE_ID := com.zyquo.atlas
25 +VERSION := 1.0.0
26 +BUILD_NUM := 1
27 +MIN_MACOS := 13.0
28 +DIST := dist
29 +APP_DIR := $(DIST)/$(APP_NAME).app
30 +IDENTITY := Developer ID Application: Simon-Pierre Boucher (3YM54G49SN)
31 +NOTARY_PROFILE:= MacLustr-Notarize
32 +ENTITLEMENTS := Resources/ZyquoAtlas.entitlements
33 +VERIFY_ARGS ?=
34 +
35 +.PHONY: dev build bundle release universal icon test clean run verify
36 +
37 +dev: build bundle
38 + @echo "=== Ad-hoc signing (dev) ==="
39 + codesign --force --deep --sign - "$(APP_DIR)"
40 + codesign --verify --deep --strict "$(APP_DIR)"
41 + @echo "Packaged: $(APP_DIR) — launch with: open \"$(APP_DIR)\""
42 +
43 +build:
44 + swift build -c release
45 +
46 +test:
47 + scripts/test.sh
48 +
49 +run: dev
50 + open "$(APP_DIR)"
51 +
52 +bundle:
53 + @echo "=== Assembling $(APP_DIR) ==="
54 + rm -rf "$(APP_DIR)"
55 + mkdir -p "$(APP_DIR)/Contents/MacOS" "$(APP_DIR)/Contents/Resources"
56 + cp .build/release/$(EXEC_NAME) "$(APP_DIR)/Contents/MacOS/$(EXEC_NAME)"
57 + @for b in .build/release/*.bundle; do [ -e "$$b" ] && cp -R "$$b" "$(APP_DIR)/Contents/Resources/" || true; done
58 + @if [ -f Resources/AppIcon.icns ]; then cp Resources/AppIcon.icns "$(APP_DIR)/Contents/Resources/AppIcon.icns"; fi
59 + @for r in Resources/MenuBarIcon.png Resources/MenuBarIcon@2x.png; do [ -f "$$r" ] && cp "$$r" "$(APP_DIR)/Contents/Resources/" || true; done
60 + scripts/write-info-plist.sh "$(APP_DIR)" "$(APP_NAME)" "$(EXEC_NAME)" "$(BUNDLE_ID)" "$(VERSION)" "$(BUILD_NUM)" "$(MIN_MACOS)"
61 +
62 +# Both arch builds land in .build/out/Products/Release, so each slice is copied
63 +# aside before lipo. The -U flag allows the swiftCompatibility56 force-load
64 +# symbol (CLT ships it arm64-only; never referenced at runtime on macOS 13+).
65 +universal:
66 + @echo "=== Building universal binary (arm64 + x86_64) ==="
67 + mkdir -p .build/universal
68 + swift build -c release --arch arm64
69 + cp .build/out/Products/Release/$(EXEC_NAME) .build/universal/$(EXEC_NAME).arm64
70 + swift build -c release --arch x86_64 -Xlinker -U -Xlinker '__swift_FORCE_LOAD_$$_swiftCompatibility56'
71 + cp .build/out/Products/Release/$(EXEC_NAME) .build/universal/$(EXEC_NAME).x86_64
72 + lipo -create \
73 + .build/universal/$(EXEC_NAME).arm64 \
74 + .build/universal/$(EXEC_NAME).x86_64 \
75 + -output .build/universal/$(EXEC_NAME)
76 + lipo -archs .build/universal/$(EXEC_NAME)
77 +
78 +release: universal
79 + @echo "=== Assembling $(APP_DIR) (universal) ==="
80 + rm -rf "$(APP_DIR)"
81 + mkdir -p "$(APP_DIR)/Contents/MacOS" "$(APP_DIR)/Contents/Resources"
82 + cp .build/universal/$(EXEC_NAME) "$(APP_DIR)/Contents/MacOS/$(EXEC_NAME)"
83 + @for b in .build/out/Products/Release/*.bundle; do [ -e "$$b" ] && cp -R "$$b" "$(APP_DIR)/Contents/Resources/" || true; done
84 + @if [ -f Resources/AppIcon.icns ]; then cp Resources/AppIcon.icns "$(APP_DIR)/Contents/Resources/AppIcon.icns"; fi
85 + @for r in Resources/MenuBarIcon.png Resources/MenuBarIcon@2x.png; do [ -f "$$r" ] && cp "$$r" "$(APP_DIR)/Contents/Resources/" || true; done
86 + scripts/write-info-plist.sh "$(APP_DIR)" "$(APP_NAME)" "$(EXEC_NAME)" "$(BUNDLE_ID)" "$(VERSION)" "$(BUILD_NUM)" "$(MIN_MACOS)"
87 + scripts/notarize.sh "$(APP_DIR)" "$(IDENTITY)" "$(NOTARY_PROFILE)" "$(ENTITLEMENTS)"
88 +
89 +icon:
90 + scripts/generate-icon.sh
91 +
92 +# Full API verification with real keys (source .env.keys first, or let make do it).
93 +verify:
94 + swift build -c release
95 + @if [ -f .env.keys ]; then set -a && . ./.env.keys && set +a && .build/release/zyquo-verify $(VERIFY_ARGS); \
96 + else .build/release/zyquo-verify $(VERIFY_ARGS); fi
97 +
98 +clean:
99 + rm -rf .build $(DIST)
added Package.resolved +23 −0
@@ -0,0 +1,23 @@
1 +{
2 + "pins" : [
3 + {
4 + "identity" : "swift-cmark",
5 + "kind" : "remoteSourceControl",
6 + "location" : "https://github.com/swiftlang/swift-cmark.git",
7 + "state" : {
8 + "revision" : "924936d0427cb25a61169739a7660230bffa6ea6",
9 + "version" : "0.8.0"
10 + }
11 + },
12 + {
13 + "identity" : "swift-markdown",
14 + "kind" : "remoteSourceControl",
15 + "location" : "https://github.com/swiftlang/swift-markdown.git",
16 + "state" : {
17 + "revision" : "3c6f9523da3a1ec2fd829673e472d95b8097a3b8",
18 + "version" : "0.8.0"
19 + }
20 + }
21 + ],
22 + "version" : 2
23 +}
added Package.swift +39 −0
@@ -0,0 +1,39 @@
1 +// swift-tools-version:5.9
2 +//
3 +// Package.swift
4 +// Zyquo Atlas
5 +//
6 +// Author: Simon-Pierre Boucher
7 +// Mail: contact@spboucher.ai
8 +//
9 +
10 +import PackageDescription
11 +
12 +let package = Package(
13 + name: "ZyquoAtlas",
14 + platforms: [
15 + .macOS(.v13)
16 + ],
17 + dependencies: [
18 + .package(url: "https://github.com/swiftlang/swift-markdown.git", from: "0.5.0")
19 + ],
20 + targets: [
21 + .executableTarget(
22 + name: "ZyquoAtlas",
23 + dependencies: [
24 + .product(name: "Markdown", package: "swift-markdown")
25 + ],
26 + path: "Sources/ZyquoAtlas"
27 + ),
28 + .executableTarget(
29 + name: "zyquo-verify",
30 + dependencies: [],
31 + path: "Sources/ZyquoVerify"
32 + ),
33 + .testTarget(
34 + name: "ZyquoAtlasTests",
35 + dependencies: ["ZyquoAtlas"],
36 + path: "Tests/ZyquoAtlasTests"
37 + ),
38 + ]
39 +)
added README.md +45 −0
@@ -0,0 +1,45 @@
1 +<!--
2 + README.md
3 + Zyquo Atlas
4 + Author: Simon-Pierre Boucher
5 + Mail: contact@spboucher.ai
6 +-->
7 +
8 +# Zyquo Atlas
9 +
10 +A legendary, native macOS **web browser** written in Swift + SwiftUI on WebKit
11 +(`WKWebView`), built **without the Xcode IDE** (Swift Package Manager + the
12 +command-line toolchain). Part of the **Zyquo** family. AI is woven into every
13 +surface, powered by the same providers/models and encrypted key vault as
14 +**Zyquo Cloud**.
15 +
16 +## Build
17 +
18 +```sh
19 +make dev # release build → dist/Zyquo Atlas.app, ad-hoc signed (local iteration)
20 +make run # make dev, then launch the app
21 +make test # run the test suite (Command Line Tools only)
22 +make release # universal, Developer ID signed, notarized, stapled (Phase 8)
23 +make verify # Phase 7 API verification with real keys (source .env.keys)
24 +make clean
25 +```
26 +
27 +### Toolchain note
28 +
29 +The Command Line Tools' default SDK (macOS 27 beta) declares SwiftUI's `@State`
30 +& co. as macros whose `SwiftUIMacros` plugin ships only with Xcode, so every
31 +SwiftUI build fails against it. All builds therefore pin
32 +`SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX26.sdk` (set in the
33 +`Makefile`). Build directly with `swift build -c release` only if you export the
34 +same `SDKROOT`.
35 +
36 +## Layout
37 +
38 +- `Sources/ZyquoAtlas/` — the app (App, DesignSystem, Models, Browser, Content,
39 + AI, Providers, Features, Services, ViewModels, Views).
40 +- `Sources/ZyquoVerify/` — thin launcher that execs the app's `--verify` harness.
41 +- `docs/``PLAN.md` (phase progress), `AI-BROWSER-RESEARCH.md` (Phase 0.A),
42 + `PROVIDER-REUSE.md` (Phase 0.B).
43 +- `Resources/`, `scripts/`, `assets/` — bundle resources, build scripts, icon source.
44 +
45 +Requires macOS 13.0+.
added Resources/ZyquoAtlas.entitlements +22 −0
@@ -0,0 +1,22 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<!--
4 + ZyquoAtlas.entitlements
5 + Zyquo Atlas
6 +
7 + Author: Simon-Pierre Boucher
8 + Mail: contact@spboucher.ai
9 +
10 + Phase 8 finalizes the Hardened Runtime posture. A WKWebView browser uses
11 + WebKit XPC/child processes; the minimal set that lets WKWebView, downloads,
12 + and the app's own HTTPS API calls work is chosen and validated in Phase 8.
13 + Not App-Sandboxed in v1 (Developer ID distribution, not Mac App Store).
14 +-->
15 +<plist version="1.0">
16 +<dict>
17 + <key>com.apple.security.cs.allow-jit</key>
18 + <true/>
19 + <key>com.apple.security.network.client</key>
20 + <true/>
21 +</dict>
22 +</plist>
added Sources/ZyquoAtlas/App/Main.swift +34 −0
@@ -0,0 +1,34 @@
1 +//
2 +// Main.swift
3 +// Zyquo Atlas
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +// Entry point. `--verify` runs the Phase 7 API harness headlessly (reusing the
9 +// production provider clients ported from Zyquo Cloud); otherwise the SwiftUI
10 +// app launches.
11 +//
12 +// Deliberately a synchronous main: launching NSApplicationMain from an async
13 +// main() corrupts Swift concurrency's executor setup (background tasks stop
14 +// being scheduled), so CLI modes drive their async work explicitly.
15 +//
16 +
17 +import Foundation
18 +
19 +@main
20 +enum Main {
21 + static func main() {
22 + let arguments = CommandLine.arguments
23 + if arguments.contains("--verify") {
24 + Task.detached {
25 + let status = await VerifyHarness.run(arguments: arguments)
26 + exit(status)
27 + }
28 + // Park the main thread servicing the main queue so MainActor work
29 + // can run (a blocking semaphore here would deadlock the harness).
30 + dispatchMain()
31 + }
32 + ZyquoAtlasApp.main()
33 + }
34 +}
added Sources/ZyquoAtlas/App/ZyquoAtlasApp.swift +40 −0
@@ -0,0 +1,40 @@
1 +//
2 +// ZyquoAtlasApp.swift
3 +// Zyquo Atlas
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +// The SwiftUI @main scene. Phase 1 stands up a single launchable window and
9 +// proper activation from a terminal launch; Phase 2 replaces the placeholder
10 +// root with the real browser window (tabs, omnibox, WKWebView).
11 +//
12 +
13 +import SwiftUI
14 +import AppKit
15 +
16 +struct ZyquoAtlasApp: App {
17 + @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
18 +
19 + var body: some Scene {
20 + WindowGroup("Zyquo Atlas") {
21 + RootPlaceholderView()
22 + .frame(minWidth: 900, minHeight: 600)
23 + }
24 + .windowStyle(.hiddenTitleBar)
25 + .windowToolbarStyle(.unified)
26 + }
27 +}
28 +
29 +/// Ensures a terminal-launched (non-bundle) process activates and shows its
30 +/// window as a regular app rather than a background agent.
31 +final class AppDelegate: NSObject, NSApplicationDelegate {
32 + func applicationDidFinishLaunching(_ notification: Notification) {
33 + NSApp.setActivationPolicy(.regular)
34 + NSApp.activate(ignoringOtherApps: true)
35 + }
36 +
37 + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
38 + true
39 + }
40 +}
added Sources/ZyquoAtlas/Verify/VerifyHarness.swift +25 −0
@@ -0,0 +1,25 @@
1 +//
2 +// VerifyHarness.swift
3 +// Zyquo Atlas
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +// Phase 7 API verification harness. Placeholder in Phase 1 — it becomes real
9 +// once the provider layer is ported from Zyquo Cloud (Phase 2/3) and the
10 +// browser AI actions exist (Phase 3), at which point it exercises the exact
11 +// production clients against live APIs with real keys (see docs/PROVIDER-REUSE.md
12 +// §6 and docs/AI-BROWSER-RESEARCH.md §8). Keys come from environment variables
13 +// (source .env.keys); they are never logged or persisted here.
14 +//
15 +
16 +import Foundation
17 +
18 +enum VerifyHarness {
19 + static func run(arguments: [String]) async -> Int32 {
20 + FileHandle.standardError.write(Data(
21 + "Zyquo Atlas verification harness is not yet implemented (Phase 7).\n".utf8
22 + ))
23 + return 0
24 + }
25 +}
added Sources/ZyquoAtlas/Views/RootPlaceholderView.swift +34 −0
@@ -0,0 +1,34 @@
1 +//
2 +// RootPlaceholderView.swift
3 +// Zyquo Atlas
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +// Phase 1 placeholder root. Confirms the app builds, launches, and renders a
9 +// window. Replaced in Phase 2 by the real browser window (BrowserWindowView).
10 +//
11 +
12 +import SwiftUI
13 +
14 +struct RootPlaceholderView: View {
15 + var body: some View {
16 + ZStack {
17 + LinearGradient(
18 + colors: [Color(red: 0.13, green: 0.66, blue: 0.63),
19 + Color(red: 0.31, green: 0.39, blue: 0.88)],
20 + startPoint: .top, endPoint: .bottom
21 + )
22 + .ignoresSafeArea()
23 +
24 + VStack(spacing: 12) {
25 + Text("Zyquo Atlas")
26 + .font(.system(size: 40, weight: .bold, design: .rounded))
27 + .foregroundStyle(.white)
28 + Text("AI-native macOS browser — Phase 1 scaffold")
29 + .font(.system(size: 14, weight: .medium))
30 + .foregroundStyle(.white.opacity(0.85))
31 + }
32 + }
33 + }
34 +}
added Sources/ZyquoVerify/main.swift +31 −0
@@ -0,0 +1,31 @@
1 +//
2 +// main.swift
3 +// Zyquo Atlas
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +// zyquo-verify — thin launcher for the Phase 7 harness. The harness itself
9 +// lives inside the ZyquoAtlas binary (`--verify`) so it exercises the exact
10 +// production provider clients; this target execs the sibling binary.
11 +//
12 +
13 +import Foundation
14 +
15 +let selfURL = URL(fileURLWithPath: CommandLine.arguments[0]).resolvingSymlinksInPath()
16 +let appBinary = selfURL.deletingLastPathComponent().appendingPathComponent("ZyquoAtlas")
17 +
18 +guard FileManager.default.isExecutableFile(atPath: appBinary.path) else {
19 + FileHandle.standardError.write(Data(
20 + "error: ZyquoAtlas binary not found next to zyquo-verify (build with `swift build`)\n".utf8
21 + ))
22 + exit(1)
23 +}
24 +
25 +let process = Process()
26 +process.executableURL = appBinary
27 +process.arguments = ["--verify"] + CommandLine.arguments.dropFirst()
28 +process.environment = ProcessInfo.processInfo.environment
29 +try process.run()
30 +process.waitUntilExit()
31 +exit(process.terminationStatus)
added Tests/ZyquoAtlasTests/SmokeTests.swift +22 −0
@@ -0,0 +1,22 @@
1 +//
2 +// SmokeTests.swift
3 +// Zyquo Atlas
4 +//
5 +// Author: Simon-Pierre Boucher
6 +// Mail: contact@spboucher.ai
7 +//
8 +// Phase 1 smoke test — proves the test target links against ZyquoAtlas.
9 +// Real coverage (SSE parser, SecureKeyStore, ContentExtractor) arrives with
10 +// the ported provider layer and content pipeline in later phases.
11 +//
12 +
13 +import Foundation
14 +import Testing
15 +@testable import ZyquoAtlas
16 +
17 +@Suite struct SmokeTests {
18 + @Test func harnessPlaceholderSucceeds() async {
19 + let status = await VerifyHarness.run(arguments: ["--verify"])
20 + #expect(status == 0)
21 + }
22 +}
modified docs/PLAN.md +20 −0
@@ -52,3 +52,23 @@ provider layer, 170-model catalog, and AES-256-GCM vault to a verbatim/adapt por
52 52 GeminiClient — Gemini uses the OpenAI-compat endpoint). Key decisions: Atlas is read-oriented
53 53 (not agentic); BYO-key + all Cloud models is the differentiator; extraction quality is the
54 54 product. Toolchain pinned to SDK 26.5. **Phase 0 gate PASSED.**
55 +
56 +## Phase 1 — Project Setup (No Xcode IDE) — COMPLETE
57 +
58 +- [x] `Package.swift` — executable target `ZyquoAtlas` (Foundation/SwiftUI/WebKit/CryptoKit + swift-markdown), `zyquo-verify` launcher target, `ZyquoAtlasTests` (swift-testing)
59 +- [x] `Makefile` — SDKROOT pinned to MacOSX26.sdk; `dev`/`build`/`bundle`/`run`/`universal`/`release`/`icon`/`verify`/`test`/`clean`
60 +- [x] `scripts/write-info-plist.sh` — browser Info.plist: `CFBundleURLTypes` http/https, `NSUserActivityTypeBrowsingWeb`, ATS `NSAllowsArbitraryLoadsInWebContent` (web content only; app API calls stay HTTPS), productivity category
61 +- [x] `Resources/ZyquoAtlas.entitlements` — Hardened-Runtime-ready draft (network client + allow-jit; finalized Phase 8)
62 +- [x] `scripts/test.sh` — CLT-only test runner (symlinks Testing.framework)
63 +- [x] `@main` `Main.swift` (sync main, `--verify` hook) + `ZyquoAtlasApp.swift` (SwiftUI App, NSApplicationDelegate activation) + `RootPlaceholderView`
64 +- [x] Clean release build (24s, zero warnings), `make dev` assembles + ad-hoc signs `Zyquo Atlas.app`, launches and renders a window (verified by screenshot: teal→indigo gradient, "Zyquo Atlas", hidden title bar)
65 +- [x] `swift test` green (1 suite); header sweep passes on all code files; `plutil -lint` OK
66 +- [x] `README.md` build docs
67 +
68 +**Phase 1 summary (2026-07-30):** SPM project builds and launches as `Zyquo Atlas.app` without Xcode.
69 +Toolchain pinned to SDK 26 in the Makefile (SDK 27's SwiftUI macros need Xcode). Browser Info.plist
70 +registers http/https URL schemes + browsing-web activity and sets the correct ATS posture (arbitrary
71 +loads only inside WKWebView content). `@main` uses a synchronous entry with a `--verify` hook so the
72 +Phase 7 harness can run headlessly on the ported provider clients. Verify/test targets and a CLT-only
73 +test runner are wired. All files carry the mandatory header. **Phase 1 gate PASSED** (buildable,
74 +launchable, single window; browser core is Phase 2).
added scripts/test.sh +36 −0
@@ -0,0 +1,36 @@
1 +#!/bin/bash
2 +#
3 +# test.sh
4 +# Zyquo Atlas
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Mail: contact@spboucher.ai
8 +#
9 +# Runs the test suite. Works with Command Line Tools only (no Xcode): CLT's
10 +# Testing.framework isn't on the test bundle's runtime search path, so it is
11 +# symlinked into the build products dir before running.
12 +#
13 +set -euo pipefail
14 +cd "$(dirname "$0")/.."
15 +
16 +CLT="/Library/Developer/CommandLineTools"
17 +# See Makefile: the default SDK's SwiftUI macros need Xcode; pin to SDK 26.
18 +export SDKROOT="$CLT/SDKs/MacOSX26.sdk"
19 +CLT_FRAMEWORKS="$CLT/Library/Developer/Frameworks"
20 +TESTING_PLUGINS="$CLT/usr/lib/swift/host/plugins/testing"
21 +
22 +swift build --build-tests -Xswiftc -plugin-path -Xswiftc "$TESTING_PLUGINS"
23 +
24 +for products in .build/out/Products/Debug .build/debug; do
25 + if [ -d "$products" ]; then
26 + mkdir -p "$products/PackageFrameworks"
27 + for fw in "$CLT_FRAMEWORKS"/*.framework; do
28 + name="$(basename "$fw")"
29 + ln -sfn "$fw" "$products/PackageFrameworks/$name"
30 + done
31 + ln -sfn "$CLT/Library/Developer/usr/lib/lib_TestingInterop.dylib" \
32 + "$products/PackageFrameworks/lib_TestingInterop.dylib"
33 + fi
34 +done
35 +
36 +swift test --skip-build "$@"
added scripts/write-info-plist.sh +86 −0
@@ -0,0 +1,86 @@
1 +#!/bin/bash
2 +#
3 +# write-info-plist.sh
4 +# Zyquo Atlas
5 +#
6 +# Author: Simon-Pierre Boucher
7 +# Mail: contact@spboucher.ai
8 +#
9 +# Writes Contents/Info.plist into an assembled Zyquo Atlas.app bundle.
10 +# Usage: write-info-plist.sh <app-dir> <app-name> <exec-name> <bundle-id> <version> <build> <min-macos>
11 +#
12 +# ATS posture for a browser: WKWebView loads arbitrary sites (incl. HTTP), so
13 +# NSAllowsArbitraryLoadsInWebContent=true opens ONLY the WKWebView content
14 +# surface — the app's own provider/API calls stay HTTPS-only (no blanket
15 +# NSAllowsArbitraryLoads). Registered as a candidate default browser via
16 +# CFBundleURLTypes (http/https) so macOS can offer Zyquo Atlas as a default.
17 +#
18 +set -euo pipefail
19 +
20 +APP_DIR="$1"; APP_NAME="$2"; EXEC_NAME="$3"; BUNDLE_ID="$4"; VERSION="$5"; BUILD_NUM="$6"; MIN_MACOS="$7"
21 +
22 +cat > "$APP_DIR/Contents/Info.plist" << PLIST
23 +<?xml version="1.0" encoding="UTF-8"?>
24 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
25 +<plist version="1.0">
26 +<dict>
27 + <key>CFBundleName</key>
28 + <string>${APP_NAME}</string>
29 + <key>CFBundleDisplayName</key>
30 + <string>${APP_NAME}</string>
31 + <key>CFBundleIdentifier</key>
32 + <string>${BUNDLE_ID}</string>
33 + <key>CFBundleShortVersionString</key>
34 + <string>${VERSION}</string>
35 + <key>CFBundleVersion</key>
36 + <string>${BUILD_NUM}</string>
37 + <key>CFBundleExecutable</key>
38 + <string>${EXEC_NAME}</string>
39 + <key>CFBundlePackageType</key>
40 + <string>APPL</string>
41 + <key>CFBundleIconFile</key>
42 + <string>AppIcon</string>
43 + <key>CFBundleInfoDictionaryVersion</key>
44 + <string>6.0</string>
45 + <key>LSMinimumSystemVersion</key>
46 + <string>${MIN_MACOS}</string>
47 + <key>NSHighResolutionCapable</key>
48 + <true/>
49 + <key>NSPrincipalClass</key>
50 + <string>NSApplication</string>
51 + <key>LSApplicationCategoryType</key>
52 + <string>public.app-category.productivity</string>
53 + <key>NSHumanReadableCopyright</key>
54 + <string>© 2026 Simon-Pierre Boucher. All rights reserved.</string>
55 + <key>NSSupportsAutomaticTermination</key>
56 + <false/>
57 + <key>NSSupportsSuddenTermination</key>
58 + <false/>
59 + <key>CFBundleURLTypes</key>
60 + <array>
61 + <dict>
62 + <key>CFBundleURLName</key>
63 + <string>Web site URL</string>
64 + <key>CFBundleTypeRole</key>
65 + <string>Viewer</string>
66 + <key>CFBundleURLSchemes</key>
67 + <array>
68 + <string>http</string>
69 + <string>https</string>
70 + </array>
71 + </dict>
72 + </array>
73 + <key>NSUserActivityTypes</key>
74 + <array>
75 + <string>NSUserActivityTypeBrowsingWeb</string>
76 + </array>
77 + <key>NSAppTransportSecurity</key>
78 + <dict>
79 + <key>NSAllowsArbitraryLoadsInWebContent</key>
80 + <true/>
81 + </dict>
82 +</dict>
83 +</plist>
84 +PLIST
85 +
86 +echo "Info.plist written to $APP_DIR/Contents/Info.plist"
87