Sapling/decisions.md

18 KiB
Raw Permalink Blame History

DECISIONS

This document records major architectural and product decisions made during the development of Sapling.

The goal is to preserve context and reasoning behind decisions so future contributors can understand why a particular approach was chosen.


D-001 — Sapling Is Local-First

Date: 2025-08

Status: Accepted

Decision

Sapling will be a local-first application.

All user content lives on the local filesystem.

No Sapling-managed cloud service will be required.

Rationale

Users should own their data.

Files must remain accessible outside of Sapling.

The application should continue functioning without network connectivity.

Consequences

Positive:

  • No vendor lock-in
  • Offline support
  • Simpler privacy story
  • Easier long-term maintenance

Negative:

  • No built-in synchronization
  • Collaboration relies on Git workflows

D-002 — Git Is Infrastructure, Not the Product

Date: 2025-08

Status: Accepted

Decision

Git will be a first-class capability but not the primary user-facing concept.

The editor and workspace experience take precedence over Git terminology.

Rationale

Most users want versioning benefits without learning Git internals.

Sapling should remain approachable to writers, researchers, and knowledge workers.

Consequences

User interfaces should prefer language such as:

  • Snapshot
  • Changes
  • History

over:

  • Commit
  • Staging
  • Reflog

Advanced Git functionality will remain available.


D-003 — Projects Are Git Repositories

Date: 2025-08

Status: Accepted

Decision

Every Sapling project corresponds directly to a Git repository.

No custom repository format will be introduced.

Rationale

Git repositories are portable and understood by existing tooling.

Users should be able to move between Sapling and other Git tools without migration.

Consequences

Projects can be opened in:

  • Terminal
  • GitHub Desktop
  • SourceTree
  • VS Code
  • Any Git client

without conversion.


D-004 — Workspaces Are Not Versioned

Date: 2025-08

Status: Accepted

Decision

Workspaces are organizational containers and are not Git repositories.

Projects are versioned.

Workspaces are not.

Rationale

Users need a place for temporary notes, drafts, and experimentation.

Not everything should require commits.

Consequences

Workspace structure exists outside repository history.

Projects remain independently portable.


D-005 — Attachments Belong to Projects

Date: 2025-08

Status: Accepted

Decision

Attachments are stored inside project directories.

They are not stored in a database.

They are not stored in a global asset store.

Rationale

Repositories should remain self-contained.

Cloning a repository should retrieve everything required to render its content.

Consequences

Projects remain portable.

Attachments participate naturally in version control.


D-006 — Large Assets Use Git LFS

Date: 2025-08

Status: Accepted

Decision

Large binary files should be managed through Git LFS.

Rationale

Repositories containing images, PDFs, design assets, and media files can become excessively large.

Git LFS is the industry-standard solution.

Consequences

Sapling must detect and assist with LFS configuration.


D-007 — Subprojects Use Git Submodules

Date: 2025-08

Status: Accepted

Decision

Nested projects are implemented using Git submodules.

Rationale

Submodules provide an existing, portable, Git-native solution.

No custom dependency system is required.

Consequences

Sapling must provide a significantly better UX around submodules than traditional Git tools.


D-008 — Hybrid Markdown Editing Is a Core Feature

Date: 2025-08

Status: Accepted

Decision

Sapling will implement hybrid Markdown editing.

The active line displays source.

Inactive lines display rendered content.

Rationale

This editing model combines the readability of rendered Markdown with the precision of source editing.

It is one of the primary differentiators of Sapling.

Consequences

The editor becomes a critical architectural component.

Prototype and validation work should occur early.


D-009 — The Editor Is the Highest-Priority System

Date: 2025-08

Status: Accepted

Decision

Editor quality takes precedence over Git features.

Rationale

Users tolerate missing Git features.

Users do not tolerate poor editing experiences.

Consequences

Development milestones should prioritize:

  1. Editing
  2. Rendering
  3. Workspace management
  4. Git integration

in that order.


D-010 — Git Access Must Be Abstracted

Date: 2025-08

Status: Accepted

Decision

All Git functionality must be accessed through a GitProvider abstraction.

Application code should never invoke Git directly.

Rationale

macOS and iOS have different implementation requirements.

A clean abstraction improves portability and testability.

Initial Implementations

MacGitProvider

  • Uses system Git

EmbeddedGitProvider

  • Future iOS implementation

Consequences

All repository operations must remain implementation-agnostic.


D-011 — Markdown Files Remain Standard Markdown

Date: 2025-08

Status: Accepted

Decision

Sapling documents are standard Markdown files.

No proprietary format will be introduced.

Rationale

Users should be free to edit documents with any editor.

Knowledge should not be trapped inside Sapling.

Consequences

Any Sapling-specific features should degrade gracefully in standard Markdown environments.


D-012 — Platform Focus

Date: 2025-08

Status: Accepted

Decision

macOS is the primary target platform.

iOS support is a secondary objective.

Rationale

The desktop writing experience is the primary use case.

Starting with macOS reduces complexity and accelerates development.

Consequences

Architecture should remain cross-platform where practical.

Product decisions should optimize for desktop workflows first.


D-013 — Editor Technology Selection

Date: 2026-05

Status: Accepted Provisionally

Review After: Milestone 2

Decision

Sapling will use native platform text systems for the editor prototype:

  • NSTextView on macOS
  • UITextView on iOS

These views will be wrapped behind a Sapling editor abstraction.

SwiftUI TextEditor will not be used as the primary editor implementation.

Rationale

Sapling's hybrid Markdown editor requires advanced control over cursor movement, selection state, layout, attributed rendering, and editing behavior.

SwiftUI TextEditor is useful for simple text entry, but it does not expose enough low-level editing hooks to validate the active-line source and inactive-line rendered model cleanly.

NSTextView and UITextView provide direct access to TextKit, attributed text storage, selection ranges, delegates, layout managers, and platform editing behaviors. That makes them better foundations for Milestone 1 validation.

Consequences

Positive:

  • The prototype can inspect and control selection ranges directly.
  • Line-level styling and rendering experiments can be performed in-place.
  • The app can preserve native editing behavior while testing hybrid Markdown concepts.
  • The implementation can remain SwiftUI at the application layer.

Negative:

  • AppKit and UIKit bridging adds platform-specific code.
  • The editor abstraction must prevent the rest of the app from depending directly on NSTextView or UITextView.
  • A future custom editor engine may still be required if line replacement or overlay rendering cannot preserve cursor correctness.
  • Native adapter updates must isolate user-originated selection changes from programmatic text, selection, and attribute changes to avoid SwiftUI/TextKit feedback loops.

D-014 — Hybrid Editor Architecture Validated

Status

Accepted

Date

2026-06-02

Context

Sapling's core user experience depends on a hybrid editing model:

  • active content is displayed as Markdown source
  • inactive content is displayed as rendered output

This model combines advantages of:

  • plain-text Markdown editors
  • live preview editors
  • rendered document editors

However, early in development there was uncertainty regarding:

  • editor performance
  • large-document scalability
  • rendering determinism
  • active-line tracking
  • viewport stability
  • TextKit suitability
  • code block rendering
  • interactive rendered elements

A significant portion of Milestones 13 was dedicated to validating the feasibility of this architecture before proceeding with workspace and Git functionality.

Decision

Sapling adopts a hybrid rendered/source editing architecture as its primary editing model.

The architecture is considered validated and will remain the foundation of the application.

The editor will not be rewritten and no custom text engine is planned at this time.

Validated Properties

The following properties have been demonstrated through implementation, profiling, and real-world testing.

Large Document Scalability

Documents exceeding:

  • 50,000 lines
  • 5 MB of Markdown content

remain usable.

Profiling identified document-wide operations and replaced them with incremental approaches.

Incremental Editing

Sapling maintains:

  • incremental line indexing
  • incremental invalidation
  • incremental rendering updates

Editor interactions scale with the edited region rather than total document size.

Rendering Determinism

Rendering output is derived from document state rather than interaction history.

Rendered content behaves consistently across:

  • scrolling
  • focus changes
  • selection changes
  • document reloads

Editable Regions

The editor supports:

  • single-line editing
  • multi-line editing
  • block editing

Rendered content transitions into source mode when actively edited.

Rendered Elements

The editor supports first-class rendered elements including:

  • headings
  • task lists
  • links
  • code blocks

The architecture supports future rendered elements without fundamental redesign.

Code Blocks

Code blocks are treated as semantic block elements rather than styled text.

They support:

  • rendered containers
  • syntax highlighting
  • editable source transitions

Viewport Stability

Rendered/source transitions preserve user context and do not require disruptive viewport repositioning.

Technology Choice

The editor continues to use:

  • NSTextView
  • NSTextStorage
  • NSLayoutManager
  • TextKit

Investigation determined that observed performance bottlenecks originated primarily from Sapling's own document-wide algorithms rather than AppKit itself.

After introducing:

  • incremental line indexing
  • incremental invalidation
  • region-based rendering

TextKit remained sufficiently performant for the project's requirements.

Alternatives Considered

Custom Text Engine

Rejected.

Reasons:

  • significantly higher complexity
  • increased maintenance burden
  • no demonstrated need
  • current architecture satisfies project requirements

Split Editor / Preview Model

Rejected.

Reasons:

  • interrupts writing flow
  • increases cognitive overhead
  • conflicts with Sapling's editing philosophy

Full WYSIWYG Editor

Rejected.

Reasons:

  • obscures Markdown source
  • reduces portability
  • conflicts with project goals

Consequences

Positive

  • Markdown remains the source of truth.
  • Editing remains fast on large documents.
  • Rendered content improves readability.
  • The editor architecture is stable enough for future feature development.
  • Workspace and Git functionality can now be built on top of a proven editor foundation.

Negative

  • Hybrid editing introduces presentation complexity.
  • Rendered/source transitions require ongoing testing.
  • Some presentation-layer edge cases may continue to require refinement.

Rationale

The editor is the core product experience.

Milestones 13 demonstrated that a hybrid rendered/source architecture can provide:

  • Markdown transparency
  • pleasant reading experience
  • scalable performance
  • future extensibility

without requiring a custom editor implementation.

Future development should build upon this foundation rather than revisit the editor architecture unless substantial new evidence emerges.


D-015 — Filesystem Is The Source Of Truth

Status

Accepted

Date

2026-06-02

Context

Sapling introduces a distinction between:

  • ordinary folders
  • versioned projects
  • Git subprojects

A key architectural decision is determining where workspace state lives.

Two approaches were considered:

Option A — Sapling-Owned Workspace Metadata

Sapling maintains a manifest or database describing:

  • folders
  • files
  • projects
  • attachments
  • hierarchy

The filesystem becomes an implementation detail.

Advantages:

  • complete control
  • fast metadata access
  • custom workspace structures

Disadvantages:

  • duplicates filesystem state
  • requires synchronization
  • external modifications become difficult
  • introduces risk of workspace corruption
  • reduces interoperability with other tools

Option B — Filesystem-Native Workspace

The workspace is a normal directory on disk.

Sapling scans and interprets the filesystem directly.

Advantages:

  • simple mental model
  • interoperability with external tools
  • no synchronization layer
  • naturally compatible with Git
  • resilient to external modifications

Disadvantages:

  • requires filesystem scanning
  • metadata must be derived rather than stored

Decision

Sapling adopts a filesystem-native architecture.

The filesystem is the authoritative source of truth.

Sapling does not maintain an authoritative database or manifest describing workspace contents.

Workspace contents are derived directly from the filesystem.

Projects are discovered through Git metadata.

Subprojects are discovered through Git submodules.

Files and folders remain ordinary filesystem objects.

Workspace Model

Workspace:

Workspace/
├── Notes/
├── Research/
├── Project-A/
└── Project-B/

Sapling scans the workspace root and builds its tree model from the current filesystem state.

Changes made through:

  • Finder
  • Terminal
  • VS Code
  • Cursor
  • Xcode
  • Photoshop
  • external scripts

must appear naturally inside Sapling.

No import or synchronization step should be required.

Project Detection

A directory containing:

.git/

is considered a project.

Projects receive additional capabilities:

  • Git status
  • commits
  • branches
  • remotes
  • history
  • Git LFS
  • submodules

Folders without Git metadata remain ordinary folders.

Subproject Detection

Git submodules are treated as first-class Sapling subprojects.

Subproject discovery is derived from Git configuration rather than Sapling metadata.

Persistence

Sapling may persist application state separately.

Examples:

  • recent workspaces
  • window state
  • open tabs
  • sidebar width
  • editor preferences
  • UI configuration

This data must never become the authoritative representation of workspace contents.

Consequences

Positive

  • Workspace remains human-readable.
  • Workspace remains tool-agnostic.
  • Users can manipulate files outside Sapling.
  • Git integration remains natural.
  • Cloud synchronization solutions work without special support.
  • Workspaces remain usable even if Sapling is uninstalled.

Negative

  • Workspace state must be derived from filesystem scans.
  • File watching becomes important.
  • Some metadata may need caching for performance.

Rationale

One of Sapling's core values is ownership.

Users should own their notes, projects, attachments, and repositories without depending on Sapling-specific storage formats.

A workspace should remain a normal directory that can be understood and manipulated using standard operating system tools.

Sapling should adapt to the filesystem rather than requiring the filesystem to adapt to Sapling.


D-016 — Workspace Tree and Document Sessions Are Separate Concepts

Status

Accepted

Date

2026-06-02

Context

A filesystem-backed workspace naturally describes what exists on disk.

However, the user interface must also represent documents that are currently open for editing.

These concerns are related but distinct.

Historically many editors conflate:

  • selected file
  • open file
  • visible editor

This makes future features such as tabs, split views, and multiple windows difficult to implement.

Decision

Sapling separates:

Workspace Tree

Represents:

  • folders
  • projects
  • files

derived from the filesystem.

The workspace tree answers:

"What exists?"

Document Sessions

Represents:

  • open documents
  • editor state
  • cursor position
  • scroll position
  • unsaved state

The document session answers:

"What is currently being edited?"

Principles

Selecting a file does not imply ownership of editor state.

A document may exist in:

  • the workspace tree
  • a tab
  • a split view
  • a separate window

without changing its identity.

Document state belongs to the document session.

Not the workspace tree.

Tab Model

Tabs are a presentation of document sessions.

A file may only have one document session within a workspace.

Opening an already-open document should activate its existing session rather than creating a duplicate.

Future Compatibility

This decision intentionally supports:

  • tabs
  • split views
  • multiple windows
  • session restoration

without requiring changes to the workspace model.

These features are presentation concerns built on top of document sessions rather than filesystem discovery.

Consequences

Positive

  • Clear separation of responsibilities.
  • Simplifies workspace discovery.
  • Enables future UI layouts.
  • Prevents duplicated editor state.

Negative

  • Introduces an additional abstraction layer.
  • Requires explicit session management.

Rationale

The filesystem should describe what exists.

Document sessions should describe what is being edited.

Keeping these concerns separate allows Sapling to evolve its user interface without revisiting the workspace architecture.