# Orgstar review, 2026-10-05 Branch `buffers` at a831086. Emacs 31.1 / Org 9.8.7 installed, so the oracle tests ran. ## 1. Current state **Scope shipped.** The design doc's phases 1 through 6 all have code: lossless parser with incremental reparse, TextKit 2 editor with folding and org-indent, SQLite/FTS index with a dirty-buffer overlay, three-way-merge save path with recovery copies, heading/list/table/timestamp/fill commands, agenda (day/week, TODO list, tag match, saved views, habits, reminders), native table formulas with Emacs fallback, Babel for shells/python/elisp plus output-only runners, capture with a global hotkey, HTML/Markdown export natively and PDF/ODT/LaTeX/text through `emacs --batch`, clocking with a menu-bar item, board/kanban, Emacs/Mac/Doom keymaps with a Vim modal engine, themes, config.toml with two-way sync, and import from an Emacs config. About 37k lines of Swift. 107 commits, all dated Oct 4 and 5. **Quality bar.** Where a command exists it is checked byte-for-byte against Emacs: 31 oracle tests run by default and fail if Emacs is missing. 341 tests pass at a6139aa (the commit before Buffers). Performance gates pass on an M-series Mac (open 75 ms for 1.5 MB, typing p95 6.5 ms, memory 9.6x), not yet on the M1 Air reference machine. **Architecture holds.** OrgCore/OrgIndex/OrgWorkspace/OrgPresentation import no AppKit/UIKit/SwiftUI; the only platform code is FSEvents behind `#if os(macOS)`. Commands are pure functions over `EditContext`, so the iOS path the design promises is still open. **Stale docs.** README says "Status: phase 1 (read-only viewer)". The design doc still names OrgSwift as the renderer and has every phase-1 checkbox unchecked. The Emacs importer tells users "Orgstar has no fonts or themes to set yet" (`Sources/OrgApp/EmacsImport.swift:451`). ### Defects found | Where | Problem | | --- | --- | | `Tests/OrgAppTests/AppTests.swift:316-374` | `AgendaModel.refresh(open:)` now takes `[String: String]`; the tests still pass `nil` and a tuple. The OrgAppTests target does not compile at a831086. | | `Sources/OrgCore/Keymap/Presets.swift:558,579` | `C-x b` is bound twice; the later `app.quick-open` wins, so the new buffer switch is unreachable in the Emacs preset. `SPC b b` is also bound twice (:90, :99); there the later `buffer.switch` wins and :90 is dead. | | `Sources/OrgEditorAppKit/OrgEditor.swift:731` | After any edit, hidden ranges are rebuilt without `bodyFolds` (line 464 passes them). CONTENTS-folded bodies reappear while the view still thinks they are folded. | | `Sources/OrgApp/WorkspaceModel.swift:57,158` | `startWatching()` runs once at launch; `addRoot` never restarts it. A folder added during a session gets no FSEvents until relaunch. | | `Sources/OrgApp/DocumentSession.swift:356-410` | Refile/archive into another file read the target from disk and write through `Saver`, ignoring that file's open buffer; the buffer catches up only by a later merge. | | `Sources/Orgstar/EditorView.swift:86` | Every per-buffer editor's `onChange` calls `session.bufferChanged()`, which acts on the current entry. A disk change merged into a background buffer schedules no autosave for it. | | `Sources/OrgApp/BabelRunner.swift:48` | stderr is discarded, and the Task is not kept, so a run cannot be cancelled. | | `Sources/OrgEditorAppKit/LineNumbers.swift:12,35` | Line numbering counts newlines from offset 0 on every draw and splits the whole string on every newline edit. Added after the performance gates and not re-measured. | | `Sources/Orgstar/ClockViews.swift:129` | Clock report reads files from disk and ignores unsaved buffers. | | `scripts/build-app.sh` | No `CFBundleDocumentTypes`, so `.org` files can't be opened from Finder or `open`; no icon; no URL scheme. | ## 2. Gaps against Emacs org-mode Grouped by how often a daily org user hits them. "Known" means the project's own plan or code already records it as not done. ### Hit every day - **Links.** No follow (`C-c C-o`, click, RET), no insert (`C-c C-l`), no store, no `id:` creation. Links are only styled. `#+LINK` abbreviations, `attachment:`, `CUSTOM_ID` lookup are absent too. - **TODO logging.** No `CLOSED:` on DONE (`org-log-done`), no `!`/`@` state notes, no `LOGBOOK` notes (`org-log-into-drawer` is hard-coded nil in `Repeat.swift:3`), no note prompt. Fast keys in `#+TODO` are parsed but unused; no fast selection. No `S-left/right` keyword cycling, no `ORDERED`/blocking. - **Tags.** Free-text prompt only. No fast selection, no `#+TAGS` groups, no completion from the workspace, no file tags (known). - **Drawer and block folding.** Property and LOGBOOK drawers are always open. Emacs folds them. - **Capture.** No `file+datetree`, `id` or `clock` targets; `%^g`, `%^t`, `%^C`, `%:keyword` fail; only `:prepend` is honoured (known). The user's own notes include journal and habit files, which typically depend on datetree. - **Agenda actions.** No filters (`/`), no clock-in, refile or archive from the agenda, no bulk actions, no log or clockreport mode, no follow mode, fixed prefix format. - **Subtree editing.** No cut/copy/paste/clone, no `org-sort`, no `org-mark-subtree`, no `C-c *` / `C-c -` toggles, no `org-toggle-comment`. - **Structure templates** (`C-c C-,`, `` shrink, no field editor (known). - Navigation: no narrowing, `org-goto`, sparse trees, `org-occur`, speed keys. - Properties: set only; no delete, no `_ALL` completion, no column view. - Archive: no archive-tag toggle, no archive-to-sibling, no `datetree/` location. - Export: `#+OPTIONS`, TOC, `:noexport:`, `#+INCLUDE`, macros, LaTeX fragments, subscripts, `#+HTML_HEAD` all ignored; Markdown is GFM, not ox-md. Pandoc path from the design is absent. - Babel: `:session`, `:noweb`, `:file` (dot/plantuml images), `#+CALL`, inline `src_` execution, tangle (known). - Visibility: `#+STARTUP` only handles visibility words; `indent`, `logdone`, `hidestars`, `align` ignored. `VISIBILITY` property ignored. - Inline images: none. ### Parser and settings - Not parsed: radio targets, `$…$` LaTeX, LaTeX environments, inline tasks, entities and subscripts as objects, export snippets, citations, `call_`, diary sexps, table.el tables, alphabetical bullets (even with the option on), description-list terms and `[@N]` counters as nodes. - File-level `:PROPERTIES:` drawer is treated as a generic drawer. - Ignored keywords: `#+TAGS`, `#+CONSTANTS`, `#+COLUMNS`, `#+LINK`, `#+OPTIONS`, `#+SETUPFILE`, `#+INCLUDE`, `#+MACRO`, `#+EXCLUDE_TAGS`. ### Editor and platform - No inline completion of any kind; no spell check; no auto-pairing; no heading-click fold; no checkbox or timestamp click; soft wrap can't be turned off; `gj`/`gk` are plain `j`/`k`. - Vim: no macros, marks, jumps, `gv`, block visual, surround, commentary, evil-org text objects (known). - Conflict UI has no diff view; Syncthing conflict copies open as ordinary files with no diff (known). - iCloud placeholders: design calls for them, only `startDownloadingUbiquitousItem` in the reconciler exists. - Distribution: ad-hoc signed, no icon, no notarization, no Sparkle, no Homebrew cask, no document types, no URL scheme (`org-protocol`), no Shortcuts/AppleScript, no Spotlight or Quick Look extension. - iOS: `Package.swift` declares the platform; no target exists. - VoiceOver checklist never run; hidden markup and stars are still in the accessibility value. ### Intentionally out (design non-goals) Elisp runtime, block storage, Mac App Store, Babel on iOS, native Calc symbolic math, sync providers beyond Syncthing and iCloud. ## 3. Prioritised feature list Ordered by what stops the app from replacing Emacs for an org-only user, then by cost. Each tier is roughly one plan per bullet. ### Tier 0: fix before building more 1. Make OrgAppTests compile and pass; fix the two duplicate bindings. 2. `bodyFolds` in `storageEdited`; restart watching on `addRoot`; per-buffer `onChange`; refile/archive through the target's open buffer. 3. Babel: capture stderr into the message, keep the Task for cancel. 4. Re-run the gates (`ORGSTAR_GATES=1`) with line numbers, pretty entities and the block band on; fix line-number counting. 5. `CFBundleDocumentTypes` for `.org`/`.org_archive`, an icon. Update README status. ### Tier 1: daily-use parity 1. **Links**: open (`C-c C-o`, ⌘-click, RET on a link), insert with completion over headings/files/ids, store link, `org-id-get-create`, `#+LINK` abbreviations, `CUSTOM_ID`. The index already has link rows and `headings(withID:)`. 2. **TODO logging**: `org-log-done`, per-keyword `!`/`@`, `org-log-into-drawer`, note prompt through the existing `Prompt` loop. Habits already parse "State" notes, so this also fixes habit tracking for users with `org-log-into-drawer t`. 3. **Fast TODO and fast tag selection**, `#+TAGS` groups, tag completion from the index. Honour `org-todo-keywords` with several sequences from config. 4. **Drawer and block folding** in `Presentation.hiddenRanges`, default folded, TAB on a drawer line. 5. **Capture targets and escapes**: `file+datetree` (day/week/month, `:tree-type`), `id`, `clock`; `%^g`, `%^t`/`%^T`/`%^u`/`%^U`, `%^C`, typed prompts; `:immediate-finish`, `:empty-lines`, `:clock-in`/`:clock-keep`, `:jump-to-captured`. 6. **Agenda actions**: filter by tag/category/regexp/effort, clock in/out, refile, archive, bulk mark and act, log mode, `org-agenda-prefix-format`. 7. **Subtree commands**: cut/copy/paste/clone, `org-sort` (entries and lists), mark subtree, `C-c *`/`C-c -`, toggle comment. 8. **Structure templates** and **`org-edit-special`** (a sheet with the tree-sitter grammar and the block's language). 9. **Clocktable** dynamic block, `org-dblock-update`, `Effort` property and `org-clock-modeline-total`. 10. **`C-c C-c` contexts**: heading tags, timestamp normalise, property line, footnote, cookie, `#+RESULTS`, keyword refresh, dynamic block. ### Tier 2: weekly parity 1. Date picker popover for `org-read-date`; date ranges; `org-log-reschedule`/`redeadline`; `C-c C-y`. 2. Footnote commands (new, goto, sort, normalise). 3. Tables: in-cell `=`/`:=` formulas, formula editor, sort, transpose, CSV import/export, `` shrink. 4. Narrowing, `org-goto`, sparse trees / `org-occur` (reuse the FTS and tag matcher), speed keys. 5. Property delete, `_ALL` completion, column view (read-only first). 6. Archive tag toggle, archive to sibling, `datetree/` archive location. 7. Export: `#+OPTIONS` (toc, num, tags, todo, `^:{}`), `:noexport:`/`:export:`, `#+INCLUDE`, macro expansion, MathJax for LaTeX fragments, subscripts, `#+HTML_HEAD`; export dialog with destination and open-after. 8. Babel: `:session` for shells and python, `:file` with inline image results (dot, plantuml, mermaid), `:noweb`, `#+CALL`, inline `src_`. 9. Inline images (`file:` links to images, `#+ATTR_ORG: :width`), toggled like `org-toggle-inline-images`. 10. Parser completions: radio targets, `$…$`, LaTeX environments, entities and subscripts as objects, inline tasks, file-level property drawer, alphabetical bullets, `#+TAGS`/`#+CONSTANTS`/`#+COLUMNS`/`#+LINK`/`#+MACRO`. 11. `#+STARTUP` beyond visibility (`indent`, `logdone`, `hidestars`, `align`), `VISIBILITY` property. 12. Conflict and Syncthing-copy diff view; recovery folder browser. 13. Vim: macros, marks, jumps, `gv`, block visual, surround, commentary, evil-org text objects, `:e`/`:bd`/`:bn`. 14. Editor: completion popover (tags, todo, properties, links, templates), spell check, heading click to fold, checkbox click, truncate-lines toggle, `gj`/`gk`. ### Tier 3: distribution and beyond Emacs 1. Notarised build, Sparkle, Homebrew cask, Developer ID signing. 2. `org-protocol://` URL scheme and a Shortcuts/App Intents capture action; share extension later. 3. Spotlight importer and Quick Look extension for `.org`. 4. Backlinks pane from the index's link rows; an ID graph is cheap once link resolution exists. 5. Column view and clock reports as live sidebars rather than dynamic blocks. 6. iCloud placeholders and `NSFilePresenter` path, then the iOS target: capture and agenda first, per the design. 7. VoiceOver pass and an accessibility value that omits hidden markup. ## 4. Notes on process - The whole repo was written in two days. The oracle discipline is what makes that credible; keep it mandatory for every Tier 1 command (each maps to an org function: `org-open-at-point`, `org-todo` with logging, `org-set-tags-command`, `org-capture` datetree, `org-sort`). - Prefer one plan per Tier 1 bullet, as the existing `docs/plans` do, and record "not yet" lists the same way; those lists were the fastest way to produce this review. - The design's phase gates were never ticked and the M1 Air run is still owed. Measure once before Tier 1 adds more rendering work.