* Extension tasks run through the host: spacedrive_op, task.begin/end with deadline, manifest grants parsed strictly
JobContext::run executes a #[task] with the retries and timeout the attribute
declares. The host records each attempt in the job log and enforces the
deadline: once it passes, every host operation the task makes fails with
timeout, which is the only way a single-threaded guest can be stopped.
spacedrive_op is the one import every data-returning operation goes through;
the answer is written into memory from the guest's own wasm_alloc. The old
spacedrive_call, its fixed-offset writer and the Wire-method permission model
go; ManifestPermissions is the grant shape photos declares (read_records,
read/write_sidecars, write_tags, write_custom_fields, dispatch_jobs,
use_models) and refuses unknown fields.
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
* Entropy and clock host functions
wasm32-unknown-unknown has neither. spacedrive_random fills guest memory
from the host's RNG and the SDK installs it as getrandom's custom backend,
so Uuid::new_v4 and rand work in a guest built with
--cfg getrandom_backend="custom". spacedrive_now_ms is the host's clock
behind spacedrive_sdk::clock::now(), which replaces Utc::now() in guests.
Neither needs a manifest grant: random ids and the time are not library
data.
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
* Records replace entries in the SDK, read from the library's source stores
The entry world is gone, so the SDK's query and read surface is defined
over source-store records: Record (uuid, source, name, kind, extension,
source-relative path, size, mtime, content uuid), get_record, read_record
and a RecordQuery narrowed by source, directory and extension. The host
answers from the stores of the job's library and reads bytes through the
source's resolved root; the manifest's read_records grant (its glob names
extensions) is checked on every call. A tag filter is refused rather than
ignored until tags have a host side.
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
* Sidecars for extensions, keyed by content uuid and an extension-declared kind
SidecarKind opens: Extension { extension_id, kind } beside the core kinds,
living under extensions/<id>/<kind> in the library's content-addressed
sidecar tree (sd-sidecar-path owns the directory), so an extension's kinds
never collide with the core's or another's. The SDK's sidecar_exists,
save_sidecar and read_sidecar write and read one JSON document per content
and kind; write_sidecars in the manifest grants writing, read_sidecars or
the extension's own write kinds grant reading. save_sidecar drops its
extension id argument, since the host supplies the namespace.
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
* Extension data models: #[model] facets in an extension-owned store
#[model] derives a facet definition from the struct (strings and uuids,
integers, floats, booleans, datetimes; anything else as json) and
#[extension(models = [...])] declares each one to the host in plugin_init.
The host collects them into a DataTypeSchema and opens an sd-store database
under <library>/extensions/<extension id>/ on the first model operation:
the same record and facet shape as a source store, owned by the extension,
which is the store the extension-kinds plan registers as an app-owned
source later. create_model, get_model and update_model key a model by its
own uuid; the _for_content and _by_content forms key it by the content it
describes; query_models lists (filters are refused until a host side
exists). sd-store gains facet_rows, which reads a model's declared fields
back with their types.
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
* AI inference answers not_available; config.get; photos handles a missing detector
ctx.ai() calls go to the host as ai.infer with the model id, task and raw
input. The host checks the manifest's use_models grant and then, since the
core has no provider for face detection, scene classification, embeddings
or language models, answers not_available naming the category; nothing
builds inference here. analyze_photos handles it: one warning, the photo
keeps no faces sidecar so a later run with a provider picks it up, and the
job completes. config.get serves config.json beside the manifest (or {})
behind ctx.config::<C>(), which the clustering task reads. The photos
extension's DBSCAN and person matching are implemented over the model
store so the job runs to its end instead of a todo!().
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
* extension: fixture library and end-to-end acceptance for host functions
The test extension gains a catalog job that reads every record of the
library's sources, digests each file through a task, writes a digest
sidecar and a CatalogEntry model, and skips what a previous run already
digested. The acceptance suite builds a library with twelve JPEG-magic
files and two text files, runs catalog twice, then runs the photos
extension's analyze_photos over the same library and asserts the
not_available path: one warning, no faces sidecar, every task attempt
logged.
Checkpointed guest state now tolerates fields added since the
checkpoint was written (serde(default) on the state structs), and
SourceDb::facet_rows numbers every bind parameter: sqlx binds a bare ?
after a ?N by position, so the external id landed in LIMIT.
Regenerates the TypeScript types for the SidecarKind::Extension variant.
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
* docs: extension host functions phase 1
The extension README describes spacedrive_op, the operations table and
the model registry in place of permissions.rs and spacedrive_call. The
SDK reference records the Entry to Record rename, the save_sidecar
signature, what has a host side and what does not. The extension READMEs
show the manifest permissions shape and the record, sidecar and model
calls that run today. PROJECT_STATUS gains the phase 1 register row.
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
* extension: grant checks fail closed; guest identifiers validated
A read_records glob the parser cannot read used to mean no filter for
records.query and no access for records.get, so the manifest is refused
at load unless the glob ends in *.ext or *.{a,b}, and granted_extensions
names nothing for anything else. The loader also refuses an extension id
that is not one path-safe segment, since it becomes a directory under
the library for sidecars and the model store. register_model checks
every field name as an identifier (and refuses record_uuid, the facet
key) because the guest can hand it any JSON. spacedrive_random resolves
the guest slice before allocating the entropy buffer.
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai-staging[bot] <305915985+capy-ai-staging[bot]@users.noreply.github.com>
Spacedrive
Your data should not have to live on somebody else's computer to be useful.
Download • Docs • Discord • Build from source
Important
Spacedrive 2.0 Beta is planned for November 1, 2026.
Beta commits to Spacedrive's data model and to preserving your library as it evolves. The release makes self-owned storage practical across your devices. It brings portable source indexes, private remote access, mounts, history, extensions, and one API for people and software.
Nightly CLI and daemon builds are available now from the nightly release. They are unsigned, move with every push to
main, and can break, so keep backups of any library you point them at. See Install a nightly. The beta will appear on the releases page when it ships.
Spacedrive is open personal data infrastructure. It turns the storage you control into one private filesystem across your devices, drives, servers, and the clouds you choose.
Bring your data home without giving up search, protection, intelligence, sharing, or access from anywhere. No hosted account, no vendor control plane, no telemetry.
Own where your data lives
Cloud services made it feel normal for your files to live on someone else's computer. Personal files and behavioral data piled up on infrastructure whose security, policies, and future you do not control. Automated attacks increase the scale of that exposure. AI increases the value of accumulated data for training, inference, and profiling.
Owning the drive is the easy part. You still need to find files, reach them from another device, know what is backed up, recover earlier states, share on your terms, and notice when something changes.
Spacedrive does all of that while you decide where the bytes and metadata live. Local disks, removable media, NAS datasets, private servers, and offline archives are first-class homes. Cloud services remain optional sources and destinations.
Read the Product Direction for the complete product boundary.
One filesystem, every source
A source can be a folder, a complete drive, a dataset on your NAS, another Spacedrive node, a cloud bucket, or an external service. Every source uses the same record shape and the same operations.
Each source has a portable store with two kinds of knowledge: a generation that can be refreshed while the origin is available, and durable assertions that cannot be reconstructed from the files alone. Disconnect a drive and its catalog remains searchable. Move a source to another machine and its metadata can travel with it.
- A live index. Watchers keep names, sizes, timestamps, and content state current, so opening a folder never rescans the disk.
- Search across boundaries. One search runs across local, remote, cloud, and adapter sources.
- Stable identity. Records survive moves. BLAKE3 content identities connect copies of the same bytes across sources and devices.
- Fast duplicate detection. Sampled hashes find candidates quickly. Full-byte verification confirms equality before destructive cleanup.
- History that stays useful. Freeze a source at a point in time, browse an offline snapshot, and inspect which operation changed it.
- Provider exit. Move data away from a service without losing the organization, tags, history, and knowledge built around it.
Protection is part of the filesystem
Keeping files safe is filesystem work.
- Track integrity, redundancy, backup state, capacity, and unexpected changes.
- Distinguish independent copies using physical drives, pools, and failure domains.
- Keep an inventory of drives that are offline, archived, lost, or retired.
- Preserve unreadable records with their error instead of omitting them.
- Run indexing, metadata extraction, previews, and search on infrastructure you control by default.
- Name every external recipient before file content or derived metadata leaves your devices.
An index snapshot preserves evidence about the filesystem. Provider versions and backups preserve the bytes. Spacedrive connects the two so you can understand what existed, where it lived, and how to recover it.
See every change before it happens
The everyday threat to your files is an operation: a copy that overwrites the wrong folder, a cleanup that deletes the last copy, a merge that lands somewhere unintended. A durable filesystem protects your files from its own operations.
Every operation that changes files answers two questions before it runs. Validation answers whether it may run and how: permissions, capacity, safety rules, and the exact strategy, enforced by the daemon rather than the dialog. Preview answers what will exist afterward, projected from the index without touching a file.
- Browse the result before it exists. A preview serves the same listings as the present filesystem, so you walk the outcome folder by folder before a byte moves.
- Plan against offline storage. The index answers for a drive sitting in a drawer, so you can prepare a merge before you plug anything in.
- Get warnings only an indexed filesystem can give. Three of these files are the last copy of their content anywhere in your library.
- Skip duplicates on proof. A file is treated as a copy only after full-byte verification, never on a sampled hash.
- Trust the execution. The daemon re-validates at dispatch, applies the same policy against the live filesystem, and reports any divergence from the plan.
Access anything from anywhere
Pair Spacedrive nodes to browse and operate their authorized sources through the same interface. A live node serves queries, snapshots, byte ranges, jobs, and logs. Other nodes can cache projections and content without claiming authority over the source.
Share a source or subtree with another person, device, or agent without merging libraries. The host decides what the recipient can see and do. The grant stays visible and revocable, while the recipient sees the shared data beside their own sources.
Mount any source or subtree into macOS, Windows, or Linux. Files stream on demand from a local disk, another device, or a cloud provider through one byte plane. Range reads power mounts, transfers, previews, media playback, and video scrubbing without copying the whole file first.
Peer connections use Iroh and QUIC with end-to-end encryption. Devices connect directly when they can and fall back to relays when they must.
One API for people and software
The desktop app, web interface, mobile clients, CLI, generated SDKs, skills, and MCP server all call the same registered operations. A copy has the same input, progress, conflicts, and result whether a person clicks it or software invokes it.
- Operations return structured data and stable identifiers.
- Validate, preview, and execute are the same three verbs for every operation and every client.
- Long-running work becomes a durable job with progress, cancellation, restart recovery, and logs.
- Remote clients can inspect the same job state through an authorized session.
- Capabilities are explicit, scoped, visible, and revocable.
Spacedrive does not bundle an agent or choose a model for you. Use the CLI, skill, SDK, or MCP server with the agent you trust. Your agent gains a consistent filesystem interface without becoming the owner of your data. An agent validates first, shows you the plan, and commits the exact input it previewed. That is what makes destructive file operations safe to delegate.
Extend the filesystem
The default installation stays small. Extensions add specialized support only when you need it.
An extension can contribute:
- A source adapter or storage backend.
- File recognition through extensions, MIME types, UTTypes, magic bytes, and provider metadata.
- Typed metadata and search fields.
- Preview renderers, thumbnails, proxies, video thumbstrips, and persistent sidecars.
- Registered jobs, actions, menus, settings, and focused views.
Platform bridges can discover handlers already registered with macOS, Windows, and Linux. Heavy codecs, provider SDKs, and models remain outside the default binary. Extensions install from explicit packages and declare the access they need.
Architecture
flowchart TB
people[Desktop, web, mobile, CLI]
software[SDKs, skills, MCP]
operations[Typed operation registry]
daemon[Spacedrive daemon]
stores[Source stores, history, jobs]
local[Local drives and NAS]
remote[Remote Spacedrive nodes]
cloud[Cloud providers]
adapters[Adapters and extensions]
people --> operations
software --> operations
operations --> daemon
daemon --> stores
daemon --> local
daemon --> remote
daemon --> cloud
daemon --> adapters
The Rust daemon owns filesystem identity, indexing, operations, policy, and durable work. Clients connect through JSON-RPC over local sockets or WebSockets. Network protocols use Iroh and QUIC. OpenDAL provides cloud storage backends. SQLite gives each source a portable store and FTS5 index.
Core operations are registered at compile time with type-safe inputs and outputs. Specta generates the TypeScript and Swift clients from those Rust types, so every interface shares one contract.
Install a nightly
The nightly release
carries sd and sd-daemon for macOS ARM64 (macos-aarch64) and Linux
x86-64 (linux-x86_64), each with a .sha256 file. Download both binaries
for your platform, verify them, and put them in a directory on your PATH:
shasum -a 256 -c sd-macos-aarch64.sha256 sd-daemon-macos-aarch64.sha256 # sha256sum -c on Linux
chmod +x sd-macos-aarch64 sd-daemon-macos-aarch64
mv sd-macos-aarch64 ~/.local/bin/sd
mv sd-daemon-macos-aarch64 ~/.local/bin/sd-daemon
sd daemon install
To let sd keep itself on the latest nightly:
sd config set update.channel nightly
sd update --yes
sd update install-timer
The binaries are not signed with a Developer ID. On macOS, a browser download
carries the quarantine attribute and Gatekeeper refuses to run it until you
remove it with xattr -d com.apple.quarantine sd sd-daemon. Nightly builds
follow main and can break or change schemas without migrations, so keep
backups of any library you point them at.
Build from source
You need Rust 1.95 or newer (rust-toolchain.toml pins 1.97.1),
Bun 1.3.4 (the version package.json and CI pin; a newer
Bun rewrites bun.lockb), Node 20, and
just.
git clone https://github.com/spacedriveapp/spacedrive
cd spacedrive
# Installs system dependencies on macOS, Linux, or Windows.
./scripts/setup.sh # .\scripts\setup.ps1 on Windows
bun install
cargo run -p xtask -- setup
Run the daemon and your preferred client:
just dev-daemon # Rust daemon
just dev-desktop # Desktop client
just dev-server # Headless server and web interface
just dev-mobile # Mobile client
The sd-ffmpeg crate is a default workspace member and links the FFmpeg
development libraries installed on the host (libavutil, libavformat,
libavcodec, libavfilter, libavdevice, libswscale, libswresample) and
uses libclang to generate its bindings. scripts/setup.sh installs them
(libav*-dev and libclang-dev on Debian and Ubuntu, ffmpeg on Homebrew).
Without them the first cargo build fails in ffmpeg-sys-next with
libavutil.pc not found.
The default build can use FFmpeg installed on the host for video thumbnails and thumbstrips. Install the native codec bundle only when developing code that links the optional FFmpeg, libheif, or Pdfium libraries:
cargo run -p xtask -- setup --native-deps
Run the checks before submitting a change:
just test
just check
See the documentation for deployment, source, extension, and architecture guides.
Project history
Spacedrive began in 2021 as one interface over files scattered across devices and cloud accounts. The first public version proved the demand and exposed the cost of carrying two file models, fragile transfers, and too much product in the default build.
V2 rebuilds the project around sources, portable stores, durable jobs, and one typed operation surface. Read the project history for the full account.
Contributing
- Read the Contributing Guide.
- Join the Discord community.
- Build a source adapter with the Archive and Adapters guide.
- Contribute to the shared interface system in SpaceUI.
License
Releases before 2026-03-24 were published under AGPL-3.0 and remain available under that license.

