Skip to main content

Overview

The Spacedrive CLI (sd) is a command-line interface for interacting with the Spacedrive daemon. It provides a comprehensive set of commands for managing libraries, files, devices, and daemon lifecycle.

Architecture

The CLI follows a client-daemon architecture:
  • CLI Binary (sd-cli / sd) - The client that sends commands
  • Daemon Binary (sd-daemon) - The background service that does the actual work
  • Unix Socket - Communication channel between CLI and daemon
┌─────────┐      Unix Socket      ┌──────────┐
│   sd    │ ◄──────────────────► │ sd-daemon│
│ (client)│                       │ (server) │
└─────────┘                       └──────────┘


                                  ┌──────────┐
                                  │ Libraries│
                                  └──────────┘

Daemon Management

Starting the Daemon

# Start in background
sd start

# Start in foreground (see logs)
sd start --foreground
The daemon:
  • Runs as a background process
  • Listens on a Unix socket at ~/Library/Application Support/spacedrive/daemon/daemon.sock
  • Manages all libraries and background tasks
  • Can run multiple instances with --instance flag

Auto-Start on Login

Install the daemon to start automatically on system boot:
# Install LaunchAgent (macOS)
sd daemon install

# Check status
sd daemon status

# Uninstall
sd daemon uninstall
This creates a LaunchAgent at ~/Library/LaunchAgents/com.spacedrive.daemon.plist that:
  • Starts daemon on user login
  • Restarts if it crashes
  • Logs to ~/Library/Application Support/spacedrive/logs/

Multi-Instance Support

Run multiple daemon instances for different data directories:
# Start with custom instance name
sd --instance work start
sd --instance personal start

# Each instance gets its own socket
# daemon-work.sock
# daemon-personal.sock

Configuration

The CLI stores configuration in ~/Library/Application Support/spacedrive/cli.json:
{
  "current_library_id": "uuid-here",
  "update": {
    "repo": "spacedriveapp/spacedrive-cli-releases",
    "channel": "stable"
  }
}

Config Commands

# View all configuration
sd config show

# Get specific value
sd config get update.repo

# Set value
sd config set update.repo "your-org/releases-repo"

Auto-Update System

The CLI includes a built-in update mechanism that fetches releases from a public GitHub repository.

Update Architecture

┌─────────┐                          ┌────────────┐
│sd update│ ──── GitHub API ────────►│  Releases  │
└─────────┘                          │ Repository │
     │                               └────────────┘
     │ Download binaries                   │
     ▼                                     │
┌─────────────────┐                       │
│ sd-macos-arm64  │◄──────────────────────┘
│ sd-daemon-...   │
└─────────────────┘

     │ Atomic replacement

┌─────────────────┐
│ Installed bins  │
└─────────────────┘

Update Process

  1. Check for updates: Queries GitHub API for latest release
  2. Download binaries: Fetches platform-specific binaries
  3. Verify integrity: Checks file sizes match expected values
  4. Atomic replacement: Replaces binaries with rollback on failure
  5. Restart daemon: If daemon was running, restarts it
# Check and install updates
sd update

# Force reinstall current version
sd update --force

Release Repository Setup

The update system uses a public GitHub repository containing only releases (no source code):
  1. Create public repo: your-org/spacedrive-cli-releases
  2. For each release:
    • Create empty commit: git commit --allow-empty -m "Release v0.1.0"
    • Tag it: git tag v0.1.0
    • Create GitHub release with binaries as assets
  3. Configure CLI: sd config set update.repo "your-org/spacedrive-cli-releases"
The CI workflow automatically builds binaries for:
  • macOS (arm64, x86_64)
  • Linux (x86_64) - coming soon
  • Windows (x86_64) - coming soon

Command Structure

All CLI commands follow this pattern:
sd [--data-dir PATH] [--instance NAME] [--format FORMAT] <command> [args]

Global Flags

  • --data-dir - Override default data directory
  • --instance - Connect to specific daemon instance
  • --format - Output format: human (default) or json

Core Commands

CommandDescription
sd startStart the daemon
sd stopStop the daemon
sd restartRestart the daemon
sd statusShow system status
sd updateUpdate CLI and daemon

Domain Commands

CommandDescription
sd libraryManage libraries
sd locationManage indexed locations
sd fileFile operations
sd indexIndexing operations
sd searchSearch files
sd tagTag management
sd volumeVolume operations
sd deviceDevice management
sd jobJob control
sd networkNetworking and pairing
sd logsView daemon logs
sd configConfiguration management
sd daemonDaemon lifecycle

Binary Distribution

For development and testing, binaries can be distributed without building from source:
  1. Build release binaries:
    cargo build --release --bin sd-cli --bin sd-daemon
    
  2. Copy both binaries to target machine:
    • sd-cli → rename to sd
    • sd-daemon → keep as sd-daemon
  3. Place in PATH:
    mv sd ~/.local/bin/
    mv sd-daemon ~/.local/bin/
    chmod +x ~/.local/bin/sd ~/.local/bin/sd-daemon
    
  4. Remove quarantine (macOS):
    xattr -d com.apple.quarantine ~/.local/bin/sd
    xattr -d com.apple.quarantine ~/.local/bin/sd-daemon
    
Both binaries must be in the same directory as the CLI expects to find the daemon binary in its parent directory.

Development

Building

# Build CLI only
cargo build --package sd-cli

# Build both CLI and daemon
cargo build --bin sd-cli --bin sd-daemon

# Release build
cargo build --release --bin sd-cli --bin sd-daemon

Code Structure

apps/cli/
├── src/
│   ├── main.rs          # Entry point, daemon lifecycle
│   ├── config.rs        # CLI configuration
│   ├── context.rs       # Execution context
│   ├── domains/         # Command domains
│   │   ├── config/      # Config commands
│   │   ├── daemon/      # Daemon management
│   │   ├── update/      # Auto-update system
│   │   ├── library/     # Library operations
│   │   ├── location/    # Location operations
│   │   └── ...
│   └── util/            # Shared utilities
└── Cargo.toml

core/
└── src/
    └── bin/
        └── daemon.rs    # Daemon binary

Adding New Commands

  1. Create a new module in domains/
  2. Define command enum with clap derives
  3. Implement run() function
  4. Register in domains/mod.rs and main.rs
Example:
// domains/myfeature/mod.rs
use anyhow::Result;
use clap::Subcommand;

#[derive(Subcommand, Debug)]
pub enum MyFeatureCmd {
    /// Do something
    Action { arg: String },
}

pub async fn run(ctx: &Context, cmd: MyFeatureCmd) -> Result<()> {
    match cmd {
        MyFeatureCmd::Action { arg } => {
            // Implementation
        }
    }
    Ok(())
}

Security Considerations

Instance Name Validation

Instance names are validated to prevent path traversal:
  • Only alphanumeric, dash, and underscore allowed
  • Max 64 characters
  • Cannot be empty

Binary Verification

The update system verifies downloaded binaries:
  • File size must match release asset size
  • Future: SHA256 checksum verification

Daemon Socket Permissions

The Unix socket is created with restrictive permissions (user-only access).

Troubleshooting

Daemon Won’t Start

# Check if already running
sd status

# View logs
sd logs follow

# Reset data and restart
sd restart --reset

Update Fails

# Check configuration
sd config show

# Verify repo is accessible
curl https://api.github.com/repos/YOUR_ORG/YOUR_REPO/releases/latest

# Force clean reinstall
sd update --force

Socket Connection Errors

The daemon socket is located at:
~/Library/Application Support/spacedrive/daemon/daemon.sock
If connection fails:
  1. Verify daemon is running: ps aux | grep sd-daemon
  2. Check socket exists: ls -la <socket-path>
  3. Restart daemon: sd restart