File: README.md
Spacedrive
What is Spacedrive?
Spacedrive is a cross-device data platform. Index files, emails, notes, and external sources. Search everything. Sync via P2P. Keep AI agents safe with built-in screening.
- Content identity โ every file gets a BLAKE3 content hash. Same file on two devices produces the same hash. Spacedrive tracks redundancy and deduplication across all your machines.
- Cross-device โ see all your files across all your devices in one place. Files on disconnected devices stay in the index and appear as offline.
- P2P sync โ devices connect directly via Iroh/QUIC. No servers, no cloud, no single point of failure. Metadata syncs between devices. Files stay where they are.
- Cloud volumes โ index S3, Google Drive, Dropbox, OneDrive, Azure, and GCS as first-class volumes alongside local storage.
- Nine views โ grid, list, columns, media, size, recents, search, knowledge, and splat. QuickPreview for video, audio, code, documents, 3D, and images.
- Local-first โ everything runs on your machine. No data leaves your device unless you choose to sync between your own devices.
Is this a replacement for Finder or Explorer?
No. Spacedrive sits above your OS file manager and adds capabilities Finder/Explorer lack:
- Portal across everything โ search and browse files across local disks, external drives, NAS, cloud storage, and archived data sources from one interface.
- Operating surface for files โ content identity, sidecars, derivative artifacts, rich metadata, sync, and cross-device awareness built into the core model.
- Embeddable and shareable โ run it as a desktop app, headless server, hosted file service, or embed the interface and APIs into other products.
- AI-ready by design โ indexing and analysis pipelines prepare data ahead of time instead of giving agents raw shell access.
- Safer access model โ route AI and automation through structured APIs, permissions, and processing layers instead of direct file operations.
You still use your OS for low-level file interactions. Spacedrive adds the cross-platform, cross-device, cloud-aware, and automation-friendly layer on top.
Data Archival
Spacedrive indexes external data sources via script-based adapters: Gmail, Apple Notes, Chrome bookmarks, Obsidian, Slack, GitHub, calendar events, contacts. Each source becomes a searchable repository alongside your files.
Adapters are a folder with an adapter.toml manifest and a sync script in any language. If it reads stdin and prints lines, it works.
Shipped adapters: Gmail, Apple Notes, Chrome Bookmarks, Chrome History, Safari History, Obsidian, OpenCode, Slack, macOS Contacts, macOS Calendar, GitHub.
Spacebot
Spacedrive integrates with Spacebot, an open source AI agent runtime. Spacebot runs as an optional separate process. Spacedrive provides the data, permission, and execution layer. Spacebot provides the intelligence.
Each Spacebot instance pairs with one Spacedrive node as its home device. That node authenticates the agent, maintains the device graph, resolves permissions, and forwards operations to peer devices. Every device in your library can reach Spacebot through the paired node over P2P (Iroh/QUIC) without direct network access. One agent runtime serves your entire device fleet.
When Spacebot spawns a worker, that worker can target any device in the library. File reads, shell commands, and operations proxy through Spacedrive to the target device. Talk to the agent from your phone while work executes on a server. Read files from a NAS, run commands on a workstation, report to a laptop โ all in one task.
Every operation passes through Spacedrive's permission system: which devices the agent can access, which paths are readable or writable, which operations are allowed, and which require human confirmation. The paired node resolves effective policy before forwarding. One security model, one audit surface across all devices and clouds.
File System Intelligence
Spacedrive adds intelligence to your filesystem by combining three layers:
- File intelligence โ derivative data like OCR, transcripts, extracted metadata, thumbnails, previews, classifications, and sidecars.
- Directory intelligence โ contextual knowledge attached to folders and subtrees ("active projects", "dormant archives", etc).
- Access intelligence โ permissions and policy that apply across devices and clouds, routing agents through structured access instead of raw shell commands.
When an agent navigates through Spacedrive, it receives the file listing, subtree context, effective permissions, and summaries. Users can explain how they organize their system. Agents can add attributed notes. Jobs generate summaries from structure and activity. The intelligence stays attached to the filesystem, not buried in temporary session memory.
Safety Screening
When enabled, every record passes through a safety pipeline before becoming searchable:
- Prompt Guard 2 โ local classifier detects prompt injection in emails, messages, and documents before they enter the index.
- Trust tiers โ authored content (your notes) gets balanced screening, external content (email inbox) gets strict screening.
- Quarantine system โ flagged records excluded from AI agent queries, reviewable in desktop app.
- Content fencing โ search results include trust metadata so agents know what's safe vs untrusted.
No other local data tool screens indexed content before exposing it to AI.
Architecture
The core is built on four principles:
Virtual Distributed Filesystem (VDFS) โ files and folders become first-class objects with rich metadata, independent of physical location. Every file gets a universal address (
SdPath) that works across devices.Content Identity System โ adaptive hashing (BLAKE3 with strategic sampling for large files) creates a unique fingerprint for every piece of content. Enables deduplication, redundancy tracking, and content-based operations.
Transactional Actions โ every file operation can be previewed before execution. See space savings, conflicts, and estimated time, then approve or cancel. Operations become durable jobs that survive network interruptions and device restarts.
Leaderless Sync โ peer-to-peer synchronization without central coordinators. Device-specific data uses state replication. Shared metadata uses an HLC-ordered log with deterministic conflict resolution.
The implementation is a single Rust crate with CQRS/DDD architecture. Every operation (file copy, tag create, search query) is a registered action or query with type-safe input/output that auto-generates TypeScript types for the frontend.
| Component | Technology |
|---|---|
| Language | Rust |
| Async runtime | Tokio |
| Database | SQLite (SeaORM + sqlx) |
| P2P | Iroh (QUIC, hole-punching, local discovery) |
| Content hashing | BLAKE3 |
| Vector search | LanceDB + FastEmbed |
| Cloud storage | OpenDAL |
| Cryptography | Ed25519, X25519, ChaCha20-Poly1305, AES-GCM |
| Media | FFmpeg, libheif, Pdfium, Whisper |
| Desktop | Tauri 2 |
| Mobile | React Native + Expo |
| Frontend | React 19, Vite, TanStack Query, Tailwind CSS v4 |
| Design system | SpaceUI (shared component library) |
| Type generation | Specta |
spacedrive/
โโโ core/ # Rust engine (CQRS/DDD)
โโโ apps/
โ โโโ tauri/ # Desktop app (macOS, Windows, Linux)
โ โโโ mobile/ # React Native (iOS, Android)
โ โโโ cli/ # CLI and daemon
โ โโโ server/ # Headless server
โ โโโ web/ # Browser client
โโโ packages/
โ โโโ interface/ # Shared React UI
โ โโโ ts-client/ # Auto-generated TypeScript client
โ โโโ ui/ # Component library
โ โโโ assets/ # Icons, images, SVGs
โโโ crates/ # Standalone Rust crates (ffmpeg, crypto, etc.)
โโโ adapters/ # Script-based data source adapters
โโโ schemas/ # TOML data type schemasGetting Started
Requires Rust 1.81+, Bun 1.3+, just, and Python 3.9+ (for adapters).
git clone https://github.com/spacedriveapp/spacedrive
cd spacedrive
just setup # bun install + native deps + cargo config
just dev-desktop # launch the desktop app (auto-starts daemon)
just test # run all workspace testsPrivacy & Security
Spacedrive is local-first. Your data stays on your devices.
- End-to-End Encryption โ all P2P traffic encrypted via QUIC/TLS
- At-Rest Encryption โ libraries can be encrypted on disk (SQLCipher)
- No Telemetry โ zero tracking or analytics
- Self-Hostable โ run your own relay servers
- Data Sovereignty โ you control where your data lives
Optional cloud integration is available for backup and remote access, but it's never required. The cloud service runs unmodified Spacedrive core as a standard P2P deviceโno special privileges.
Contributing
- Join Discord to chat with developers and community
- Contributing Guide
- Adapter Guide โ write a data source adapter
- SpaceUI โ shared design system (clone alongside Spacedrive to work on UI)
License
FSL-1.1-ALv2 โ Functional Source License, converting to Apache 2.0 after two years.
File: apps/server/README.md
Spacedrive Server
HTTP server for Spacedrive with embedded daemon (RPC only, no web UI).
Overview
sd-server runs the Spacedrive daemon and exposes RPC endpoints over HTTP. Perfect for:
- NAS deployments (TrueNAS, Unraid, Synology, etc.)
- Headless servers
- Remote access to your Spacedrive libraries
- Docker/container environments
- CLI-only usage with
sd-cli
Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ sd-server (HTTP Server) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Axum HTTP Server (Port 8080) โ โ
โ โ โโ /health (healthcheck) โ โ
โ โ โโ /rpc (proxy to daemon) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Embedded Daemon โ โ
โ โ (Unix socket: daemon.sock) โ โ
โ โ โโ Core VDFS โ โ
โ โ โโ Indexing โ โ
โ โ โโ P2P Networking โ โ
โ โ โโ File Operations โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโUnlike Tauri (desktop app), the server:
- Embeds the daemon instead of spawning a separate process
- Provides only RPC endpoints (no bundled web UI)
- Proxies RPC requests to daemon via Unix socket
- Provides basic auth for security
Quick Start
Development (without Docker)
Build the server:
bashcargo build -p sd-serverRun the server:
bash# Development mode (creates temp data dir) cargo run -p sd-server # Production mode (requires DATA_DIR) DATA_DIR=/path/to/data cargo run -p sd-server --releaseAccess the RPC endpoint:
- Health check: http://localhost:8080/health
- RPC endpoint: http://localhost:8080/rpc
- Default auth: disabled in dev mode
Docker Deployment (Recommended)
Perfect for TrueNAS, Unraid, or any Docker-compatible NAS.
Create a
.envfile:bash# REQUIRED: Set your credentials SD_AUTH=admin:your-secure-password # Optional: Change port PORT=8080 # Optional: Disable auth (NOT RECOMMENDED) # SD_AUTH=disabledStart with docker-compose:
bashcd apps/server docker-compose up -dAccess the server:
- Navigate to
http://your-nas-ip:8080 - Login with credentials from
.env
- Navigate to
Configuration
Environment Variables
| Variable | Description | Default | Required |
|---|---|---|---|
DATA_DIR |
Path to Spacedrive data directory | /data (in Docker) |
Yes (production) |
PORT |
HTTP server port | 8080 |
No |
SD_AUTH |
Authentication credentials (format: user:pass,user2:pass2) |
None | Recommended |
SD_P2P |
Enable P2P networking | true |
No |
RUST_LOG |
Log level | info,sd_core=debug |
No |
Authentication
IMPORTANT: Always set SD_AUTH in production!
# Single user
SD_AUTH=admin:securepassword123
# Multiple users
SD_AUTH=admin:pass1,user:pass2,readonly:pass3
# Disable (NOT RECOMMENDED - only for trusted networks)
SD_AUTH=disabledUses HTTP Basic Authentication. The server will return 401 Unauthorized if credentials don't match.
Data Storage
The server stores all data in DATA_DIR:
$DATA_DIR/
โโโ daemon/
โ โโโ daemon.sock # Unix socket for RPC
โโโ libraries/
โ โโโ *.sdlibrary/ # Library databases
โโโ logs/ # Application logs
โโโ current_library_id.txt # Last opened libraryDocker volumes: Mounted at /data inside the container.
TrueNAS Setup
Using TrueNAS SCALE (Docker)
Navigate to Apps in TrueNAS web UI
Click "Launch Docker Image"
Configure:
- Image: Build locally or use pre-built image
- Port: Map
8080to host - Volume: Mount
/mnt/pool/spacedriveto/data - Environment:
SD_AUTH=admin:yourpasswordTZ=America/New_York(your timezone)
Add storage pools (optional):
- Mount your datasets as read-only volumes
- Example:
/mnt/tank/photosโ/photosin container
Manual Docker Run
docker run -d \
--name spacedrive \
-p 8080:8080 \
-p 7373:7373 \
-v /mnt/pool/spacedrive:/data \
-v /mnt/pool/media:/media:ro \
-e SD_AUTH=admin:password \
-e TZ=UTC \
--restart unless-stopped \
spacedrive/server:latestBuilding
# Build server (RPC only)
cargo build --release -p sd-server
# Run server
./target/release/sd-server --data-dir /path/to/dataYou can connect with:
sd-cli(CLI client)- Custom HTTP clients via
/rpc - Tauri desktop app configured to connect to this server
- Future web UI (not yet implemented)
Development Workflow
# Run server in dev mode
cargo run -p sd-server
# Server starts on http://localhost:8080
# Use sd-cli or custom client to interact with RPC endpointAPI Endpoints
`GET /health`
Health check endpoint.
Response: 200 OK with body "OK"
`POST /rpc`
JSON-RPC proxy to daemon.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "query:libraries.list",
"params": { "include_stats": false }
}Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": [...]
}Comparison: Server vs Tauri
| Feature | Server | Tauri |
|---|---|---|
| Platform | Linux/Docker | macOS/Windows/Linux |
| UI | None (RPC only) | Native webview |
| Daemon | Embedded in process | Spawned as child process |
| Access | Remote over HTTP | Local only |
| Auth | HTTP Basic Auth | Not needed (local) |
| Use Case | NAS, headless servers, CLI | Desktop workstations |
Both use the same Spacedrive core!
Troubleshooting
Server won't start
- Check
DATA_DIRexists and is writable - Verify port 8080 is not in use:
lsof -i :8080 - Check logs:
RUST_LOG=debug cargo run -p sd-server
Can't connect to daemon
- Ensure
daemon.sockexists in$DATA_DIR/daemon/ - Check daemon logs in
$DATA_DIR/logs/ - Try removing stale socket:
rm $DATA_DIR/daemon/daemon.sock
Authentication failing
- Verify
SD_AUTHformat:username:password - Check browser is sending Basic Auth header
- Test with curl:bash
curl -u admin:password http://localhost:8080/health
Docker build failing
- Ensure you're building from repository root:bash
docker build -f apps/server/Dockerfile . - Check Docker has enough memory (4GB+ recommended)
Contributing
The server app is part of the Spacedrive v2 monorepo.
Project structure:
apps/server/
โโโ src/
โ โโโ main.rs # Server implementation
โโโ Cargo.toml # Dependencies
โโโ Dockerfile # Container image
โโโ docker-compose.yml # Docker setupMaking changes:
- Server code: Edit
apps/server/src/main.rs - Daemon integration: See
core/src/infra/daemon/
License
FSL-1.1-ALv2 - See LICENSE file in repository root.
File: apps/gpui-photo-grid/README.md
GPUI Photo Grid
High-performance photo grid viewer for Spacedrive built with GPUI.
Features
- GPU-accelerated rendering with GPUI
- Grid layout with configurable columns and thumbnail size
- Direct connection to Spacedrive daemon
- Loads up to 1000 media files per directory
- Smart thumbnail variant selection
Building
cargo build --releaseRunning
Make sure Spacedrive daemon is running, then:
export SD_LIBRARY_ID="your-library-uuid"
export SD_SOCKET_PATH="$HOME/.spacedrive/daemon.sock" # optional
export SD_HTTP_URL="http://127.0.0.1:54321" # optional
export SD_INITIAL_PATH="/" # optional
cargo runHelper Script
Use the included script to automatically find your library and run:
./run.shEnvironment Variables
SD_LIBRARY_ID(required) - Your Spacedrive library UUIDSD_SOCKET_PATH(optional) - Path to daemon socket (default:~/.spacedrive/daemon.sock)SD_HTTP_URL(optional) - HTTP server URL (default:http://127.0.0.1:54321)SD_INITIAL_PATH(optional) - Initial directory path (default:/)
Architecture
- Uses
sd-clientcrate to communicate with Spacedrive daemon - Queries files via Unix socket
- Loads thumbnails via HTTP from sidecar server
- GPUI handles image loading, caching, and GPU rendering
Performance
Current implementation:
- Loads 1000 files at a time
- Renders all visible thumbnails
- Uses GPUI's built-in image caching
Future optimizations:
- Virtual scrolling (only render visible rows)
- Texture streaming with LRU cache
- Infinite scroll with pagination
- Batch image loading
File: core/src/infra/extension/README.md
WASM Extension System
Status: Basic structure integrated, compiling successfully
This module provides Spacedrive's WebAssembly-based extension system, enabling secure, sandboxed plugins.
What's Implemented
Core Infrastructure
manager.rs- PluginManager for loading/unloading WASM modules (Wasmer integration)host_functions.rs- Skeleton forhost_spacedrive_call()andhost_spacedrive_log()permissions.rs- Capability-based security with rate limitingtypes.rs- Extension manifest format and types
Dependencies Added
wasmer = "4.2"
wasmer-middlewares = "4.2"The Design
Key Insight: ONE generic host function reuses the entire Wire/Registry infrastructure.
// WASM extensions import:
extern "C" {
fn spacedrive_call(method, library_id, payload) -> result;
}
// Host function routes to existing registry:
host_spacedrive_call()
โ
RpcServer::execute_json_operation() // EXISTING!
โ
LIBRARY_QUERIES/ACTIONS.get() // EXISTING!
โ
Operation::execute() // EXISTING!Result: Zero code duplication. WASM extensions use same operations as CLI/GraphQL/daemon clients.
What's NOT Implemented Yet
Pending Work
1. WASM Memory Interaction (host_functions.rs)
- Read/write strings from WASM linear memory
- Read/write JSON payloads
- UUID handling
- Guest allocator integration
2. Full Wire Bridge (host_functions.rs)
- Call
RpcServer::execute_json_operation() - Permission checking before operation
- Error handling and propagation
3. Extension Operations (core/src/ops/)
ai.ocr- OCR operationai.classify_text- AI classificationcredentials.store/get- Credential managementvdfs.write_sidecar- Sidecar file operations
4. Test WASM Module
- Simple "hello world" .wasm file
- Calls
spacedrive_call()to test integration - Validates permission system
5. Extension SDK (separate crate)
spacedrive-sdkRust crate- Type-safe wrapper around
spacedrive_call() - Ergonomic API for extension developers
Next Steps
Immediate (This Week)
Implement WASM Memory Helpers
- Study Wasmer 4.2 API documentation
- Implement
read_string_from_wasm() - Implement
write_json_to_wasm() - Test with simple WASM module
Complete
host_spacedrive_call()- Bridge to
execute_json_operation() - Add permission checking
- Error handling
- Bridge to
Create Test WASM Module
- Rust project that compiles to WASM
- Calls
spacedrive_call()with test payload - Validates round-trip works
Week 2-3
Add Extension Operations
- Implement
ai.ocr(Tesseract integration) - Implement
credentials.store/get - Implement
vdfs.write_sidecar
- Implement
Build Extension SDK
- Create
spacedrive-sdkcrate - Type-safe wrappers
- Documentation
- Create
Week 4+
- Finance Extension
- Email scanning
- Receipt processing
- Full end-to-end test
Architecture Documents
- WASM_ARCHITECTURE_FINAL.md - Quick reference
- EXTENSION_IPC_DESIGN.md - Detailed design
- EMAIL_INGESTION_EXTENSION_DESIGN.md - Finance extension
- PLATFORM_REVENUE_MODEL.md - Business model
Example Usage (Future)
// In Spacedrive Core
let mut plugin_manager = PluginManager::new(core.clone(), plugins_dir);
plugin_manager.load_plugin("finance").await?;
// Extension (WASM) calls:
let result = spacedrive_call(
"query:ai.ocr",
library_id,
json!({ "data": pdf_bytes, "options": { "language": "eng" } })
);Testing
# Check compilation
cd core && cargo check
# Run tests (once implemented)
cd core && cargo test extension
# Load test plugin (once implemented)
cargo run --bin spacedrive extension load ./plugins/test-pluginNotes
- Memory Management: WASM modules must export
wasm_alloc(size: i32) -> *mut u8 - Error Handling: Errors returned as JSON
{ "error": "message" } - Permissions: Checked on every
spacedrive_call() - Rate Limiting: 1000 requests/minute default
Last Updated: October 2025 - Initial integration
File: core/src/ops/network/sync_setup/README.md
Library Sync Setup System
Overview
This module handles library synchronization setup between paired devices. It is intentionally separate from the pairing protocol to maintain clean separation between networking concerns (device authentication) and application concerns (library data organization).
Architecture
Why Separate from Pairing?
- Separation of Concerns: Pairing is a pure networking operation, while library setup involves application-level business logic
- User Flexibility: Users may want to pair devices without immediately syncing libraries
- Progressive Enhancement: Can start simple and evolve independently when sync is fully implemented
- Clean Testing: Each component tests independently
Components
Actions
LibrarySyncSetupAction(action.rs): CoreAction that sets up library sync between two paired devices- Currently implements
RegisterOnlymode: registers devices in each other's libraries - Future modes:
MergeIntoLocal,MergeIntoRemote,CreateShared(awaits full sync implementation)
- Currently implements
Queries
DiscoverRemoteLibrariesQuery(discovery/query.rs): CoreQuery that discovers libraries on a remote paired device- Validates device is paired
- Returns library metadata (name, stats, etc.)
- Currently returns empty list (requires messaging protocol extension)
Message Types
LibraryMessage(service/network/protocol/library_messages.rs): Protocol messages for library operationsDiscoveryRequest/DiscoveryResponse: Library discoveryRegisterDeviceRequest/RegisterDeviceResponse: Device registration
Current Implementation Status
Phase 1: Basic Structure (Complete)
- Directory structure and module organization
- Input/Output types with proper serialization
- CQRS action and query registration
- Device registration in local library database
- Validation of paired devices
- Error handling and logging
Phase 2: Network Implementation (Pending)
- LibraryMessage handler in messaging protocol
- Actual library discovery over network
- Remote device registration requests
- Bi-directional library setup
Phase 3: Full Sync Support (Future)
- Library merging (MergeIntoLocal, MergeIntoRemote)
- Shared library creation
- Conflict resolution
- Sync job initialization
- Sync leadership management
Usage Flow
// 1. User pairs two devices (via pairing protocol)
PairGenerateAction::execute() // Device A
PairJoinAction::execute() // Device B
// Result: Devices are now paired
// 2. User initiates library sync setup
DiscoverRemoteLibrariesQuery {
device_id: paired_device_id
}
// Result: List of libraries on remote device (currently empty)
// 3. User selects libraries and sync action
LibrarySyncSetupAction {
local_device_id: device_a_id,
remote_device_id: device_b_id,
local_library_id: my_library_id,
remote_library_id: their_library_id,
action: LibrarySyncAction::RegisterOnly,
leader_device_id: device_a_id,
}
// Result: Devices registered in each other's librariesDatabase Changes
The action registers paired devices in library databases:
INSERT INTO device (uuid, name, os, os_version, ...)
VALUES (remote_device_id, 'Remote Device', 'Desktop', '1.0', ...);This enables:
- Future sync operations
- Device-to-device file operations (Spacedrop)
- Multi-device library awareness
Integration Points
With Pairing System
- Depends on: Device must be in
PairedorConnectedstate - Location:
core/src/service/network/protocol/pairing/
With Library Manager
- Uses:
LibraryManager::get_library()for validation - Accesses: Library database for device registration
- Location:
core/src/library/manager.rs
With Networking Service
- Uses:
NetworkingService::device_registry()for device info - Future: Will use messaging protocol for remote operations
- Location:
core/src/service/network/core/
With Sync System (Future)
- Will integrate with: Sync jobs, leader election, merge operations
- Design: See
docs/core/design/SYNC_DESIGN.mdlines 245-311 - Location: TBD (
core/src/sync/when implemented)
API Endpoints
Query: `query:network.sync_setup.discover`
Input:
{
"device_id": "uuid-of-paired-device"
}Output:
{
"device_id": "uuid",
"device_name": "Device Name",
"libraries": [
{
"id": "uuid",
"name": "My Library",
"description": "Optional description",
"created_at": "2025-01-01T00:00:00Z",
"statistics": {
"total_entries": 1000,
"total_locations": 5,
"total_size_bytes": 1000000,
"device_count": 2
}
}
],
"is_online": true
}Action: `action:network.sync_setup.input`
Input:
{
"local_device_id": "uuid",
"remote_device_id": "uuid",
"local_library_id": "uuid",
"remote_library_id": "uuid",
"action": {
"type": "RegisterOnly"
},
"leader_device_id": "uuid"
}Output:
{
"success": true,
"local_library_id": "uuid",
"remote_library_id": "uuid",
"devices_registered": true,
"message": "Devices successfully registered for library access"
}Testing Recommendations
- Unit Tests: Test action validation logic
- Integration Tests: Test device registration in database
- E2E Tests: Test full flow from pairing โ discovery โ setup
- Error Cases: Test with unpaired devices, invalid libraries, etc.
Future Enhancements
See SYNC_DESIGN.md for full sync system design including:
- Library merging strategies
- Conflict resolution
- Sync jobs and state machines
- Leader election
- Dependency-aware sync protocol
Notes
- Remote operations currently log TODO warnings
- Full implementation awaits messaging protocol extension
- Design aligns with provisional sync architecture
- Maintains backward compatibility with existing pairing system
File: core/README.md
Spacedrive Core
Rust library implementing the Virtual Distributed File System (VDFS) architecture for local-first, AI-native file management.
Architecture
Structure
src/
โโโ domain/ # Core data models (Entry, Library, Device)
โโโ ops/ # Operations (actions and queries, CQRS pattern)
โโโ infra/ # Infrastructure (database, events, wire protocol)
โโโ service/ # High-level services (network, jobs, sessions)
โโโ location/ # Location management and indexing
โโโ library/ # Library lifecycle and operations
โโโ device/ # Device identity and management
โโโ volume/ # Volume detection and fingerprinting
โโโ config/ # Application configuration
โโโ crypto/ # Cryptographic primitives
โโโ bin/ # Binaries (cli, daemon)Core Components
Core Manager (Core struct in lib.rs)
- Coordinates all subsystems
- Manages application lifecycle
- Provides unified access to capabilities
Library (library/)
- File-based storage (
.sdlibrarydirectories) - SQLite database with SeaORM
- Job management and thumbnail generation
- Device registration and sync coordination
Entry-Centric Model (domain/entry.rs)
- Unified representation for files and directories
- Conditional UUIDs (directories immediate, files after content ID)
- On-demand UserMetadata creation
- Relative paths from location roots
Device Management (device/)
- Single device identity per installation
- Persistent across restarts (
device.json) - Sync leadership model per library
- Network address tracking for P2P
Operations Layer (ops/)
- CQRS pattern: Actions (mutations) and Queries (reads)
- Wire protocol with automatic type generation
- Registry system using
inventorycrate - Shared across daemon RPC, iOS FFI, and WASM extensions
Infrastructure (infra/)
api/: Wire protocol dispatcher and RPC serverevent/: Event bus for state changesaction/: Transactional action system with preview-commit-verifyquery/: Read-optimized query handlers
Networking (service/network/)
- Iroh-based P2P networking
- Device pairing protocol
- File transfer (Spacedrop)
- mDNS local discovery
Jobs (service/jobs/)
- Durable, resumable operations
- MessagePack serialization for state
- Progress reporting and cancellation
- Per-library job managers
Indexing (location/indexer/)
- Five-phase pipeline (discover, classify, extract, thumbnail, cleanup)
- File system watcher integration
- Rules engine with glob patterns
- Resumable with checkpoints
Volume Management (volume/)
- Cross-platform volume detection
- Fingerprinting for identity
- Mount point tracking
Communication Patterns
Daemon-Client (Desktop/CLI)
- Unix socket JSON-RPC 2.0
- Wire method strings (e.g.,
query:vdfs.list_entries) - Operations auto-register at compile time
Embedded FFI (iOS/Mobile)
- Direct Rust library integration
- Same JSON-RPC protocol over FFI
- Swift client with Specta-generated types
Extensions (WASM)
- Sandboxed WASM modules
- Minimal host functions (log, register_job)
- SDK with procedural macros (
crates/sdk/) - Models, jobs, actions, agents, UI manifests
Key Technologies
- Async runtime: tokio
- Database: SQLite via SeaORM
- Serialization: serde, Specta for type generation
- Networking: Iroh (P2P), mdns-sd (local discovery)
- WASM: wasmer runtime, spacedrive-sdk
- Jobs: inventory for registration, rmp-serde for state
- Crypto: blake3 (content addressing), ed25519 (signing)
- Indexing: notify (fs watcher), globset (rules)
Building
# Full build
cargo build --release
# With optional features
cargo build --features ffmpeg,ai,heif
# Specific binary
cargo build --bin spacedrive
cargo build --bin daemon
# Run CLI
cargo run --bin spacedrive -- --helpBinaries
spacedrive: CLI interfacedaemon: Background daemon process
Development
- Uses CQRS and DDD patterns
- Operations register via
inventorycrate macros - Resumable jobs with MessagePack state serialization
- Type-safe Wire protocol with Specta generation
- Event-driven architecture with EventBus
- No layered architecture (direct Rust patterns)
Testing
# All tests
cargo test
# Specific module
cargo test --lib location::indexer
# Integration tests
cargo test --test indexer_testSee /docs/core/ for detailed architecture documentation.
File: crates/sdk/README.md
Spacedrive Extension SDK
Beautiful, type-safe API for building Spacedrive WASM extensions.
Installation
Add to your extension's Cargo.toml:
[dependencies]
spacedrive-sdk = { path = "../spacedrive-sdk" }Quick Start
use spacedrive_sdk::prelude::*;
use spacedrive_sdk::ExtensionContext;
#[no_mangle]
pub extern "C" fn plugin_init() -> i32 {
spacedrive_sdk::ffi::log_info("Extension started!");
0 // Success
}
fn process_receipt(ctx: &ExtensionContext, pdf_data: &[u8]) -> Result {
// Create entry
let entry = ctx.vdfs().create_entry(CreateEntry {
name: "Receipt: Starbucks".into(),
path: "receipts/1.pdf".into(),
entry_type: "FinancialDocument".into(),
metadata: None,
})?;
// Run OCR
let ocr_result = ctx.ai().ocr(pdf_data, OcrOptions::default())?;
// Store result
ctx.vdfs().write_sidecar(entry.id, "ocr.txt", ocr_result.text.as_bytes())?;
// Classify with AI
let receipt = ctx.ai().classify_text(
&ocr_result.text,
"Extract vendor, amount, date from this receipt. Return JSON."
)?;
ctx.vdfs().write_sidecar(entry.id, "receipt.json",
serde_json::to_vec(&receipt)?.as_slice()
)?;
Ok(entry.id)
}No Unsafe, No FFI, Just Clean Rust
Before (raw C bindings):
#[link(wasm_import_module = "spacedrive")]
extern "C" {
fn spacedrive_call(
method_ptr: *const u8,
method_len: usize,
library_id_ptr: u32,
payload_ptr: *const u8,
payload_len: usize
) -> u32;
}
// Then manually:
// - Serialize to JSON
// - Get pointer to string
// - Call unsafe function
// - Read result from returned pointer
// - Deserialize JSON
// - Handle errorsAfter (with SDK):
let entry = ctx.vdfs().create_entry(CreateEntry { ... })?;
let ocr = ctx.ai().ocr(&pdf_data, OcrOptions::default())?;That's it! Clean, type-safe, ergonomic.
API Reference
VDFS Operations
// Create entries
let entry = ctx.vdfs().create_entry(CreateEntry {
name: "My File".into(),
path: "path/to/file".into(),
entry_type: "Document".into(),
metadata: None,
})?;
// Write sidecars (store metadata/analysis)
ctx.vdfs().write_sidecar(entry.id, "metadata.json", data)?;
// Read sidecars
let data = ctx.vdfs().read_sidecar(entry.id, "metadata.json")?;
// Update metadata
ctx.vdfs().update_metadata(entry.id, json!({ "category": "Important" }))?;AI Operations
// OCR
let ocr_result = ctx.ai().ocr(&pdf_bytes, OcrOptions {
language: "eng".into(),
engine: OcrEngine::Tesseract,
preprocessing: true,
})?;
// Text classification
let result = ctx.ai().classify_text(
&text,
"Extract structured data from this receipt"
)?;
// Embeddings
let embedding = ctx.ai().embed("search query text")?;Credential Management
// Store OAuth token
ctx.credentials().store("gmail_oauth", Credential::oauth2(
access_token,
Some(refresh_token),
3600, // expires_in_seconds
vec!["https://www.googleapis.com/auth/gmail.readonly".into()]
))?;
// Get credential (auto-refreshes if OAuth)
let cred = ctx.credentials().get("gmail_oauth")?;
// Delete credential
ctx.credentials().delete("old_credential")?;Job System
// Dispatch background job
let job_id = ctx.jobs().dispatch("email_scan", json!({
"provider": "gmail"
}))?;
// Check status
match ctx.jobs().get_status(job_id)? {
JobStatus::Running { progress } => {
ctx.log(&format!("Job {}% complete", progress * 100.0));
}
JobStatus::Completed => {
ctx.log("Job done!");
}
_ => {}
}
// Cancel job
ctx.jobs().cancel(job_id)?;Building Your Extension
# Build for release (optimized for size)
cargo build --target wasm32-unknown-unknown --release
# Output: target/wasm32-unknown-unknown/release/your_extension.wasmRequired Exports
Your extension must export these functions:
#[no_mangle]
pub extern "C" fn plugin_init() -> i32 {
spacedrive_sdk::ffi::log_info("Extension starting!");
0 // Return 0 for success
}
#[no_mangle]
pub extern "C" fn plugin_cleanup() -> i32 {
spacedrive_sdk::ffi::log_info("Extension cleanup");
0 // Return 0 for success
}The SDK automatically provides wasm_alloc and wasm_free - you don't need to implement them!
manifest.json
{
"id": "my-extension",
"name": "My Extension",
"version": "0.1.0",
"description": "What my extension does",
"author": "Your Name",
"wasm_file": "my_extension.wasm",
"permissions": {
"methods": ["vdfs.", "ai.ocr", "credentials."],
"libraries": ["*"],
"rate_limits": {
"requests_per_minute": 1000
},
"max_memory_mb": 512
}
}Error Handling
All operations return Result<T, Error>:
use spacedrive_sdk::prelude::*;
fn my_operation(ctx: &ExtensionContext) -> Result<()> {
let entry = ctx.vdfs().create_entry(...)?; // ? operator works!
ctx.vdfs().write_sidecar(entry.id, "data.json", data)?;
Ok(())
}Logging
ctx.log("Info message");
ctx.log_error("Error message");
// Or directly:
spacedrive_sdk::ffi::log_info("Message");
spacedrive_sdk::ffi::log_debug("Debug");
spacedrive_sdk::ffi::log_warn("Warning");
spacedrive_sdk::ffi::log_error("Error");Examples
See extensions/test-extension/ for a complete working example.
**Beautiful API. Zero unsafe code. Just Rust. **
File: crates/sd-client/README.md
sd-client
Rust client library for connecting to the Spacedrive daemon.
Features
- Unix socket communication with Spacedrive core
- Type-safe query and action execution
- Media file listing queries
- Thumbnail URL construction
- Smart thumbnail variant selection
Usage
use sd_client::{SpacedriveClient, SdPath};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Create client
let mut client = SpacedriveClient::new(
"/path/to/daemon.sock".into(),
"http://localhost:54321".into(),
);
// Set library context
client.set_library("library-uuid".to_string());
// Query media files
let files = client.media_listing(
SdPath::Physical {
device_id: "local".to_string(),
path: "/Users/you/Photos".to_string(),
},
Some(1000),
).await?;
// Get thumbnail URLs
for file in files {
if let Some(content_id) = file.content_identity {
if let Some(thumb) = client.select_best_thumbnail(&file.sidecars, 256.0) {
let url = client.thumbnail_url(
&content_id.uuid,
&thumb.variant,
&thumb.format,
);
println!("{}: {}", file.name, url);
}
}
}
Ok(())
}Example
Run the test connection example:
export SD_LIBRARY_ID="your-library-uuid"
export SD_SOCKET_PATH="$HOME/.spacedrive/daemon.sock" # optional
export SD_HTTP_URL="http://127.0.0.1:54321" # optional
cargo run --example test_connectionAPI
SpacedriveClient
new(socket_path, http_base_url)- Create a new clientset_library(library_id)- Set the current library contextexecute(wire_method, input)- Execute a query or actionmedia_listing(path, limit)- Query media filesthumbnail_url(content_uuid, variant, format)- Construct thumbnail URLselect_best_thumbnail(sidecars, target_size)- Pick optimal thumbnail variant
Types
File- File metadata with content identity and sidecarsContentIdentity- Content hash and UUID for deduplicationSidecar- Generated derivatives (thumbnails, proxies, etc.)SdPath- Location-independent file referenceImageMediaData- Image-specific metadata (dimensions, date taken)VideoMediaData- Video-specific metadata (dimensions, duration)
File: crates/log-analyzer/README.md
Log Analyzer
A powerful log analysis system for Spacedrive that parses, patterns, and collapses repetitive log entries into queryable insights.
Features
- Pattern Detection: Automatically identifies log templates and variables
- Collapse Repetitions: Groups consecutive similar logs with statistics
- Sequence Detection: Identifies repeating multi-step patterns (e.g., Commit โ Emit ร 1000)
- Phase-Based Summary: Aggregates activity by time windows (e.g., "5s intervals showing operation counts")
- Condensed Timeline: Collapses sequences while preserving chronological order
- Queryable Storage: SQLite database for advanced queries with sequences table
- Timeline Generation: Visual timeline of log activity
- Multiple Output Formats: Markdown reports, JSON export, and phase summaries
- Extreme Compression: 99.5% compression achieved on real Spacedrive logs (73,028 lines โ 398 sequences)
Quick Start
Recommended: Phase Summary
For most debugging tasks, start with the phase summary:
cargo run --example analyze_sync_log --features cli -- phases test.log --duration 5This aggregates 85,000+ interleaved log lines into 5-second windows showing operation counts, perfect for understanding sync flow.
As a Library
use log_analyzer::LogAnalyzer;
let analyzer = LogAnalyzer::from_file("test.log")?;
// Phase-based summary (most useful)
let summary = analyzer.generate_phase_summary(5)?; // 5s windows
println!("{}", summary);
// Statistics
println!("Compression: {:.1}%", analyzer.compression_ratio() * 100.0);As a CLI Tool
# Phase summary (recommended - shows "what happened when")
cargo run --example analyze_sync_log --features cli -- phases test.log --duration 5
# Statistics (quick overview)
cargo run --example analyze_sync_log --features cli -- stats test.log
# Condensed timeline (preserves chronological order)
cargo run --example analyze_sync_log --features cli -- condense test.log
# Full analysis with markdown report
cargo run --example analyze_sync_log --features cli -- analyze test.log
# Export to JSON with database
cargo run --example analyze_sync_log --features cli -- analyze test.log \
--format json \
--output analysis.json \
--database analysis.dbHow It Works
1. Parse
Extracts structured components from each log line:
2025-11-16T07:19:57.232531Z DEBUG ThreadId(02) sd_core::sync::peer: Recorded ACK peer=1817e146
โ
{
timestamp: 2025-11-16T07:19:57.232531Z,
level: DEBUG,
thread: ThreadId(02),
module: "sd_core::sync::peer",
message: "Recorded ACK peer=1817e146"
}2. Pattern
Identifies templates by comparing similar messages:
Log A: "Recorded ACK peer=1817e146"
Log B: "Recorded ACK peer=8ef7a321"
โ
Template: "Recorded ACK peer={UUID}"3. Collapse
Groups consecutive instances with statistics:
Template: "Recorded ACK peer={UUID}"
Count: 1992
Duration: 96ms
Variables:
- UUID: 1992 unique values4. Detect Sequences
Identifies repeating multi-step patterns:
Pattern: [Commit, Emit Event]
Detected: This 2-step sequence repeats 1000ร times
Result: 2000 groups โ 1 sequence (compression!)5. Phase-Based Summary (NEW - Most Useful!)
Aggregates operations by time windows for high-level flow understanding:
cargo run --example analyze_sync_log --features cli -- phases test.log --duration 5Output:
## 09:15:28 โ 09:15:33 (5s, 12,450 events)
### Key Operations
[4,028ร] transaction: Committing device-owned data (entry)
[3,829ร] sync_transport: [MockTransport] Delivering message to target
[3,829ร] peer: State change applied successfully (entry)
[2,015ร] peer: Broadcasting shared change (content_identity)
[1,936ร] peer: Shared change applied successfully
[ 200ร] dependency: Added dependency tracking
### By Module
sd_core::service::sync: 8,450 events
sd_core::infra::sync: 2,100 events
sync_realtime_integration_test::helpers: 1,900 eventsBenefits:
- Shows "what happened when" without chronological noise
- Highlights warnings/errors per phase
- Aggregates thousands of interleaved async operations
- Perfect for understanding sync flow at a glance
6. Store & Query
Save to SQLite for advanced queries:
-- Query sequences
SELECT id, repetitions, description, group_count
FROM sequences
ORDER BY repetitions DESC;
-- Query templates
SELECT template_id, COUNT(*) as count
FROM log_instances
WHERE timestamp BETWEEN '07:19:57' AND '07:20:00'
GROUP BY template_id;Architecture
Log File โ Parser โ Pattern Detector โ Collapse Engine โ Sequence Detector โ Database
โ
Analysis & ReportsAnalysis Pipeline
- Parser: Extract structured log components (73,028 logs)
- Pattern Detector: Identify templates (102 unique patterns)
- Collapse Engine: Group consecutive repetitions (64,709 groups)
- Sequence Detector: Find repeating multi-step patterns (398 sequences)
- Result: 99.5% compression ratio!
Examples
See examples/ directory:
simple.rs- Basic library usageanalyze_sync_log.rs- Full-featured CLI tool
Testing
cargo test -p log-analyzerPerformance
Real-world results from Spacedrive sync test logs:
- Input: 73,028 log lines (40MB+)
- Parsing: ~1 second
- Templates: 102 unique patterns detected
- Groups: 64,709 collapsed groups
- Sequences: 398 multi-step patterns
- Compression: 99.5% (73,028 โ 398)
Example sequences detected:
- 1000ร "Commit โ Emit Event" (2-step pattern)
- 790ร "Track Dependency โ Add Tracking" (2-step pattern)
- 499ร "Commit โ Emit โ Commit โ Emit" (4-step pattern)
Output Modes
1. Phase Summary (Best for Understanding Flow)
Shows aggregated operations per time window - answers "what happened when?"
## 09:15:37 โ 09:15:42 (5s, 46,581 events)
[5,374ร] Delivering message to target
[3,576ร] State change sent successfully
[1,798ร] Shared change applied successfully
[1,798ร] Broadcasting shared change
[1,798ร] ACK sent successfullyUse when: Debugging sync flow, understanding system behavior
2. Condensed Timeline (Best for Chronological View)
Shows collapsed sequences preserving order - answers "in what sequence?"
[999ร SEQUENCE] 09:15:28 โ 09:15:38 (2 steps, 10s total)
Step 1: Committing device-owned data (entry)
Step 2: Sync event emitted (StateChange)
09:15:38 Location created successfully
[100ร] 09:15:38 Indexing jobs still running (200ms)Use when: Timeline analysis, event ordering matters
3. Full Report (Best for Documentation)
Markdown/JSON with complete statistics and templates
Use when: Sharing analysis, generating documentation
Use Cases
Sync Test Debugging
Instead of manually scrolling through 85,000 log lines, get:
Phase Summary:
- See that 4,028 entries committed in 09:15:28-33 window
- See that 3,829 applied successfully (239 missing = stuck in dependencies)
- Spot 24 warnings in 09:15:37-42 window
Condensed Timeline:
- 999ร "CommitโEmit" sequence collapsed to 1 line
- Easy anomaly spotting: Missing steps in expected sequences
Performance Analysis
- Measure throughput: "20,750 operations/sec"
- Identify bottlenecks: Sequences with long durations
- Compare test runs: Query database for regression analysis
CI Integration
- Automated log verification in tests
- Assert expected sequence patterns
- Fail builds on missing or broken sequences
Example Query
-- Find the most frequently repeating sequences
SELECT
s.id,
s.repetitions,
s.description,
s.group_count,
s.template_sequence
FROM sequences s
ORDER BY s.repetitions DESC
LIMIT 10;Design
See /docs/core/design/LOG_ANALYSIS_SYSTEM.md for complete design specification.