Why
The companion to #507. That issue wraps Solid behind WebDAV — universal but loses Solid's distinctive features. This one exposes Solid natively: a FUSE filesystem driver that speaks Solid as its native protocol and surfaces what makes Solid Solid.
The pitch: this is the mount that lets getfattr -n user.solid.acl /mnt/alice/diary.md return the actual ACL doc, and lets inotifywait /mnt/alice/inbox/ block on the pod's real-time /.notifications stream. Once these become filesystem-native, every tool that knows about xattrs and inotify (Nautilus included) inherits the integration for free.
Shape
solidfs mount https://alice.solidcommunity.net /mnt/alice
fusermount -u /mnt/alice
Standard FUSE ops on top of Solid HTTP:
getattr → HEAD upstream, cache briefly
readdir → GET with Accept: application/ld+json, parse ldp:contains
read → GET with Range
write → buffer + PUT on flush (or chunked via PATCH if the server supports it)
create → PUT empty body with content-type from filename
unlink → DELETE
mkdir → LDP POST with Slug + Link: <ldp#BasicContainer>
rmdir → walk + DELETE (LDP needs empty containers)
rename → GET + PUT + DELETE (LDP has no MOVE)
Solid features as first-class filesystem properties:
| Solid concept |
FS surface |
| Container |
Directory |
| Resource |
File |
ACL (<r>.acl) |
xattr user.solid.acl (read/write the JSON-LD doc) |
| WAC-Allow |
xattr user.solid.permissions (effective modes for current identity) |
JSON-LD @type |
xattr user.solid.type |
/.notifications WS |
inotify events on the mountpoint |
| Solid-OIDC identity |
xattr user.solid.webid at mount root |
| Cross-pod link |
symlink with magic target solid://<url> |
Bonus once notifications are wired: Nautilus auto-refreshes when a collaborator writes a file. No explicit reload.
Tradeoffs
- ✓ Solid features (ACL, types, notifications) are first-class, not lost in translation
- ✓ Better performance (no protocol shim)
- ✓ Standard Unix tools (
stat, getfattr, inotifywait, find) just work
- ✗ Linux + macOS only out of the box (Windows needs WinFsp shim — possible but more work)
- ✗ Higher complexity than WebDAV; needs FUSE kernel module on Linux, macFUSE on macOS
- ✗ Distribution friction: Node +
fuse-native bindings, or a Rust/Go binary
Implementation options
- Node +
fuse-native — sits in the same ecosystem as JSS; cheapest spike. Performance OK for most uses.
- Rust +
fuser crate — production-quality, fast, single static binary. Better for rsync-of-pod scale.
- Go +
bazil.org/fuse — middle ground, good cross-compile story.
Node first is probably right: prove the model, then port hot paths if needed.
Open questions
- Caching policy: getattr fires per-stat; need short-TTL cache (~1s) plus invalidation on notifications.
- Write semantics: write-on-flush vs streaming. Solid PUT is whole-resource, so partial writes need buffering. Big files = big memory unless we PATCH (server-dependent).
- ACL edits via xattr: writing
user.solid.acl should PUT to <resource>.acl. Clean API but a footgun if user pastes broken JSON.
- Auth refresh in long-lived mounts: same issue as the WebDAV bridge — needs a quiet renewal loop.
- Notifications → inotify mapping: pod events are JSON-LD; need a translation layer to IN_CREATE / IN_MODIFY / IN_DELETE.
Effort
~2000-3000 LOC for a first cut. Bigger than the WebDAV bridge but each line bought back is a Solid feature that survives the round trip.
Naming
solidfs or solid-mount. solidfs is shorter and the established convention (sshfs, s3fs).
Related
Why
The companion to #507. That issue wraps Solid behind WebDAV — universal but loses Solid's distinctive features. This one exposes Solid natively: a FUSE filesystem driver that speaks Solid as its native protocol and surfaces what makes Solid Solid.
The pitch: this is the mount that lets
getfattr -n user.solid.acl /mnt/alice/diary.mdreturn the actual ACL doc, and letsinotifywait /mnt/alice/inbox/block on the pod's real-time/.notificationsstream. Once these become filesystem-native, every tool that knows about xattrs and inotify (Nautilus included) inherits the integration for free.Shape
Standard FUSE ops on top of Solid HTTP:
getattr→ HEAD upstream, cache brieflyreaddir→ GET withAccept: application/ld+json, parseldp:containsread→ GET withRangewrite→ buffer + PUT on flush (or chunked via PATCH if the server supports it)create→ PUT empty body with content-type from filenameunlink→ DELETEmkdir→ LDP POST withSlug+Link: <ldp#BasicContainer>rmdir→ walk + DELETE (LDP needs empty containers)rename→ GET + PUT + DELETE (LDP has no MOVE)Solid features as first-class filesystem properties:
<r>.acl)user.solid.acl(read/write the JSON-LD doc)user.solid.permissions(effective modes for current identity)@typeuser.solid.type/.notificationsWSuser.solid.webidat mount rootsolid://<url>Bonus once notifications are wired: Nautilus auto-refreshes when a collaborator writes a file. No explicit reload.
Tradeoffs
stat,getfattr,inotifywait,find) just workfuse-nativebindings, or a Rust/Go binaryImplementation options
fuse-native— sits in the same ecosystem as JSS; cheapest spike. Performance OK for most uses.fusercrate — production-quality, fast, single static binary. Better forrsync-of-pod scale.bazil.org/fuse— middle ground, good cross-compile story.Node first is probably right: prove the model, then port hot paths if needed.
Open questions
user.solid.aclshould PUT to<resource>.acl. Clean API but a footgun if user pastes broken JSON.Effort
~2000-3000 LOC for a first cut. Bigger than the WebDAV bridge but each line bought back is a Solid feature that survives the round trip.
Naming
solidfsorsolid-mount.solidfsis shorter and the established convention (sshfs,s3fs).Related
solid-apps/explorer— same primitives, but in the browser