A native macOS client for InterlinedList — built with Swift 6, SwiftUI, and SwiftData.
InterlinedList for macOS mirrors every capability of the InterlinedList web app, organized as native macOS features: a timeline, a composer window, structured lists with a schema DSL, an offline-capable Markdown document store, social and organization features, notifications, and Settings — all backed by the documented InterlinedList API.
The project is greenfield. Scope, architecture, milestones, and branding are pinned in PLAN.md; orchestration rules live in ORCHESTRATION.md. Progress is recorded in docs/progress.md and endpoint coverage in docs/api-coverage.md.
| Milestone | Scope | Status |
|---|---|---|
| M0 — Foundation | Xcode project, three SPM packages, CI, auth, Keychain, brand assets | Shipped |
| M1 — Read-only core | Timeline (all/mine/tag), threads, public list browsing, profile header | Shipped |
| M2 — Posting | Composer (⌘N), replies, digs, reposts, edit/delete own messages | Shipped |
| M3 — Lists | CRUD, schema DSL editor, rows table, nesting, connections graph, watchers, GitHub refresh | Shipped |
| M4 — Documents | Folder tree, Markdown editor/preview, image upload, delta sync engine | Shipped |
| M5 — Social & notifications | Follow/unfollow, requests, mutuals, notifications tray, dock badge | Shipped |
| M6 — Subscriber & orgs | Media attachments, scheduled posts, cross-posting, OAuth linking, organizations | Shipped |
| M7 — Ship | CSV exports, Settings polish, sandbox + notarization, Sparkle, accessibility, brand QA | Pending |
Endpoint coverage today: 97 / 98 implemented, 66 / 98 fully tested, 25 / 98 partial. See docs/api-coverage.md for the row-by-row matrix.
InterlinedList.xcodeproj
App/ # App target (UI only)
Composition/ # AppEnvironment composition root
Features/ # Timeline, Compose, Lists, Documents, Social, Orgs, Notifications, Settings, Onboarding
MenuCommands/ # ⌘N etc.
Navigation/ # Sidebar, deep-link routing
Resources/ # Asset catalog, fonts, Info.plist, entitlements
Packages/
InterlinedKit/ # API layer: APIClient, Endpoints, DTOs, Auth, Pagination, Errors
InterlinedDomain/ # Business logic: Models + Services on top of InterlinedKit protocols
InterlinedPersistence/ # SwiftData schemas, cache policy, document sync engine
AppTests/ # App-target XCTest (BDD-named)
docs/ # progress, api-coverage, decisions, spikes, user guides
See PLAN.md §3 for the rules at each boundary — in particular the kit-import policy from Decision 0003: the App target imports InterlinedKit only from the composition root.
Requirements:
- macOS 15 (Sequoia) or later (see Decision 0004)
- Xcode 16.2 / Swift 6.0.3
Build and test:
# All three SPM packages
swift test --package-path Packages/InterlinedKit
swift test --package-path Packages/InterlinedDomain
swift test --package-path Packages/InterlinedPersistence
# App target (incl. AppTests)
xcodebuild test \
-project InterlinedList.xcodeproj \
-scheme InterlinedList \
-destination 'platform=macOS'CI runs the same steps on every push and pull request (.github/workflows/ci.yml) and uploads the unsigned .app bundle as a workflow artifact.
The env-gated contract suite in InterlinedKitTests hits the real API. To run it locally, export credentials before invoking swift test:
export INTERLINEDLIST_EMAIL="you@example.com"
export INTERLINEDLIST_PASSWORD="..."
swift test --package-path Packages/InterlinedKitThe CI workflow does not run contract tests. Credentials must never be committed.
- PLAN.md — product scope, architecture, milestones, branding (authoritative).
- ORCHESTRATION.md — how work is sequenced and how agents own paths.
- docs/progress.md — running log of waves, gates, deviations.
- docs/api-coverage.md — endpoint matrix.
- docs/decisions/ — recorded architecture decisions.
- docs/spikes/ — investigations and probes against the live API.
- docs/user/ — end-user guides.
All visual identity follows the official InterlinedList branding standards. The product name is InterlinedList — capital I, capital L, no spaces or hyphens. See PLAN.md §9 for the palette, typography, and asset rules used throughout the app.