Type: Architecture / Documentation / UX
Severity: Conceptual (suspected root cause of many usability reports)
TL;DR
After several hours configuring Make.md from scratch in a real working vault (5,000+ notes, several symlinked external folders) and then reading the source carefully, I came away convinced:
A Space is a queryable subset of a vault — defined by folder, by tag, by the whole vault, or by an arbitrary saved query — rendered through views (table/board/calendar/gallery), with user-defined typed columns (contexts) and optional custom frames.
In other words: Notion-style databases where the "database" is any slice of your vault.
That is a genuinely ambitious and genuinely useful idea — Dataview + Bases + Kanban + a frame engine, unified. But the README markets it as "folders with extra powers," and the in-product UI reinforces the smaller framing. New users build the wrong mental model on day one and never recover.
This issue argues that the gap is conceptual scaffolding and a handful of small UX affordances, not a rewrite.
The model I reverse-engineered from source
Reading src/shared/types/PathState.ts, src/shared/types/spaceInfo.ts, src/shared/types/spaceDef.ts, src/core/types/space.ts, and src/core/spaceManager/filesystemAdapter/, the actual model is:
| Entity |
Definition |
How it surfaces |
PathState |
Any addressable node — file, folder, tag, virtual entity — plus its memberships (spaces, linkedSpaces, liveSpaces) |
The "rows" in a Space |
SpaceInfo / FilesystemSpaceInfo |
A Space's static on-disk location: path, defPath, notePath, and (on the FS subtype) folderPath, dbPath, framePath, commandsPath |
6+ artifacts on disk per Space |
SpaceDefinition |
A Space's behavior: contexts, sort, joins, links, tags, template, ... |
Folder-note YAML (_contexts, _joins, _links, _sort, _template) |
SpaceType |
'folder' | 'tag' | 'vault' | 'default' | 'unknown' |
Five fundamentally different containers, same UI chrome |
waypoints.json (Focus[]) |
List of pinned top-level Spaces — each a { name, sticker, paths: string[] } |
The Spaces sidebar's pinned rail |
PathState.spaces vs linkedSpaces vs liveSpaces |
Three membership-like arrays; their distinct semantics are undocumented in the type |
Indistinguishable in the UI |
A single working folder-Space therefore depends on the consistency of:
- A real folder on disk (for folder-typed Spaces)
- A folder note (
<name>.md) carrying SpaceDefinition in frontmatter
- A
.space/ subfolder with views.mdb / context.mdb (SQLite, via sql.js)
- A
waypoints.json entry (if pinned)
- A
PathState entry in .makemd/superstate.mdc
- The
.makemd/fileCache.mdc index being current
- Inverse references (
linkedSpaces) on every member path
That's seven artifacts. Any one can drift silently. When any drift, the Space "looks empty" with no diagnostic.
Confusions we hit, mapped to causes
| Symptom |
Root cause in the model |
Created a Space via UI named n8n docs → it's empty |
The paths value was a display-style label, not a resolvable folder path |
| Symlinked folders never appear in the Spaces panel even though they appear in Obsidian's native file explorer |
Make.md inherits whatever Obsidian's vault API returns; symlinks that Obsidian's adapter excludes are invisible to Make.md too, with no warning or alternative path |
| Vault changes made while Obsidian is closed aren't reflected on next launch |
.makemd/fileCache.mdc and .makemd/superstate.mdc are persisted and trusted on startup; in-session events are handled, but there's no reconciliation pass on load |
| No command palette entry to reindex / rescan |
None implemented, even though a superstateReindex event already exists internally (dispatched from superstate.ts) |
| Adding a file to a Space is non-obvious for new users |
The command mk-pin-active ("Pin Active File to Space") exists and works — but its name doesn't surface the "add to Space" concept that new users are searching for |
waypoints.json schema bundles all pinned entries without distinguishing their role |
The paths: string[] field carries the pinned target(s) flatly, without separating "the Space's home" from any reference scoping |
The vault-root Spaces/ folder feels magical |
It's just a default container, but new users assume all Spaces must live inside it |
Proposed changes — small, surgical, high-leverage
Each of the following closes a documented class of confusion.
1. A Concepts doc, linked prominently from the README
One page. The framing sentence at the top:
A Space is a queryable subset of your vault — defined by folder, by tag, by the whole vault, or by an arbitrary query — rendered as a view, with optional typed columns.
Then the table above, plus three diagrams: (a) the seven artifacts of a folder-Space, (b) Path→Space membership via the three relationship types, (c) which file stores what. This single page would do more for adoption than any code change.
2. Make.md: Reindex vault command
The single highest-leverage UX win, and almost free to implement: the superstateReindex event is already wired internally and dispatched from superstate.ts. A command palette entry that clears fileCache.mdc + superstate.mdc, triggers a re-walk, and emits the existing reindex event (plus a Notice with progress) would be a thin wrapper over machinery that already exists.
Many "everything is empty after I did X" reports would resolve themselves the first time a user runs this — especially for users (like me) whose vault changed between Obsidian sessions.
3. Treat symlinks as a first-class question
Make.md's filesystem adapter doesn't independently resolve symlinks — it delegates to Obsidian's vault API. For users whose vault contains symlinked external project trees, this means whole folder subtrees can be invisible to Spaces while still visible in Obsidian's own file explorer (which traverses them just fine), with no diagnostic.
Two reasonable directions:
- Document the dependency explicitly: "Make.md indexes only what Obsidian's adapter exposes; symlinks behave as Obsidian configures them."
- Or add an optional
followSymlinks setting that bypasses the Obsidian adapter for known mount points (with a depth cap to prevent loops) and feeds those paths into the index.
Even just a warning chip in the Spaces panel for "this Space's folder appears to be a symlink — make sure your vault adapter is configured to follow it" would close a real gap.
4. Disambiguate spaces / linkedSpaces / liveSpaces in PathState
These three arrays carry distinct membership semantics in the implementation, but the type itself documents none of them — and they all look the same in the UI. Either rename for clarity:
type PathState = {
containedInSpaces: string[]; // physical parent
linkedFromSpaces: string[]; // someone _links to me
queriedIntoSpaces: string[]; // I match a Space's joins/filters
...
}
…or unify into one field with a per-edge type tag:
spaceMembership: { spacePath: string; via: 'contained' | 'linked' | 'query' }[]
The latter would also let the UI become honest: hovering a row in a Space view could show why that row is there. For a Notion-style database where membership rules can be subtle, this is critical — and for the source, it would replace a load-bearing tribal-knowledge split with a documented one.
5. Surface SpaceType in the UI
Five fundamentally different containers (folder, tag, vault, default, unknown) appear to share the same sticker, menu, and property pane. A small chip or distinct icon per type would let users immediately recognize what kind of container they are looking at — and would also signal the system's full power to users who currently only see "fancy folders."
6. Promote Pin Active File to Space as the "Add to Space" affordance
The command exists and does the right thing — it just isn't named in the language users search for. Two cheap improvements:
- Rename or alias the command to
Make.md: Add active file to Space (keeping the old name as an alias for compatibility).
- Surface it from the file context menu and from a Space's "+" button as "Add file to this Space…" rather than only as a draggable affordance.
The existence of mk-pin-active is one of the clearest demonstrations that the model is sound and the discoverability gap is the real issue.
7. Make.md: Diagnose this Space command
Walks the seven artifacts and reports which are present / missing / stale. Even a simple Notice saying "Space 'X' is missing its folder note" or "Space 'X' has no .space/views.mdb — recreate?" would close a large class of "it looks empty" reports.
Why one issue instead of seven
These problems get reported individually as bugs, but they share a single root cause: users don't know the data model exists. A Concepts page, a Reindex command (which is mostly wrapping an existing event), a Diagnose command, and a rename of Pin Active File to Space would, I suspect, dramatically reduce the rate of new confusion reports — and would let new users perceive the actual ambition of the system instead of mistaking it for a folder skin.
I'd be happy to take a first pass at the Reindex vault command and the Concepts doc as a PR if maintainers think these directions make sense. Before writing code I'd love to know:
- Is the
spaces / linkedSpaces / liveSpaces split intentional and load-bearing, or accreted? Would unification break the views / contexts pipeline?
- Is the README's "folders with superpowers" framing a deliberate audience choice (non-technical), or just unfinished? Happy to write the Concepts page in whichever register fits.
- Is there an existing internal design doc I missed?
Thanks for the work on this plugin. The data-model power is real and impressive — it just needs the conceptual scaffolding to land for users.
Related forum discussion: Make.md Spaces, Add files to Space in Make.md.
TL;DR
After several hours configuring Make.md from scratch in a real working vault (5,000+ notes, several symlinked external folders) and then reading the source carefully, I came away convinced:
That is a genuinely ambitious and genuinely useful idea — Dataview + Bases + Kanban + a frame engine, unified. But the README markets it as "folders with extra powers," and the in-product UI reinforces the smaller framing. New users build the wrong mental model on day one and never recover.
This issue argues that the gap is conceptual scaffolding and a handful of small UX affordances, not a rewrite.
The model I reverse-engineered from source
Reading
src/shared/types/PathState.ts,src/shared/types/spaceInfo.ts,src/shared/types/spaceDef.ts,src/core/types/space.ts, andsrc/core/spaceManager/filesystemAdapter/, the actual model is:PathStatespaces,linkedSpaces,liveSpaces)SpaceInfo/FilesystemSpaceInfopath,defPath,notePath, and (on the FS subtype)folderPath,dbPath,framePath,commandsPathSpaceDefinitioncontexts,sort,joins,links,tags,template, ..._contexts,_joins,_links,_sort,_template)SpaceType'folder' | 'tag' | 'vault' | 'default' | 'unknown'waypoints.json(Focus[]){ name, sticker, paths: string[] }PathState.spacesvslinkedSpacesvsliveSpacesA single working folder-Space therefore depends on the consistency of:
<name>.md) carryingSpaceDefinitionin frontmatter.space/subfolder withviews.mdb/context.mdb(SQLite, viasql.js)waypoints.jsonentry (if pinned)PathStateentry in.makemd/superstate.mdc.makemd/fileCache.mdcindex being currentlinkedSpaces) on every member pathThat's seven artifacts. Any one can drift silently. When any drift, the Space "looks empty" with no diagnostic.
Confusions we hit, mapped to causes
n8n docs→ it's emptypathsvalue was a display-style label, not a resolvable folder path.makemd/fileCache.mdcand.makemd/superstate.mdcare persisted and trusted on startup; in-session events are handled, but there's no reconciliation pass on loadsuperstateReindexevent already exists internally (dispatched fromsuperstate.ts)mk-pin-active("Pin Active File to Space") exists and works — but its name doesn't surface the "add to Space" concept that new users are searching forwaypoints.jsonschema bundles all pinned entries without distinguishing their rolepaths: string[]field carries the pinned target(s) flatly, without separating "the Space's home" from any reference scopingSpaces/folder feels magicalProposed changes — small, surgical, high-leverage
Each of the following closes a documented class of confusion.
1. A
Conceptsdoc, linked prominently from the READMEOne page. The framing sentence at the top:
Then the table above, plus three diagrams: (a) the seven artifacts of a folder-Space, (b) Path→Space membership via the three relationship types, (c) which file stores what. This single page would do more for adoption than any code change.
2.
Make.md: Reindex vaultcommandThe single highest-leverage UX win, and almost free to implement: the
superstateReindexevent is already wired internally and dispatched fromsuperstate.ts. A command palette entry that clearsfileCache.mdc+superstate.mdc, triggers a re-walk, and emits the existing reindex event (plus aNoticewith progress) would be a thin wrapper over machinery that already exists.Many "everything is empty after I did X" reports would resolve themselves the first time a user runs this — especially for users (like me) whose vault changed between Obsidian sessions.
3. Treat symlinks as a first-class question
Make.md's filesystem adapter doesn't independently resolve symlinks — it delegates to Obsidian's vault API. For users whose vault contains symlinked external project trees, this means whole folder subtrees can be invisible to Spaces while still visible in Obsidian's own file explorer (which traverses them just fine), with no diagnostic.
Two reasonable directions:
followSymlinkssetting that bypasses the Obsidian adapter for known mount points (with a depth cap to prevent loops) and feeds those paths into the index.Even just a warning chip in the Spaces panel for "this Space's folder appears to be a symlink — make sure your vault adapter is configured to follow it" would close a real gap.
4. Disambiguate
spaces/linkedSpaces/liveSpacesinPathStateThese three arrays carry distinct membership semantics in the implementation, but the type itself documents none of them — and they all look the same in the UI. Either rename for clarity:
…or unify into one field with a per-edge type tag:
The latter would also let the UI become honest: hovering a row in a Space view could show why that row is there. For a Notion-style database where membership rules can be subtle, this is critical — and for the source, it would replace a load-bearing tribal-knowledge split with a documented one.
5. Surface
SpaceTypein the UIFive fundamentally different containers (
folder,tag,vault,default,unknown) appear to share the same sticker, menu, and property pane. A small chip or distinct icon per type would let users immediately recognize what kind of container they are looking at — and would also signal the system's full power to users who currently only see "fancy folders."6. Promote
Pin Active File to Spaceas the "Add to Space" affordanceThe command exists and does the right thing — it just isn't named in the language users search for. Two cheap improvements:
Make.md: Add active file to Space(keeping the old name as an alias for compatibility).The existence of
mk-pin-activeis one of the clearest demonstrations that the model is sound and the discoverability gap is the real issue.7.
Make.md: Diagnose this SpacecommandWalks the seven artifacts and reports which are present / missing / stale. Even a simple
Noticesaying "Space 'X' is missing its folder note" or "Space 'X' has no.space/views.mdb— recreate?" would close a large class of "it looks empty" reports.Why one issue instead of seven
These problems get reported individually as bugs, but they share a single root cause: users don't know the data model exists. A Concepts page, a Reindex command (which is mostly wrapping an existing event), a Diagnose command, and a rename of
Pin Active File to Spacewould, I suspect, dramatically reduce the rate of new confusion reports — and would let new users perceive the actual ambition of the system instead of mistaking it for a folder skin.I'd be happy to take a first pass at the
Reindex vaultcommand and the Concepts doc as a PR if maintainers think these directions make sense. Before writing code I'd love to know:spaces/linkedSpaces/liveSpacessplit intentional and load-bearing, or accreted? Would unification break the views / contexts pipeline?Thanks for the work on this plugin. The data-model power is real and impressive — it just needs the conceptual scaffolding to land for users.
Related forum discussion: Make.md Spaces, Add files to Space in Make.md.