Files
linkding-ios/openwiki/quickstart.md
Krishna Kumar f7735431a8
All checks were successful
CI / build-and-deploy (push) Successful in 16s
Update OpenWiki for source ingest
2026-07-02 01:20:18 -05:00

8.2 KiB

Marks OpenWiki Quickstart

Marks is a native SwiftUI iOS client for linkding, a self-hosted bookmark manager. The app targets iOS 26 and Swift 6, and includes a main app, share extension, widget extension, App Intents, AI-assisted bookmark features, local source ingest, and podcast generation/playback.

Start here when changing the repository, then follow the page links below for the area you are touching.

What this repository contains

  • Main iOS app in /Marks with SwiftUI tabs for bookmarks, tags, sources, podcasts, and search. The entrypoint is /Marks/MarksApp.swift.
  • Models in /Marks/Models, centered on Bookmark, linkding response/create/update payloads, tags, smart collections, ServerConfig, URL ingest payloads, and locally ingested sources.
  • Services in /Marks/Services for linkding networking, AI/backend calls, auth, on-device bookmark Q&A, Spotlight indexing, source storage, widget/podcast data, analytics, and logging.
  • Views in /Marks/Views for the primary product surfaces. BookmarksViewModel is the central app state object.
  • App Intents in /Marks/Intents for opening, searching, adding, listing unread, and summarizing bookmarks.
  • Share extension in /ShareExtension for extracting URLs from shared URLs, text, HTML, and RTF, saving to linkding, and queueing podcast generation.
  • Widget extension in /MarksWidget for recent bookmarks, random bookmark, and recent podcast widgets.
  • Tests in /MarksTests, currently focused on App Intents plus ingest parser/source-store coverage.
  • XcodeGen project spec in /project.yml; Marks.xcodeproj is generated/checked in but project.yml is the project definition to inspect first.
  • Design notes in /docs/design-wwdc26.md for iOS 26/Liquid Glass, search, widgets, and row-design guidance.

Major documentation pages

  • Architecture notes — target layout, state flow, networking, persistence, AI, Spotlight, extensions, widgets, and App Intents.
  • Product workflows — how bookmark browsing, saving, AI enrichment, Ask, smart collections, podcasts, widgets, and intents behave.
  • Development and testing — setup/build/test commands, generated project guidance, storage/config map, verification checklist, and caveats.

Build and run

The README documents the intended local setup:

brew install xcodegen
xcodegen generate
open Marks.xcodeproj

Then build and run from Xcode using the Marks scheme. /project.yml defines Swift 6.0, iOS 26.0 deployment target, the Marks, ShareExtension, MarksWidget, and MarksTests targets, and the app-group entitlements used by all app surfaces.

Useful checks before shipping a change:

xcodegen generate
xcodebuild test -scheme Marks -destination 'platform=iOS Simulator,name=iPhone 16'

Adjust the simulator name to what is installed locally.

Runtime architecture in one minute

At launch, MarksApp loads a ServerConfig, constructs LinkdingAPI, and stores a shared BookmarksViewModel in MainContainer so it survives SwiftUI re-renders (/Marks/MarksApp.swift, /Marks/Views/BookmarksViewModel.swift). The top-level TabView has Bookmarks, Tags, Sources, Podcasts, and Search tabs.

BookmarksViewModel fetches paginated bookmarks from linkding through LinkdingAPI, restores local AI metadata, caches bookmarks to Application Support, writes recent bookmark metadata for widgets, and indexes bookmarks into Spotlight. It also owns ClaudeService, PodcastPlayerViewModel, and PodcastGenerationManager, so AI, podcast, search, and list state are shared across tabs. MainContainer separately owns IngestedSourceLibrary for the Sources tab.

Local sources are stored in Application Support under Sources/: sources.json stores metadata, Sources/files/ stores imported files, PDF text is extracted with PDFKit, and sources are indexed into Spotlight through SourceSpotlightIndexer.

Extensions and widgets use the shared app group group.com.magicive.marks. ServerConfig.save() writes to standard defaults and the app-group defaults; WidgetDataStore writes app-group JSON files for widgets; PodcastRequests uses app-group defaults to hand podcast requests from the share extension to the main app.

External systems and privacy boundaries

  • linkding is the source of truth for bookmarks and tags. LinkdingAPI uses token auth and calls linkding bookmark, check, tag, create, update, delete, archive, and connection-test endpoints.
  • Marks backend is used by MarksAuth/ClaudeService for AI enrichment, semantic search, smart collections, analytics events, and podcast generation/audio download.
  • Apple on-device intelligence and Spotlight power the in-app Ask surface via FoundationModels, CoreSpotlight, and the BookmarkSearchTool retrieval path. Spotlight is also used for locally ingested sources.
  • WidgetKit, App Intents, AVFoundation, and MediaPlayer support widgets, Siri/Shortcuts integration, podcast playback, background audio, now-playing metadata, and remote controls.

Do not document or expose secret values. /Marks/MarksApp.swift currently contains a built-in default server configuration with a token-like value; treat it as sensitive source material and avoid copying it into docs, logs, screenshots, or tests.

Important caveats for future agents

  • The README says optional AI features use OpenRouter/Gemini directly. Current source routes backend AI/podcast calls through MarksAuth + ClaudeService; the in-app Ask feature is on-device via FoundationModels. Prefer source evidence when changing AI behavior.
  • OnboardingView exists, but current launch flow uses saved-or-default config directly. Do not assume onboarding is active without changing /Marks/MarksApp.swift.
  • Settings' disconnect callback currently resets to the built-in default config path rather than forcing onboarding. Confirm intended product behavior before changing account/config flows.
  • BookmarksViewModel is shared across tabs, so changes to bookmark arrays, filters, search, enrichment, and pagination can affect Bookmarks, Tags, Search, Podcasts, widgets, and Spotlight indexing.
  • Share-extension podcast requests are queued in shared defaults and drained by the main app on launch/foreground. Be careful with crash/retry semantics when touching that flow.
  • Local source podcasts use marks-source://{uuid} pseudo-URLs plus extracted text sent to ClaudeService.generatePodcast(...). The backend must accept text and source_kind for non-web podcast generation.
  • Existing automated tests cover App Intents plus focused ingest parser/source-store behavior. For UI, networking, sync, share extension, widgets, and podcasts, add tests where feasible and perform manual verification.

Where to start for common changes

  • Bookmark list, pagination, search, tags, enrichment state: /Marks/Views/BookmarksViewModel.swift, /Marks/Views/BookmarksView.swift, /Marks/Services/LinkdingAPI.swift.
  • Linkding API changes: /Marks/Services/LinkdingAPI.swift, /Marks/Models/Bookmark.swift, /ShareExtension/ShareView.swift, /Marks/Intents/IntentSupport.swift.
  • AI/backend changes: /Marks/Services/ClaudeService.swift, /Marks/Services/MarksAuth.swift, /Marks/Services/BookmarkAssistant.swift, /Marks/Services/BookmarkSearchTool.swift.
  • Source ingest and local documents: /Marks/Views/SourcesView.swift, /Marks/Models/IngestedSource.swift, /Marks/Services/IngestedSourceStore.swift, /Marks/Services/SourceSpotlightIndexer.swift.
  • Podcast generation/playback: /Marks/Services/PodcastGenerationManager.swift, /Marks/Services/PodcastIndex.swift, /Marks/Views/PodcastPlayerView.swift, /Marks/Views/BookmarksViewModel.swift, /Marks/Views/SourcesView.swift.
  • Share extension and text/link extraction: /Marks/Models/IngestPayload.swift, /ShareExtension/ShareViewController.swift, /ShareExtension/ShareView.swift, /ShareExtension/TagSuggester.swift, plus shared files declared in /project.yml.
  • Widgets/deep links: /MarksWidget/WidgetDataStore.swift, /MarksWidget/*Widget.swift, /Marks/MarksApp.swift.
  • App Intents/Siri/Shortcuts: /Marks/Intents/*, /MarksTests/AppIntentsTests.swift.