A local-first macOS writing assistant built around a Review Workbench — an explicit, document-centric review and rewrite workflow.
Architecture direction: WriteAssist has pivoted from a system-wide ambient monitor to a review-first, local-first workbench. See
tasks/prd-writeassist-review-workbench.mdfor the current product requirements.
- Review Workbench — paste or import text into a dedicated window; run a local spell/grammar/style check; inspect issues by paragraph and sentence; apply deterministic fixes locally.
- Explicit AI rewrites — select a sentence or paragraph, choose a rewrite mode (Fix Grammar, Natural, Shorter, Formal), and request a rewrite via Ollama (local) or a configured cloud provider.
- Review Selection — one-shot import of selected text from any app via Accessibility API; opens a lightweight review panel first, with the full workspace available when you want deeper editing or rewrites.
- Local-first — all passive checks are on-device; cloud AI is invoked only on explicit user request.
- Loopback-only Ollama — local model traffic is restricted to
localhost/ loopback.
| Requirement | Minimum |
|---|---|
| macOS | 15 Sequoia |
| Swift toolchain | 6.0 (Xcode 16+) |
| Accessibility permission | Required for Review Selection — see Granting Accessibility Access |
No external package dependencies. The project uses Swift Package Manager with a core library target plus a thin app target.
git clone <repo-url> && cd WriteAssist
swift build
swift run- Open the
WriteAssistdirectory in Xcode. - Let Xcode resolve
Package.swift. - Select the
WriteAssistscheme and run.
Because the app uses .accessory activation policy, it does not appear in the Dock. Look for the pencil icon in the menu bar after launch.
WriteAssist needs Accessibility access for the Review Selection feature, which imports selected text from the focused application.
- Launch the app from
swift runor Xcode. - Open System Settings → Privacy & Security → Accessibility.
- Enable WriteAssist (or the Swift toolchain binary when using
swift run).
- The menu bar launcher provides four actions: Review Selection, Open Workspace, Settings, Quit.
- Review Selection is the primary path. It imports the current selection from the focused app via AX, opens a lightweight review panel, and can also be triggered globally with ⌃⌥⌘R.
- Open Workspace opens the full Review Workbench window directly.
- The review panel shows a quick, compact issue summary near your current context without forcing a document window.
- Inside the workbench, DeterministicReviewEngine runs a local spell + grammar + style pipeline.
- ReviewGrouping organises results by paragraph and sentence.
- ReviewSessionStore owns the document, analysis lifecycle, selection state, and the single local mutation path.
- LocalFirstRewriteEngine rewrites selected text via Ollama first, with optional cloud fallback.
- Spelling, grammar, and style checks stay on-device.
- Text is sent to the configured AI provider only when you explicitly request an AI rewrite.
- API keys for Anthropic and OpenAI are stored in macOS Keychain.
- Cloud AI traffic uses TLS certificate pinning for supported providers.
- Ollama traffic is allowed only to loopback addresses.
- The app suppresses AX inspection for secure input contexts such as password fields.
- Personal dictionary entries, ignore rules, provider/model preferences, and writing stats are stored locally in
UserDefaults.
WriteAssist/
├── Sources/
│ ├── App/ # AppShellController, AppMode, app entry point
│ ├── ReviewDomain/ # ReviewDocument, ReviewAnalysisSnapshot, ReviewSessionStore
│ ├── ReviewServices/ # DeterministicReviewEngine, ReviewGrouping
│ ├── ReviewWindow/ # ReviewWorkbenchView, editor, sidebar, inspector, rewrite UI
│ ├── Rewrite/ # RewriteSessionStore, LocalFirstRewriteEngine, contracts
│ ├── SystemIntegration/ # SelectionImportService (one-shot AX import)
│ ├── SpellCheckService.swift
│ ├── NLAnalysisService.swift
│ ├── RuleEngine.swift
│ ├── WritingRules/ # individual rule implementations
│ └── [legacy inline-monitor files — non-primary, see note below]
├── docs/
│ ├── architecture/ # target architecture
│ └── plans/ # migration and implementation plans
├── tasks/
│ ├── prd-writeassist-review-workbench.md # current PRD
│ └── review-workbench/ # implementation tickets (RW-001 … RW-602)
├── Package.swift
└── LICENSE
Legacy note:
GlobalInputMonitor,SelectionMonitor,ExternalSpellChecker,ErrorHUDPanel,SelectionSuggestionPanel,UndoToastPanel, and related files represent the old ambient inline-monitor path. They are kept compilable for reference but are no longer the primary product surface. The app boots inreviewWorkbenchOnlymode by default.
tasks/prd-writeassist-review-workbench.md— product requirementsdocs/architecture/review-workbench-target-architecture.md— target architecturedocs/plans/review-workbench-migration-plan.md— migration plantasks/review-workbench/README.md— implementation ticket index
swiftlintSee LICENSE for details.