84c72b6 antonApr 8, 2026 api

create TODO.md via macOS

A /sublimated/undefined +340 -0
1# obsidian plugin
2
3build an Obsidian community plugin as a marketing/distribution channel. no signup required — plugin reads file metadata directly from xattrs set by FileProvider.
4
5consistency rule: VS Code plugin (src/vscode-sublimated/, v0.3.5, 2,951 LOC) is the reference implementation. both plugins must show the same information in the same format, adapted to each platform's UI. when adding features to either plugin, check the other for parity.
6
7related docs (in main sublimated repo):
8- https://sublimated.com/sublimated/docs/MARKETING/OBSIDIAN — plugin ideas, submission requirements, promotion channels, competitive research
9- https://sublimated.com/sublimated/docs/MARKETING/ZED_LANGUAGE_SERVER — language server design (shared API endpoints, feature set, comment anchoring)
10- https://sublimated.com/sublimated/docs/SDK/FILEPROVIDER_DATA_MODEL — FileProvider data model and sync status
11- https://sublimated.com/sublimated/docs/DEV/OPEN_IN — "open in" deeplink design
12- https://sublimated.com/sublimated/docs/KNOWLEDGE_BASE/OBSIDIAN — integration strategy, pain points, features
13
14## xattrs (existing)
15
16FileProvider already writes these on every synced file:
17- `com.sublimated.version#PS` — version number (integer)
18- `com.sublimated.commit#PS` — last commit hash
19- `com.sublimated.url#PS` — web link (sublimated.com/anton/blog/readme_md)
20- `com.sublimated.content-hash#PS` — BLAKE3 hash
21- `com.sublimated.id#PS` — item ID (stable across renames)
22- `com.sublimated.created-by#PS` — original author name
23- `com.sublimated.modified-by#PS` — last author name
24- `com.sublimated.modified-by-type#PS` — person/ai_agent/bot
25
26plugin reads these directly from filesystem. no API calls, no token, no signup for core features.
27
28## xattrs (new — add to FileProvider)
29
30- `com.sublimated.sync-status#PS` — synced/uploading/downloading/error (set by FileProvider during operations, more reliable than trying to read system badges)
31- `com.sublimated.space#PS` — space slug (so plugin knows which space without parsing paths)
32- `com.sublimated.branch#PS` — current branch name
33- `com.sublimated.modified-at#PS` — server-side timestamp of last change
34
35note: Finder's FileProvider sync badges (green checkmark, cloud arrow etc) are NOT readable by other apps — `NSFileProviderItemDecorating` is private IPC between FileProvider and Finder. the `sync-status` xattr is our workaround: FileProvider writes it, plugin reads it.
36
37alternative: `SF_DATALESS` flag via `stat -f "%Xf"` tells if file is cloud-only placeholder vs materialized locally. works for all FileProvider files but only gives binary downloaded/not-downloaded.
38
39## URI scheme: sublimated://
40
41registered in `apps/mac/Resources/Info.plist`. existing "open in" feature uses:
42```
43sublimated://open-in?tool=zed&type=file&path={contentPath}
44```
45
46already supports: Zed, Cursor, Claude Code, Codex, Amp. implementation in `apps/mac/Sublimated/URLHandler.swift`.
47
48### open in Obsidian (web -> local)
49
50add Obsidian as another tool in URLHandler.swift:
51```
52sublimated://open-in?tool=obsidian&type=file&path=blog/post.md
53```
54
55URLHandler resolves local FileProvider path (`~/Library/CloudStorage/Sublimated-{space}/{subpath}`) then opens:
56```
57obsidian://open?vault={vaultName}&file={relativePath}
58```
59
60web UI: add Obsidian to "OPEN IN" section in SharePopup.astro (next to Zed). show only when space has `.obsidian/` folder (detected from items table — .obsidian is synced or known to exist).
61
62### open on web (local -> web)
63
64plugin reads `com.sublimated.url` xattr -> opens `https://{url}` in browser. no URI scheme needed, just a browser open.
65
66## v1 scope
67
68### 1. sync status bar — DONE (basic), needs update
69
70done: basic text status bar, click to open on web, updates on file change
71missing (VS Code has these):
72- sync status icons: checkmark synced, up-arrow uploading, down-arrow downloading, ! error, warning conflict
73- visibility indicator: globe public, people shared, lock private
74- branch display (hide when `main`)
75- AI agent prefix: `by AI: name` when `modifiedByType === "ai_agent"` (vs plain `by name`)
76- `visibility` field missing from Obsidian's FileMetadata type (VS Code has 13 fields, Obsidian has 12)
77- target format: `sublimated: v12 · checkmark synced · by anton · feature-x · globe` (matches VS Code)
78
79### 2. version history — DONE (basic), needs update
80
81done: sidebar view, version list with number/author/timestamp, "view on web" link
82missing (VS Code has these):
83- group versions by day: "Today", "Yesterday", "X days ago", "Mon DD"
84- show commit message per version
85- diff viewer (click version to see diff against current)
86
87### 3. view on web — DONE
88
89done: command palette + status bar click opens sublimated.com URL from xattr
90
91### 4. open in Obsidian (from sublimated.com) — DONE (plugin side)
92
93done: URI handler for `obsidian://sublimated?action=open&file=path` + OAuth token `action=auth`
94not done: web UI changes (add Obsidian to SharePopup.astro OPEN IN section), macOS app URLHandler.swift
95
96### 5. welcome modal — DONE
97
98done: first-run modal with setup steps, links, hasSeenWelcome flag
99
100### 6. settings page — DONE (basic)
101
102done: API token input, test connection, workspace detection (.sbl/ folder), links
103missing: OAuth sign-in button (see oauth-signin section below)
104
105### 7. file explorer decorations — NEW (VS Code has this)
106
107VS Code shows sync status badges on files in the explorer tree:
108- checkmark synced (no color), up-arrow uploading (blue), down-arrow downloading (blue), ! error (red), warning conflict (red)
109- Obsidian equivalent: FileExplorerPlugin API or CSS-based decorations on file tree items
110- read sync-status xattr per file, show badge/icon next to filename
111
112### 8. cache layer — NEW (VS Code has this)
113
114VS Code has `cache.ts` (85 lines) with in-memory cache for xattr reads and API responses. Obsidian plugin currently re-reads all xattrs on every file switch with no caching.
115- add TTL-based cache for xattr reads (avoid shelling out `xattr` 13 times on every tab switch)
116- cache API responses (folder context, file context)
117- invalidate on file save events
118
119### 9. workspace detection — needs update
120
121done: checks for `.sbl/` folder in vault root
122missing (VS Code has these):
123- CloudStorage mount path detection: `~/Library/CloudStorage/Sublimated-{space}/` (prod) and `~/Library/CloudStorage/sublimated-dev-{space}/` (dev)
124- `.sbl/config` or `.sbl/config.yml` parsing for space slug (VS Code reads plain text `space=...` or YAML `space: ...`)
125- detection result should include: space slug, folder path, root path, detection mode (cloud-storage vs sbl-config vs sbl-folder)
126
127### 10. comments and threads (VS Code has full implementation)
128
129VS Code: `comments/controller.ts` (513 lines) — native CommentController with gutter "+", threading, resolve/reopen, reactions, anchor resolution (text search -> line number -> top of file).
130
131Obsidian equivalent:
132- sidebar view: list all comments on the active file (anchored to specific text)
133- each comment shows: author, timestamp, quoted text, resolved/unresolved status
134- threaded replies shown inline under parent comment
135- clicking a comment scrolls to the anchored text in the editor
136- anchor resolution: same cascade as LSP — Loro cursors -> PM JSON blockId -> text search (quote+prefix+suffix) -> blockIndex -> orphaned
137- unresolved comments shown as notices/callouts or gutter markers
138- "resolve" button on each comment (API call, just a toggle)
139- "reply on sublimated.com" button opens browser at the thread
140- new comment creation happens on sublimated.com (no input forms in plugin)
141- API endpoint: GET /v1/spaces/{slug}/items/{id}/context (returns comments with FileAnchor)
142
143### 11. reactions
144
145- show reactions on file or section level in sidebar or status bar
146- hover or click to see who reacted
147- adding reactions happens on sublimated.com — plugin links to web UI
148- reactions are anchored to text via FileAnchor (same as comments)
149
150### 12. section-level history (VS Code has CodeLens equivalent)
151
152VS Code: `codelens.ts` (157 lines) — CodeLens above headings showing "last: {author}, {timeAgo}" and version/comment counts. Obsidian has no CodeLens, so use different UI.
153
154- command palette: "sublimated: show section history"
155- for each heading in the current file, show: last author, edit count, actor count
156- sections derived from AST (heading boundaries)
157- useful for long docs — see which sections changed recently and by whom
158- API provides this via file context endpoint (sections array with lastAuthor, editCount, actorCount)
159
160### 13. hover and diagnostics (VS Code has these, Obsidian needs equivalents)
161
162VS Code: `hover.ts` (163 lines) — wikilink hovers showing file info (versions, comments, backlinks). `diagnostics.ts` (104 lines) — broken link warnings, unresolved comment indicators.
163
164Obsidian equivalent:
165- reading view: render broken `[[links]]` with visual indicator (strikethrough, red text)
166- sidebar or notice: list unresolved comments with context
167- hover on wikilinks (if Obsidian API supports it): show version count, last author, comment count
168
169### 14. block attribution (PM JSON)
170
171- sidebar or hover: per-paragraph attribution
172- each block (PM JSON blockId) shows: original author, creation date, edit count, last editor
173- requires PM JSON representation (block IDs stable across edits)
174
175### 15. character-level attribution (Loro)
176
177- deeper attribution: percentage breakdown of who wrote what in a paragraph
178- distinguishes human vs AI edits
179- Loro CRDT tracks character-level authorship
180- could render as colored highlights in reading view (different color per author)
181
182### 16. @mention rendering
183
184- render `@username` as styled inline elements (colored, linked)
185- clicking @mention opens that user's profile on sublimated.com
186- in editing mode: autocomplete dropdown when typing `@` (users with access to the space)
187- API provides user list via folder context endpoint
188
189### 17. stale content detection
190
191- embedded files (`![[data.csv]]`, `![[report.md]]`) checked for staleness
192- if referenced file changed since current file was last edited, show notice
193- uses content-hash xattr on referenced file vs stored hash at embed time
194
195### 18. activity tracking
196
197- plugin sends editor events to API as they happen (same as LSP):
198 - file opened, content changed (with position info), file saved, file closed
199- API endpoint: POST /v1/spaces/{slug}/items/{id}/events
200- server computes section-level focus data from change positions
201- powers writing analytics: time spent editing vs reading per section
202
203### 19. backlinks
204
205- sidebar view: list all files that link to the current file via `[[wikilinks]]`
206- each backlink shows: file path, link context (surrounding text), version count, last author
207- clicking a backlink opens that file
208- data from item_dependencies table (dep_type = 'links_to')
209- Obsidian has native backlinks but sublimated adds: version count, author info, comment count per linking file
210
211### 20. broken link detection
212
213- `[[links]]` pointing to nonexistent files flagged in reading view or sidebar
214- offer to create the missing file
215- also detects broken content embeds (`![[missing.png]]`)
216- uses folder context items list to check existence
217
218## implementation work
219
220### plugin — exists, needs updates
221
222existing: TypeScript + esbuild, main.ts + manifest.json + styles.css, plugin ID `sublimated`
223existing: xattr.ts (reads 12 attrs), api.ts (versions + test connection), settings.ts, version-view.ts, welcome-modal.ts
224
225immediate work (VS Code parity for status bar):
226- add `visibility` to FileMetadata in xattr.ts (13th field, matching VS Code)
227- update status bar format to match VS Code: icons, visibility, branch, AI prefix
228- add cache layer (new cache.ts) for xattr reads and API responses
229- update workspace detection: CloudStorage mount path, `.sbl/config` parsing
230- add file explorer decorations (sync badges)
231
232later work:
233- comments sidebar (equivalent of VS Code's CommentController)
234- section-level info (equivalent of VS Code's CodeLens)
235- hover/diagnostics (equivalent of VS Code's hover + diagnostics providers)
236- API client: expand to match VS Code's api.ts (folder context, file context, editor events, comments)
237
238### FileProvider changes (sdk/swift/)
239- add 4 new xattrs: sync-status, space, branch, modified-at
240- add visibility xattr (already in VS Code constants.ts but needs FileProvider to set it)
241- set sync-status during upload/download/error operations in SublimatedFileProviderExtension.swift
242
243### web UI changes (sublimated.com worker)
244- add Obsidian to OPEN IN tools in SharePopup.astro (with Obsidian icon)
245- detect `.obsidian/` folder presence to show/hide the button
246
247### macOS app changes
248- add `obsidian` case to URLHandler.swift tool router
249- resolve path -> `obsidian://open?vault={vault}&file={path}`
250
251### API (api.sublimated.com)
252- same endpoints as language server:
253 - GET /v1/spaces/:slug/items/:folderId/context — folder context (items, links, users)
254 - GET /v1/spaces/:slug/items/:id/context — file context (comments, versions, sections, blocks, attribution, reactions, session)
255 - POST /v1/spaces/:slug/items/:id/events — editor events (open, change, save, close)
256 - POST /v1/spaces/:slug/messages — comment resolve
257- plugin uses folder context on vault open, file context on note open
258- editor events sent as user interacts (same as LSP)
259
260## OAuth sign-in
261
262add OAuth redirect flow so users can sign in with one click instead of pasting API tokens.
263
264how it works:
2651. user clicks "Sign in with sublimated" in plugin settings
2662. plugin opens browser to `id.sublimated.com/auth/obsidian`
2673. user signs in (GitHub, Apple, email — whatever id.sublimated.com supports)
2684. after sign-in, server redirects to `obsidian://sublimated?action=auth&token={sessionToken}`
2695. plugin URI handler catches the redirect, stores the token
2706. API calls use `Authorization: Bearer {token}` — same as the macOS app
271
272server-side: add GET `/auth/obsidian` route to id.sublimated.com. bearer plugin already set up.
273plugin-side: `main.ts` already handles `obsidian://sublimated?action=auth&token=...` in handleUri(). settings.ts needs a "Sign in" button that opens the browser URL.
274
275notes:
276- keep manual API token input as fallback
277- token should be long-lived (months/never) since there's no session refresh in Obsidian
278- consider scoped access token (read-only, specific space) vs full session
279
280## submission
281
282- source of truth: https://sublimated.com/sublimated/code/obsidian (dogfooded on our own platform)
283- GitHub mirror for submission: https://github.com/sublimates/obsidian — Obsidian community plugins require a GitHub repo URL in community-plugins.json. keep sublimated.com as primary, push to GitHub for releases
284- PR to obsidianmd/obsidian-releases adding entry to community-plugins.json
285- must work on Windows, macOS, Linux (xattr features macOS only, degrade gracefully)
286- automated validation + manual review
287- README with screenshots, description, setup instructions
288- stale PR policy: 30 days warning, 45 days auto-close
289
290## cross-platform notes
291
292- xattrs are macOS only — on Windows/Linux plugin works in API-only mode (token required for everything)
293- FileProvider is macOS only — but version history and "view on web" work everywhere with API token
294- status bar degrades: on non-mac, show "sublimated" with link to web, no local sync/version info
295
296## open questions
297
298### git-only users (no FileProvider)
299
300what if someone clones via `git clone https://sublimated.com/slug.git` and opens the clone as an Obsidian vault? no FileProvider means no xattrs, no sync status, no `.sbl/` detection. options:
301- plugin detects `.git/` with sublimated remote URL instead of `.sbl/` folder
302- shell out to `git log`, `git status`, `git diff` to show version/sync info
303- show unsynced changes by running `git status` — dirty files = unsynced
304- push/pull via git commands from within the plugin
305- this is a separate mode from FileProvider mode — need to detect which one we're in
306
307### auto-push
308
309should the plugin offer auto-push in settings? when user saves a file:
310- run `git add . && git commit -m "auto" && git push` in background
311- or debounce: push every N minutes if there are uncommitted changes
312- risk: merge conflicts if someone else pushes. how to handle?
313- could be opt-in toggle in settings: "auto-sync" on/off, with interval selector
314- only makes sense for git-clone mode — FileProvider already syncs automatically
315
316### sessions, checkpoints, and focus mode
317
318the macOS app tracks editing sessions with checkpoints, focus mode, and attribution (human vs AI edits). how does this surface in Obsidian?
319- session sidebar: show active session with elapsed time, word count delta, checkpoint list
320- checkpoints: auto-snapshot at intervals or on save. "restore checkpoint" command to revert to a point-in-time
321- focus mode: start/stop focus session from command palette. track uninterrupted writing time, words written
322- attribution: show which parts were edited by human vs AI agent (inline highlights or gutter marks)
323- this is a differentiator vs plain Obsidian — writing analytics and session tracking built into the sync layer
324
325### sharing and access visibility
326
327shared/public folders and files should be visible in Obsidian:
328- status bar: show sharing status alongside sync info
329- file explorer decorations: small icon (people, globe) next to shared/public files and folders
330- command: "sublimated: show access" — opens panel showing who has access, roles, visibility
331- needs: `com.sublimated.visibility#PS` xattr (private/shared/public) and optionally `com.sublimated.shared-with#PS`
332- API endpoint: `GET /v1/items/{id}/access` for detailed access panel
333
334## promotion
335
336- r/ObsidianMD (https://www.reddit.com/r/ObsidianMD/)
337- Obsidian Forum "Share & showcase"
338- Obsidian Discord #updates
339- twitter #ObsidianMD
340- blog post: "how to use Obsidian with sublimated"