docs/review-2026-10-05.md
136 lines · 13382 bytes
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, noid:creation. Links are only styled.#+LINKabbreviations,attachment:,CUSTOM_IDlookup are absent too. - TODO logging. No
CLOSED:on DONE (org-log-done), no!/@state notes, noLOGBOOKnotes (org-log-into-draweris hard-coded nil inRepeat.swift:3), no note prompt. Fast keys in#+TODOare parsed but unused; no fast selection. NoS-left/rightkeyword cycling, noORDERED/blocking. - Tags. Free-text prompt only. No fast selection, no
#+TAGSgroups, 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,idorclocktargets;%^g,%^t,%^C,%:keywordfail; only:prependis 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, noorg-mark-subtree, noC-c */C-c -toggles, noorg-toggle-comment. - Structure templates (
C-c C-,,<s TAB) andorg-edit-special(C-c '). - Clocktable dynamic block and
org-dblock-update; effort estimates (known). C-c C-ccovers only item, table, TBLFM and src. Missing: heading (tags), timestamp, property, footnote, clock, cookie,#+RESULTS/#+CALL, keyword refresh, dynamic block.
Hit weekly
- Timestamps: no calendar picker, no date ranges in the prompt, no
org-log-reschedule/redeadline, noC-c C-y(known). - Footnotes: parsed and exported, no new/goto/sort/normalize commands.
- Tables: no in-cell field formulas or formula editor, no sort/transpose/CSV import-export, no
<10>shrink, no field editor (known). - Navigation: no narrowing,
org-goto, sparse trees,org-occur, speed keys. - Properties: set only; no delete, no
_ALLcompletion, 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_HEADall ignored; Markdown is GFM, not ox-md. Pandoc path from the design is absent. - Babel:
:session,:noweb,:file(dot/plantuml images),#+CALL, inlinesrc_execution, tangle (known). - Visibility:
#+STARTUPonly handles visibility words;indent,logdone,hidestars,alignignored.VISIBILITYproperty 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/gkare plainj/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
startDownloadingUbiquitousItemin 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.swiftdeclares 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
- Make OrgAppTests compile and pass; fix the two duplicate bindings.
bodyFoldsinstorageEdited; restart watching onaddRoot; per-bufferonChange; refile/archive through the target's open buffer.- Babel: capture stderr into the message, keep the Task for cancel.
- Re-run the gates (
ORGSTAR_GATES=1) with line numbers, pretty entities and the block band on; fix line-number counting. CFBundleDocumentTypesfor.org/.org_archive, an icon. Update README status.
Tier 1: daily-use parity
- Links: open (
C-c C-o, ⌘-click, RET on a link), insert with completion over headings/files/ids, store link,org-id-get-create,#+LINKabbreviations,CUSTOM_ID. The index already has link rows andheadings(withID:). - TODO logging:
org-log-done, per-keyword!/@,org-log-into-drawer, note prompt through the existingPromptloop. Habits already parse "State" notes, so this also fixes habit tracking for users withorg-log-into-drawer t. - Fast TODO and fast tag selection,
#+TAGSgroups, tag completion from the index. Honourorg-todo-keywordswith several sequences from config. - Drawer and block folding in
Presentation.hiddenRanges, default folded, TAB on a drawer line. - 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. - Agenda actions: filter by tag/category/regexp/effort, clock in/out, refile, archive, bulk mark and act, log mode,
org-agenda-prefix-format. - Subtree commands: cut/copy/paste/clone,
org-sort(entries and lists), mark subtree,C-c */C-c -, toggle comment. - Structure templates and
org-edit-special(a sheet with the tree-sitter grammar and the block's language). - Clocktable dynamic block,
org-dblock-update,Effortproperty andorg-clock-modeline-total. C-c C-ccontexts: heading tags, timestamp normalise, property line, footnote, cookie,#+RESULTS, keyword refresh, dynamic block.
Tier 2: weekly parity
- Date picker popover for
org-read-date; date ranges;org-log-reschedule/redeadline;C-c C-y. - Footnote commands (new, goto, sort, normalise).
- Tables: in-cell
=/:=formulas, formula editor, sort, transpose, CSV import/export,<N>shrink. - Narrowing,
org-goto, sparse trees /org-occur(reuse the FTS and tag matcher), speed keys. - Property delete,
_ALLcompletion, column view (read-only first). - Archive tag toggle, archive to sibling,
datetree/archive location. - 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. - Babel:
:sessionfor shells and python,:filewith inline image results (dot, plantuml, mermaid),:noweb,#+CALL, inlinesrc_. - Inline images (
file:links to images,#+ATTR_ORG: :width), toggled likeorg-toggle-inline-images. - Parser completions: radio targets,
$…$, LaTeX environments, entities and subscripts as objects, inline tasks, file-level property drawer, alphabetical bullets,#+TAGS/#+CONSTANTS/#+COLUMNS/#+LINK/#+MACRO. #+STARTUPbeyond visibility (indent,logdone,hidestars,align),VISIBILITYproperty.- Conflict and Syncthing-copy diff view; recovery folder browser.
- Vim: macros, marks, jumps,
gv, block visual, surround, commentary, evil-org text objects,:e/:bd/:bn. - 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
- Notarised build, Sparkle, Homebrew cask, Developer ID signing.
org-protocol://URL scheme and a Shortcuts/App Intents capture action; share extension later.- Spotlight importer and Quick Look extension for
.org. - Backlinks pane from the index's link rows; an ID graph is cheap once link resolution exists.
- Column view and clock reports as live sidebars rather than dynamic blocks.
- iCloud placeholders and
NSFilePresenterpath, then the iOS target: capture and agenda first, per the design. - 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-todowith logging,org-set-tags-command,org-capturedatetree,org-sort). - Prefer one plan per Tier 1 bullet, as the existing
docs/plansdo, 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.