9 Commits
Author SHA1 Message Date
Puranjay Savar MattasandClaude Sonnet 5 da1e7a180c chore: switch Xcode to the local swift-markdown-engine submodule
Removed the remote XCRemoteSwiftPackageReference and pointed
MarkdownEngine/MarkdownEngineCodeBlocks/MarkdownEngineLatex at the
XCLocalSwiftPackageReference for Vendor/swift-markdown-engine instead.
Package.resolved drops the now-irrelevant remote pin (HighlighterSwift
and SwiftMath stay remote, only swift-markdown-engine itself moved
local).

Also bumps the submodule pointer to include three warning fixes made
directly in the vendored source (var->let, unused local, #selector) —
first real edits to the package now that it's locally editable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 23:52:16 +01:00
Puranjay Savar MattasandClaude Sonnet 5 57eae9f643 chore: vendor swift-markdown-engine as a git submodule
Pinned to e5f7607 (v0.12.0), the exact commit already resolved in
Outpost.xcodeproj's Package.resolved — no version change, just gives it
a local, versioned checkout instead of only existing as an Xcode-managed
remote package cache. Brings its own ARCHITECTURE.md along at
Vendor/swift-markdown-engine/ARCHITECTURE.md.

Xcode side still needs a manual follow-up: remove the remote
"swift-markdown-engine" package reference and add
Vendor/swift-markdown-engine as a local package instead (File > Add
Package Dependencies > Add Local...). Not done here — pbxproj package
references aren't safely hand-editable without a build to verify against.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 23:45:38 +01:00
Puranjay Savar Mattas 0da26e0fed Merge pull request 'fix(about): About Outpost opens Settings' About section, no popup window' (#10) from fix/about-menu-no-popup into main
Reviewed-on: #10
2026-08-19 14:22:40 +01:00
Puranjay Savar Mattas 6ffba3be02 fix(about): About Outpost opens Settings' About section, no popup window
"About Outpost" in the app menu used to open a separate standalone
window (Window(id: "about") wrapping AboutView). Now just opens Settings
and jumps straight to the About section instead — same content
(AboutInfoView, unchanged), one less window/code path to maintain.

Also removed the "Check for Updates…" button — deferred per explicit
instruction, not deleted for a real reason beyond "not now." A simple
button can come back later; no update-checking logic was ever built; ,
nothing else to clean up alongside it.
2026-08-19 14:08:43 +01:00
Puranjay Savar Mattas 187f2eaa25 Merge pull request 'docs: fix wiki links to include trailing .-' (#9) from docs/wiki-link-fix into main
Reviewed-on: #9
2026-08-19 02:43:10 +01:00
Puranjay Savar Mattas 3fadd008f4 Merge branch 'main' into docs/wiki-link-fix 2026-08-19 02:42:56 +01:00
Puranjay Savar Mattas 410049d161 docs: fix wiki links, they need a trailing .- to resolve correctly
Confirmed live against the actual Gitea wiki — hyperlinks to
hyphenated wiki page names 404 without a trailing .-, e.g.
.../wiki/Privacy-Policy needs to be .../wiki/Privacy-Policy.-
2026-08-19 02:40:43 +01:00
Puranjay Savar Mattas 5301187413 Merge pull request 'docs: README - logo, TestFlight link, drop Status, expand Privacy' (#8) from docs/readme-testflight-privacy into main
Reviewed-on: #8
2026-08-19 02:38:12 +01:00
Puranjay Savar Mattas fe275ac17c docs: README — logo, real TestFlight link, drop Status, expand Privacy
- Logo and a TestFlight download badge at the top.
- Removed the Status/phase checklist — CLAUDE.md already tracks this,
  duplicating it in the README just goes stale.
- Requirements corrected to what the project actually targets right
  now (Xcode 27+, macOS 27+) instead of stale Xcode 16/iOS 17 numbers.
- Privacy section expanded with a real inline summary, linking out to
  the wiki for the full Privacy Policy, Terms of Service, and Data
  Processing Statement rather than duplicating them as repo files.
2026-08-19 02:26:36 +01:00
7 changed files with 64 additions and 95 deletions
+3
View File
@@ -1,3 +1,6 @@
[submodule "docs/reference/outline-openapi"] [submodule "docs/reference/outline-openapi"]
path = docs/reference/outline-openapi path = docs/reference/outline-openapi
url = https://github.com/outline/openapi.git url = https://github.com/outline/openapi.git
[submodule "Vendor/swift-markdown-engine"]
path = Vendor/swift-markdown-engine
url = https://github.com/nodes-app/swift-markdown-engine.git
+26 -36
View File
@@ -7,10 +7,10 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
FA7596B230366A1D0000167E /* MarkdownEngine in Frameworks */ = {isa = PBXBuildFile; productRef = FA7596B130366A1D0000167E /* MarkdownEngine */; };
FA7596B430366A1D0000167E /* MarkdownEngineCodeBlocks in Frameworks */ = {isa = PBXBuildFile; productRef = FA7596B330366A1D0000167E /* MarkdownEngineCodeBlocks */; };
FA7596B630366A1D0000167E /* MarkdownEngineLatex in Frameworks */ = {isa = PBXBuildFile; productRef = FA7596B530366A1D0000167E /* MarkdownEngineLatex */; };
FAF99C44302CF1BD00C9949F /* OutlineKit in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99C43302CF1BD00C9949F /* OutlineKit */; }; FAF99C44302CF1BD00C9949F /* OutlineKit in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99C43302CF1BD00C9949F /* OutlineKit */; };
FAF99CAF302D120500C9949F /* MarkdownEngine in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99CAE302D120500C9949F /* MarkdownEngine */; };
FAF99CB1302D120500C9949F /* MarkdownEngineCodeBlocks in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99CB0302D120500C9949F /* MarkdownEngineCodeBlocks */; };
FAF99CB3302D120500C9949F /* MarkdownEngineLatex in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99CB2302D120500C9949F /* MarkdownEngineLatex */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -59,9 +59,9 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
files = ( files = (
FAF99C44302CF1BD00C9949F /* OutlineKit in Frameworks */, FAF99C44302CF1BD00C9949F /* OutlineKit in Frameworks */,
FAF99CB1302D120500C9949F /* MarkdownEngineCodeBlocks in Frameworks */, FA7596B430366A1D0000167E /* MarkdownEngineCodeBlocks in Frameworks */,
FAF99CB3302D120500C9949F /* MarkdownEngineLatex in Frameworks */, FA7596B630366A1D0000167E /* MarkdownEngineLatex in Frameworks */,
FAF99CAF302D120500C9949F /* MarkdownEngine in Frameworks */, FA7596B230366A1D0000167E /* MarkdownEngine in Frameworks */,
); );
}; };
FAF99C24302CE96200C9949F /* Frameworks */ = { FAF99C24302CE96200C9949F /* Frameworks */ = {
@@ -116,9 +116,9 @@
name = Outpost; name = Outpost;
packageProductDependencies = ( packageProductDependencies = (
FAF99C43302CF1BD00C9949F /* OutlineKit */, FAF99C43302CF1BD00C9949F /* OutlineKit */,
FAF99CAE302D120500C9949F /* MarkdownEngine */, FA7596B130366A1D0000167E /* MarkdownEngine */,
FAF99CB0302D120500C9949F /* MarkdownEngineCodeBlocks */, FA7596B330366A1D0000167E /* MarkdownEngineCodeBlocks */,
FAF99CB2302D120500C9949F /* MarkdownEngineLatex */, FA7596B530366A1D0000167E /* MarkdownEngineLatex */,
); );
productName = Outpost; productName = Outpost;
productReference = FAF99C18302CE96100C9949F /* Outpost.app */; productReference = FAF99C18302CE96100C9949F /* Outpost.app */;
@@ -200,7 +200,7 @@
minimizedProjectReferenceProxies = 1; minimizedProjectReferenceProxies = 1;
packageReferences = ( packageReferences = (
FAF99C42302CF1BD00C9949F /* XCLocalSwiftPackageReference "OutlineKit" */, FAF99C42302CF1BD00C9949F /* XCLocalSwiftPackageReference "OutlineKit" */,
FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */, FA7596B030366A1D0000167E /* XCLocalSwiftPackageReference "Vendor/swift-markdown-engine" */,
); );
preferredProjectObjectVersion = 77; preferredProjectObjectVersion = 77;
productRefGroup = FAF99C19302CE96100C9949F /* Products */; productRefGroup = FAF99C19302CE96100C9949F /* Products */;
@@ -622,43 +622,33 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */ /* Begin XCLocalSwiftPackageReference section */
FA7596B030366A1D0000167E /* XCLocalSwiftPackageReference "Vendor/swift-markdown-engine" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = "Vendor/swift-markdown-engine";
};
FAF99C42302CF1BD00C9949F /* XCLocalSwiftPackageReference "OutlineKit" */ = { FAF99C42302CF1BD00C9949F /* XCLocalSwiftPackageReference "OutlineKit" */ = {
isa = XCLocalSwiftPackageReference; isa = XCLocalSwiftPackageReference;
relativePath = OutlineKit; relativePath = OutlineKit;
}; };
/* End XCLocalSwiftPackageReference section */ /* End XCLocalSwiftPackageReference section */
/* Begin XCRemoteSwiftPackageReference section */
FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/nodes-app/swift-markdown-engine";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.12.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
FA7596B130366A1D0000167E /* MarkdownEngine */ = {
isa = XCSwiftPackageProductDependency;
productName = MarkdownEngine;
};
FA7596B330366A1D0000167E /* MarkdownEngineCodeBlocks */ = {
isa = XCSwiftPackageProductDependency;
productName = MarkdownEngineCodeBlocks;
};
FA7596B530366A1D0000167E /* MarkdownEngineLatex */ = {
isa = XCSwiftPackageProductDependency;
productName = MarkdownEngineLatex;
};
FAF99C43302CF1BD00C9949F /* OutlineKit */ = { FAF99C43302CF1BD00C9949F /* OutlineKit */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = OutlineKit; productName = OutlineKit;
}; };
FAF99CAE302D120500C9949F /* MarkdownEngine */ = {
isa = XCSwiftPackageProductDependency;
package = FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */;
productName = MarkdownEngine;
};
FAF99CB0302D120500C9949F /* MarkdownEngineCodeBlocks */ = {
isa = XCSwiftPackageProductDependency;
package = FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */;
productName = MarkdownEngineCodeBlocks;
};
FAF99CB2302D120500C9949F /* MarkdownEngineLatex */ = {
isa = XCSwiftPackageProductDependency;
package = FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */;
productName = MarkdownEngineLatex;
};
/* End XCSwiftPackageProductDependency section */ /* End XCSwiftPackageProductDependency section */
}; };
rootObject = FAF99C10302CE96100C9949F /* Project object */; rootObject = FAF99C10302CE96100C9949F /* Project object */;
@@ -1,5 +1,5 @@
{ {
"originHash" : "f233fa96f0c6bdcdbf87f726af38f25704f6d46a156a27dfac47541baa63bf97", "originHash" : "4127e8224149bef00a33500e8db49748a735e1c07626f2255faea52554afef5e",
"pins" : [ "pins" : [
{ {
"identity" : "highlighterswift", "identity" : "highlighterswift",
@@ -10,15 +10,6 @@
"version" : "3.1.0" "version" : "3.1.0"
} }
}, },
{
"identity" : "swift-markdown-engine",
"kind" : "remoteSourceControl",
"location" : "https://github.com/nodes-app/swift-markdown-engine",
"state" : {
"revision" : "e5f7607fc4021181056ef7a09dbb7573dc0237d9",
"version" : "0.12.0"
}
},
{ {
"identity" : "swiftmath", "identity" : "swiftmath",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
+6 -28
View File
@@ -2,13 +2,11 @@
import AppKit import AppKit
import SwiftUI import SwiftUI
/// Bare content (icon, name, version, links) with no window chrome reused /// Bare content (icon, name, version, links) with no window chrome the
/// by both the standalone "About Outpost" window (`AboutView`, the standard /// macOS "About Outpost" app-menu command now opens Settings' own About
/// macOS app-menu affordance) and the Settings page's own About section, so /// section directly (no separate popup window), so this is its only caller.
/// the two can't drift out of sync.
struct AboutInfoView: View { struct AboutInfoView: View {
private let repositoryURL = URL(string: "https://git.psmattas.com/psmattas/Outpost")! private let repositoryURL = URL(string: "https://git.psmattas.com/psmattas/Outpost")!
private let releasesURL = URL(string: "https://git.psmattas.com/psmattas/Outpost/releases")!
var appName: String { var appName: String {
Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "Outpost" Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "Outpost"
@@ -45,35 +43,15 @@ struct AboutInfoView: View {
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
VStack(spacing: 10) { Link(destination: repositoryURL) {
Link(destination: repositoryURL) { Label("View Source on Git", systemImage: "link")
Label("View Source on Git", systemImage: "link")
}
.font(.callout)
Button("Check for Updates…") {
checkForUpdates()
}
} }
.font(.callout)
Text("© \(copyrightYear) Puranjay Savar Mattas") Text("© \(copyrightYear) Puranjay Savar Mattas")
.font(.caption2) .font(.caption2)
.foregroundStyle(.tertiary) .foregroundStyle(.tertiary)
} }
} }
// No Sparkle-style in-app updater yet this just opens the releases page
// on the self-hosted Gitea instance so the user can check/download manually.
private func checkForUpdates() {
NSWorkspace.shared.open(releasesURL)
}
}
struct AboutView: View {
var body: some View {
AboutInfoView()
.padding(32)
.frame(width: 320)
}
} }
#endif #endif
+2 -8
View File
@@ -18,7 +18,6 @@ struct OutpostApp: App {
@AppStorage("outpost.appearance") private var appearance: AppAppearance = .system @AppStorage("outpost.appearance") private var appearance: AppAppearance = .system
#if os(macOS) #if os(macOS)
@Environment(\.openWindow) private var openWindow
@State private var isShowingLogoutConfirmation = false @State private var isShowingLogoutConfirmation = false
#endif #endif
@@ -40,7 +39,8 @@ struct OutpostApp: App {
.commands { .commands {
CommandGroup(replacing: .appInfo) { CommandGroup(replacing: .appInfo) {
Button("About Outpost") { Button("About Outpost") {
openWindow(id: "about") navigation.selectedSettingsSection = .about
navigation.isShowingSettings = true
} }
} }
// No `Settings {}` scene anymore Settings renders inside the // No `Settings {}` scene anymore Settings renders inside the
@@ -64,12 +64,6 @@ struct OutpostApp: App {
#endif #endif
#if os(macOS) #if os(macOS)
Window("About Outpost", id: "about") {
AboutView()
.disablesFullScreen()
}
.windowResizability(.contentSize)
Window("Keyboard Shortcuts", id: "keyboard-shortcuts") { Window("Keyboard Shortcuts", id: "keyboard-shortcuts") {
KeyboardShortcutsView() KeyboardShortcutsView()
.disablesFullScreen() .disablesFullScreen()
+25 -13
View File
@@ -1,27 +1,29 @@
# Outpost <p align="center">
<img src="Outpost/Assets.xcassets/AppLogo.imageset/outpost-ios-1024.png" width="120" alt="Outpost logo">
</p>
<h1 align="center">Outpost</h1>
<p align="center">
<a href="https://testflight.apple.com/join/y1mYcYAM">
<img src="https://img.shields.io/badge/Download-TestFlight-0D96F6?style=for-the-badge&logo=apple&logoColor=white" alt="Download on TestFlight">
</a>
</p>
A native Apple ecosystem client for [Outline](https://github.com/outline/outline) — built for iOS, iPadOS, and macOS from a single SwiftUI codebase, aiming for full editing parity with Outline's web app, including realtime collaborative editing. A native Apple ecosystem client for [Outline](https://github.com/outline/outline) — built for iOS, iPadOS, and macOS from a single SwiftUI codebase, aiming for full editing parity with Outline's web app, including realtime collaborative editing.
> **Early alpha — macOS only for now.** Expect missing features and rough edges. iOS/iPadOS support is planned but not in the current build. See the [releases page](https://git.psmattas.com/psmattas/Outpost/releases) for changelogs, and [open an issue](https://git.psmattas.com/psmattas/Outpost/issues) if you hit anything.
## Why ## Why
Outline's web app is great, but there's no native Apple client with full editing parity. This project connects to a self-hosted Outline instance over its REST API and realtime collaboration socket to provide a proper native experience across the Apple ecosystem. Outline's web app is great, but there's no native Apple client with full editing parity. This project connects to a self-hosted Outline instance over its REST API and realtime collaboration socket to provide a proper native experience across the Apple ecosystem.
## Status
Early development. See `CLAUDE.md` for the current architecture and phased build plan.
- [ ] Phase 1 — Auth, browse, search, REST-only editing
- [ ] Phase 2 — Realtime collaborative editing (Yjs/Hocuspocus)
- [ ] Phase 3 — Offline cache, tables, embeds, comments, macOS polish
## Requirements ## Requirements
- Xcode 16+ - Xcode 27+ (currently developed against an Xcode 27 beta — this is a hard minimum, not a suggestion)
- iOS 17+ / iPadOS 17+ / macOS 14+ - macOS 27+. iOS/iPadOS support is planned but not in the current build (see the alpha note above) — same 27+ minimum will apply once it lands
- A self-hosted (or hosted) Outline instance with API access - A self-hosted (or hosted) Outline instance with API access
> They will be updated. These are old requirements.
## Setup ## Setup
1. Clone the repo and open the `.xcodeproj` in Xcode. 1. Clone the repo and open the `.xcodeproj` in Xcode.
@@ -42,6 +44,16 @@ Parts of this codebase are AI-assisted (built with the help of AI coding tools).
This project is a client only — it does not include, vendor, or redistribute any of Outline's (BSL 1.1 licensed) server source. See [`LICENSE`](./LICENSE) for this repository's own license. This project is a client only — it does not include, vendor, or redistribute any of Outline's (BSL 1.1 licensed) server source. See [`LICENSE`](./LICENSE) for this repository's own license.
## Privacy
Outpost collects nothing about you — no analytics, no telemetry, no crash reporting of its own, no age or demographic data, nothing. The only thing stored locally is your Outline server URL and API token (in the device Keychain) and, optionally, a local offline cache of what you've viewed. Everything else goes straight from your device to whatever Outline server you configure — there's no backend in between, and the developer has no access to your data or your server.
Full policy, terms of service, and data-processing statement are on the [wiki](https://git.psmattas.com/psmattas/Outpost/wiki):
- [Privacy Policy](https://git.psmattas.com/psmattas/Outpost/wiki/Privacy-Policy.-)
- [Terms of Service](https://git.psmattas.com/psmattas/Outpost/wiki/Terms-of-Service.-)
- [Data Processing Statement](https://git.psmattas.com/psmattas/Outpost/wiki/Data-Processing-Statement.-)
## Not affiliated with Outline ## Not affiliated with Outline
This is an independent, unofficial client. Not affiliated with or endorsed by General Outline, Inc. This is an independent, unofficial client. Not affiliated with or endorsed by General Outline, Inc.