RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Configs/spacedriveapp/spacedrive/diff

Two files, one repository

spacedriveapp/spacedrive ships 2 formats across 3 indexed files. The question worth asking is whether the second one says anything the first does not.

CompareAGENTS.md ↔ CLAUDE.md
A · AGENTS.md · 2585 wordsB · core/AGENTS.md · 753 words
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections15392%
Commands614129%
Section tags67046%

What each file covers

Sections

1 shared · 53 only in A · 9 only in B
  • − Spacedrive Core v2 Development Guide
  • − Quick Start
  • − Development Workflow
  • − Common Commands
  • − Common Mistakes
  • − Quick tips
  • − Architecture Overview
  • − CQRS and DDD Pattern
  • − Feature Module Structure
  • − Communication Architecture
  • − Daemon-Client Communication (Tauri Desktop, CLI, Web)
  • − Tauri Desktop Development
  • − Install dependencies
  • − Run Tauri app in dev mode (auto-starts daemon)
  • − Build for production
  • − Generate TypeScript types
  • − Native Prototypes (iOS, macOS)
  • − Extension System (WASM)
  • − From extension directory
  • − Output: target/wasm32-unknown-unknown/release/extension_name.wasm
  • − Code Standards
  • − Import Organization
  • − Naming Conventions
  • − Error Handling
  • − Async Code
  • − Resumable Jobs
  • − Formatting
  • − Logging
  • − Setup
  • − Writing Style
  • − Macros
  • − Job Logging
  • − Log Levels
  • − Environment Control
  • − Testing
  • − Test Organization
  • − Running Tests
  • − Task Tracking
  • − When to Create Tasks
  • − Task Structure
  • − Description
  • − Implementation Steps
  • − Acceptance Criteria
  • − Managing Tasks
  • − List your active tasks
  • − List high priority tasks
  • − Validate before committing (automatic via git hook)
  • − Task Lifecycle
  • − Debugging
  • − Log Files
  • − Daemon Restart
  • − Verbose Logging
  • − Documentation Locations
  • + AGENTS.md - Spacedrive Core v2
  • + Build/Test Commands
  • + Code Style
  • + Daemon Architecture
  • + **The `Wire` Trait**
  • + **Registration Macros**
  • + **Registry System**
  • + Logging Standards
  • + Debug Instructions
  •   Documentation

Commands

6 shared · 14 only in A · 1 only in B
  • − bun install
  • − bun run tauri:dev
  • − bun run tauri:build
  • − cargo run --bin generate_typescript_types
  • − cargo run --bin generate_swift_types
  • − cargo build --target wasm32-unknown-unknown --release
  • − cargo test test_share_file
  • − cargo test --lib
  • − cargo test -- --nocapture
  • − cargo run -p task-validator -- list --assignee "yourname" --status "In Progress"
  • − cargo run -p task-validator -- list --priority "High" --sort-by id
  • − cargo run -p task-validator -- validate
  • − cargo run --bin sd-cli -- restart
  • − cargo run --bin sd-daemon
  • + cargo test library_test
  •   cargo build
  •   cargo test
  •   cargo test <test_name>
  •   cargo clippy
  •   cargo fmt
  •   cargo run --bin sd-cli -- <command>

Section tags

6 shared · 7 only in A · 0 only in B
  • − setup
  • − architecture
  • − types
  • − git-pr
  • − dependencies
  • − deployment
  • − do-not
  •   build
  •   test
  •   lint-format
  •   code-style
  •   agent-behaviour
  •   docs

Line diff

+69 added−713 removed38 unchanged5.1% identical
spacedriveapp/spacedrive · AGENTS.md
@@ −1 @@
1# Spacedrive Core v2 Development Guide
2 
3## Quick Start
4 
5### Development Workflow
 
 
 
 
 
6 
71. Start daemon: `cargo run --bin sd-daemon`
82. Make code changes
93. Run tests: `cargo test`
104. Rebuild and restart: `cargo run --bin sd-cli -- restart`
115. Test via CLI: `cargo run --bin sd-cli -- <command>`
12 
13### Common Commands
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14 
15```bash
16cargo build # Build the project
17cargo test # Run all tests
18cargo test <test_name> # Run specific test
19cargo clippy # Lint code
20cargo fmt # Format code
21cargo run --bin sd-cli -- <command> # Run CLI (binary is sd-cli, not spacedrive)
22```
23 
24### Common Mistakes
25 
26- Running `spacedrive` instead of `sd-cli` (the binary name is `sd-cli`)
27- Forgetting to restart daemon after rebuilding
28- Using `println!` instead of `tracing` macros (`info!`, `debug!`, etc)
29- Implementing `Wire` manually instead of using `register_*` macros
30- Blocking the async runtime with synchronous I/O operations
31 
32### Quick tips
33 
34- On frontend apps, such as the interface in React, you must ALWAYS ensure type-safety based on the auto generated TypeScript types from `ts-client`. Never cast to as any or redefine backend types. our hooks are typesafe with correct input/output types, but sometimes you might need to access types directly from the `ts-client`.
35- If you have changed types on the backend that are public to the frontend (have `Type` derive), then you must regenerate the types using `cargo run --bin generate_typescript_types`
36- Read the `.mdx` files in /docs for context on any part of the app, they are kept up to date.
37-
38 
39## Architecture Overview
40 
41Spacedrive uses daemon-client architecture. A single daemon process manages core functionality. Multiple clients (CLI, GraphQL server, desktop app) connect via Unix domain sockets.
42 
43### CQRS and DDD Pattern
44 
45- **Domain** (`src/domain/`): Core data structures and business logic (nouns)
46- **Operations** (`src/ops/`): Actions and queries (verbs)
47- **Actions**: State-changing operations (writes)
48- **Queries**: Data retrieval without state changes (reads)
49 
50### Feature Module Structure
51 
52Each feature lives in its own module under `src/ops/`. Example: `src/ops/files/share`
53 
54```
55src/ops/files/share/
56├── action.rs # State-changing logic
57├── input.rs # Action input structures
58├── output.rs # Action output structures
59└── job.rs # Long-running job implementation (if needed)
60```
61 
62Complete feature example:
63 
64```rust
65// src/ops/files/share/input.rs
66#[derive(Debug, Serialize, Deserialize)]
67pub struct ShareFileInput {
68 pub file_id: i32,
69 pub recipient: String,
70}
71 
72// src/ops/files/share/output.rs
73#[derive(Debug, Serialize, Deserialize)]
74pub struct ShareFileOutput {
75 pub share_id: String,
76 pub url: String,
77}
78 
79// src/ops/files/share/action.rs
80use super::{ShareFileInput, ShareFileOutput};
81 
82pub struct ShareFileAction;
83 
84crate::register_library_action!(ShareFileAction, "files.share");
85 
86impl Action for ShareFileAction {
87 type Input = ShareFileInput;
88 type Output = ShareFileOutput;
89 
90 async fn run(input: Self::Input, ctx: &ActionContext) -> Result<Self::Output> {
91 // Implementation
92 }
93}
94```
95 
96## Communication Architecture
97 
98Spacedrive supports multiple communication patterns for different platforms and use cases.
99 
100### Daemon-Client Communication (Tauri Desktop, CLI, Web)
 
101 
102The Tauri desktop app, CLI, and web interface connect to a daemon process via Unix domain sockets (or WebSockets for web). Communication uses JSON-RPC 2.0 with Wire method strings.
103 
104**Registration Macros:**
105 
106Never implement `Wire` manually. Use registration macros:
107 
108```rust
109// Queries
110crate::register_query!(NetworkStatusQuery, "network.status");
111// Generates: "query:network.status"
112 
113// Library Actions
114crate::register_library_action!(FileCopyAction, "files.copy");
115// Generates: "action:files.copy.input"
116 
117// Core Actions
118crate::register_core_action!(LibraryCreateAction, "libraries.create");
119// Generates: "action:libraries.create.input"
120```
121 
122**Registry System:**
123 
124The `inventory` crate collects operations at compile time. When you use `register_query!` or `register_library_action!`, the operation automatically appears in global `QUERIES` and `ACTIONS` hashmaps at startup. You never manually register operations.
125 
126Location: `core/src/ops/registry.rs`
127 
128### Tauri Desktop Development
129 
130The Tauri app (`apps/tauri/`) is the primary desktop application for Spacedrive. It connects to the daemon via the TypeScript client.
131 
132**Development Workflow:**
133 
134```bash
135# Install dependencies
136bun install
137 
138# Run Tauri app in dev mode (auto-starts daemon)
139cd apps/tauri
140bun run tauri:dev
141 
142# Build for production
143bun run tauri:build
144```
145 
146**TypeScript Client:**
147 
148The TypeScript client (`packages/ts-client/`) is auto-generated from Rust types using Specta:
149 
150```bash
151# Generate TypeScript types
152cargo run --bin generate_typescript_types
153```
154 
155**Output:** `packages/ts-client/src/generated.ts`
156 
157**Architecture:**
158 
159```
160Tauri App (React)
161 ↓
162@sd/ts-client (TypeScript)
163 ↓
164Daemon (Unix Socket / IPC)
165 ↓
166RpcServer (Rust)
167 ↓
168Operation Registry
169```
170 
171### Native Prototypes (iOS, macOS)
172 
173**Note:** iOS and macOS apps are experimental prototypes, not production apps.
174 
175Native prototypes embed the core directly as a library via FFI rather than connecting to a daemon. These are located in `apps/ios/` and `apps/macos/` but are private and not documented for public use.
176 
177**Swift Client Generation:**
178 
179For the prototypes, Swift types can be generated:
180 
181```bash
182cargo run --bin generate_swift_types
183```
184 
185Output: `packages/swift-client/Sources/SpacedriveClient/`
186 
187### Extension System (WASM)
188 
189Extensions run as sandboxed WASM modules that interact with Spacedrive core via host functions. Extensions are distributed as compiled `.wasm` files.
190 
191**Architecture:**
192 
193```
194Extension.wasm (compiled Rust)
195 ↓
196spacedrive-sdk (Rust crate)
197 ↓
198Host Functions (FFI boundary)
199 ↓
200Core (VDFS, Jobs, AI, etc.)
201```
202 
203**Key Components:**
204 
205**SDK Location:** `crates/sdk/`
206 
207- High-level Rust API abstracting FFI details
208- Procedural macros for extension definition
209- Type-safe job, model, and action builders
210 
211**Extension Development:**
212 
213Extensions use procedural macros to minimize boilerplate:
214 
215```rust
216use spacedrive_sdk::prelude::*;
217 
218#[extension(
219 id = "test-extension",
220 name = "Test Extension",
221 version = "0.1.0",
222 jobs = [test_counter],
223)]
224struct TestExtension;
225 
226#[derive(Serialize, Deserialize, Default)]
227pub struct CounterState {
228 pub current: u32,
229 pub target: u32,
230 pub processed: Vec<String>,
231}
232 
233#[job(name = "counter")]
234fn test_counter(ctx: &JobContext, state: &mut CounterState) -> Result<()> {
235 ctx.log(&format!("Starting counter (current: {}, target: {})",
236 state.current, state.target));
237 
238 while state.current < state.target {
239 if ctx.check_interrupt() {
240 ctx.checkpoint(state)?;
241 return Err(Error::OperationFailed("Interrupted".into()));
242 }
243 
244 state.current += 1;
245 ctx.report_progress(
246 state.current as f32 / state.target as f32,
247 &format!("Counted {}/{}", state.current, state.target),
248 );
249 
250 if state.current % 10 == 0 {
251 ctx.checkpoint(state)?;
252 }
253 }
254 
255 Ok(())
256}
257```
258 
259**Host Functions:**
260 
261Extensions import minimal FFI functions:
262 
263```rust
264#[link(wasm_import_module = "spacedrive")]
265extern "C" {
266 fn spacedrive_log(level: u32, msg_ptr: *const u8, msg_len: usize);
267 fn register_job(
268 job_name_ptr: *const u8,
269 job_name_len: u32,
270 export_fn_ptr: *const u8,
271 export_fn_len: u32,
272 resumable: u32,
273 ) -> i32;
274}
275```
276 
277**Building Extensions:**
278 
279```bash
280# From extension directory
281cargo build --target wasm32-unknown-unknown --release
 
282 
283# Output: target/wasm32-unknown-unknown/release/extension_name.wasm
284```
285 
286**Extension Capabilities:**
 
 
 
 
 
 
287 
288Extensions can define:
289 
290- Models: Data structures stored in `models` table (content-scoped, standalone, or entry-scoped)
291- Jobs: Long-running resumable operations
292- Actions: User-invoked operations with preview-commit workflow
293- Agents: Autonomous logic with memory and event handling
294- UI: Custom views via `ui_manifest.json`
295 
296**Example Use Cases:**
297 
298- Photos extension: Face detection, scene tagging, album organization
299- Finance extension: Receipt extraction, expense tracking
300- Research extension: Citation extraction, knowledge graphs
301 
302**Key Benefits:**
303 
304- Single `.wasm` file works on all platforms
305- True sandboxing (WASM isolation)
306- Resumable jobs with checkpointing
307- Type-safe API with procedural macros
308- No core modifications needed for new features
309 
310**Documentation:**
311 
312- `/docs/sdk/sdk.md` - Complete SDK specification and API reference
313- `extensions/test-extension/` - Working example extension
314- `crates/sdk/` - SDK implementation
315- `crates/sdk-macros/` - SDK procedural macros
316 
317**Status:** SDK implementation in progress. Test extension compiles to WASM successfully. Core integration for loading and executing WASM modules is next phase.
318 
319## Code Standards
320 
321### Import Organization
322 
323Group imports with blank lines between groups:
324 
325```rust
326// Standard library
327use std::path::PathBuf;
328use std::sync::Arc;
329 
330// External crates
331use serde::{Deserialize, Serialize};
332use tokio::sync::RwLock;
333 
334// Local modules
335use crate::domain::library::Library;
336use crate::ops::Action;
337```
338 
339### Naming Conventions
340 
341- Functions/variables: `snake_case`
342- Types: `PascalCase`
343- Constants: `SCREAMING_SNAKE_CASE`
344 
345### Error Handling
346 
347Use `Result<T, E>` for all fallible operations. Use `thiserror` for custom errors, `anyhow` for application errors.
348 
349```rust
350use thiserror::Error;
351 
352#[derive(Error, Debug)]
353pub enum ShareError {
354 #[error("File not found: {0}")]
355 FileNotFound(i32),
356 
357 #[error("Permission denied")]
358 PermissionDenied,
359 
360 #[error("Database error: {0}")]
361 Database(#[from] sea_orm::DbErr),
362}
363 
364pub async fn share_file(id: i32) -> Result<String, ShareError> {
365 let file = find_file(id).await.ok_or(ShareError::FileNotFound(id))?;
366 // Implementation
367 Ok(share_url)
368}
369```
370 
371### Async Code
372 
373- Use `async/await` syntax
374- Prefer `tokio` primitives (`tokio::sync::RwLock`, `tokio::spawn`)
375- Avoid blocking operations (use `tokio::fs` not `std::fs`)
376- Use `tokio::task::spawn_blocking` for CPU-intensive work
377 
378### Resumable Jobs
379 
380Store job state within the job struct. Use `#[serde(skip)]` for non-persistent fields.
381 
382```rust
383#[derive(Serialize, Deserialize)]
384pub struct FileCopyJob {
385 pub source: PathBuf,
386 pub destination: PathBuf,
387 pub copied_files: Vec<PathBuf>, // Persisted for resumability
388 
389 #[serde(skip)]
390 pub progress_tx: Option<tokio::sync::mpsc::Sender<Progress>>, // Not persisted
391}
392 
393impl Job for FileCopyJob {
394 async fn run(&mut self, ctx: &JobContext) -> Result<()> {
395 ctx.log().info("Starting file copy job");
396 
397 for file in &self.files_to_copy {
398 if self.copied_files.contains(file) {
399 continue; // Skip already copied files on resume
400 }
401 
402 copy_file(file).await?;
403 self.copied_files.push(file.clone());
404 }
405 
406 Ok(())
407 }
408}
409```
410 
411### Documentation
412 
413**Core principle:** Explain WHY, not WHAT. Keep comments as short as possible. One sentence explaining rationale beats a paragraph restating code.
414 
415**Module docs (`//!`):**
416- Add a title with `#` for the module name
417- Explain what the module does in plain language (not bullet points)
418- Include design rationale naturally in prose
419- Add runnable code examples showing usage
420 
421````rust
422//! # File Sharing System
423//!
424//! `core::ops::files::share` provides temporary file sharing via signed URLs.
425//! Share links expire after 7 days by default to prevent indefinite access to
426//! private files. UUID v5 deterministic IDs ensure the same file generates
427//! consistent share URLs across devices without coordination.
428//!
429//! ## Example
430//! ```rust,no_run
431//! use spacedrive_core::ops::files::share::{ShareFileAction, ShareFileInput};
432//!
433//! let input = ShareFileInput { file_id: 123, recipient: "user@example.com" };
434//! let output = ShareFileAction::run(input, &ctx).await?;
435//! ```
436````
437 
438**Function docs (`///`):**
439- First line: brief one-liner
440- Second paragraph: explain design rationale and why this exists
441- Document error handling philosophy when relevant
442- Explain non-obvious behavior and platform differences
443 
444```rust
445/// Creates a share link with automatic expiration.
446///
447/// Share links use signed JWTs so the daemon can validate them without
448/// database lookups on every request. Expiration is enforced server-side
449/// to prevent timezone manipulation. Recipients without library access
450/// get read-only access to the specific file only.
451///
452/// Returns `ShareError::PermissionDenied` if the file is private and
453/// the recipient isn't a library member. The share is still created
454/// but marked inactive for audit logging.
455pub async fn share_file(input: ShareFileInput) -> Result<ShareFileOutput>
456```
457 
458**Inline comments:**
459- Delete comments that restate obvious code
460- Explain WHY for decisions, not WHAT the code does
461- Use one sentence when possible
462- Only expand for truly non-obvious consequences
463 
464```rust
465// Good: explains WHY
466// Lowercase for case-insensitive search matching.
467let ext = path.extension().map(|e| e.to_lowercase());
468 
469// Bad: restates code
470// Extract file extension and convert to lowercase
471let ext = path.extension().map(|e| e.to_lowercase());
472 
473// Good: explains consequence
474// Preserve ephemeral UUIDs so tags attached during browsing survive promotion to managed location.
475let uuid = ephemeral_cache.get(path).unwrap_or_else(|| Uuid::new_v4());
476 
477// Bad: verbose explanation of obvious behavior
478// UUID assignment strategy:
479// 1. First check if there's an ephemeral UUID
480// 2. If not, generate a new one
481let uuid = ephemeral_cache.get(path).unwrap_or_else(|| Uuid::new_v4());
482```
483 
484**Error handling comments:**
485Explain strategy and recovery, not just "log and continue".
486 
487```rust
488// Good: explains recovery
489// Best-effort: continue with remaining moves, stale paths cleaned up on next reindex.
490Err(e) => ctx.log(format!("Failed to move: {}", e)),
491 
492// Bad: states the obvious
493// Log error but continue
494Err(e) => ctx.log(format!("Failed to move: {}", e)),
495```
496 
497**Platform-specific comments:**
498Explain consequences, not implementation blockers.
499 
500```rust
501// Good: explains why and fallback
502#[cfg(windows)]
503pub fn get_inode(_metadata: &std::fs::Metadata) -> Option<u64> {
504 // Windows file indices are unstable across reboots; fall back to path-only matching.
505 None
506}
507 
508// Bad: over-explains implementation details
509#[cfg(windows)]
510pub fn get_inode(_metadata: &std::fs::Metadata) -> Option<u64> {
511 // Windows doesn't have inodes.
512 // The method `file_index()` is unstable (issue #63010).
513 // Returning None is safe as the field is Optional.
514 None
515}
516```
517 
518**Never use:**
519- Placeholder comments ("for now", "TODO: extract this later")
520- Markdown formatting (`**bold**`, `_italic_`) in code comments
521- ASCII diagrams (put those in `/docs/` if needed)
522- Section divider comments (`// ========== Section ==========`)
523- Comments explaining removed code during refactors
524 
525Track future work in GitHub issues, not code comments.
526 
527### Formatting
528 
529Run `cargo fmt` before committing. Tabs for indentation. No emojis.
530 
531## Logging
532 
533### Setup
534 
535Use `tracing_subscriber` in main or examples:
536 
537```rust
538use tracing_subscriber::EnvFilter;
539 
540fn main() {
541 tracing_subscriber::fmt()
542 .with_env_filter(
543 EnvFilter::try_from_default_env()
544 .unwrap_or_else(|_| EnvFilter::new("sd_core=info"))
545 )
546 .init();
547}
548```
549 
550## Writing Style
551 
552This applies to all documentation, code comments, and design documents.
553 
554Use clear, simple language. Write short, impactful sentences. Use active voice. Focus on practical, actionable information.
555 
556Address the reader directly with "you" and "your". Support claims with data and examples when possible.
557 
558Avoid these constructions:
559 
560- Em dashes (use commas or periods)
561- "Not only this, but also this"
562- Metaphors and cliches
563- Generalizations
564- Setup language like "in conclusion"
565- Unnecessary adjectives and adverbs
566- Emojis, hashtags, markdown formatting in prose
567 
568Avoid these words:
569comprehensive, delve, utilize, harness, realm, tapestry, unlock, revolutionary, groundbreaking, remarkable, pivotal
570 
571### Macros
572 
573Use `tracing` macros, never `println!`:
574 
575```rust
576use tracing::{info, warn, error, debug};
577 
578info!("Server started on port {}", port);
579debug!(file_id = %id, "Processing file");
580warn!(error = %e, "Retrying operation");
581error!("Failed to connect to database");
582```
583 
584### Job Logging
585 
586Use `ctx.log()` in job implementations for automatic `job_id` tagging:
587 
588```rust
589impl Job for MyJob {
590 async fn run(&mut self, ctx: &JobContext) -> Result<()> {
591 ctx.log().info("Job started");
592 ctx.log().debug!(progress = %self.progress, "Processing");
593 Ok(())
594 }
595}
596```
597 
598### Log Levels
599 
600- `debug`: Detailed flow for troubleshooting
601- `info`: User-relevant events (server start, job completion)
602- `warn`: Recoverable issues (retry, fallback)
603- `error`: Failures requiring attention
604 
605### Environment Control
606 
607Use `RUST_LOG` environment variable:
608 
609```bash
610RUST_LOG=debug cargo run --bin sd-cli
611RUST_LOG=sd_core=trace cargo run
612RUST_LOG=sd_core::ops=debug cargo run
613```
614 
615## Testing
616 
617### Test Organization
618 
619- Unit tests: Colocated in `#[cfg(test)]` modules
620- Integration tests: `tests/` directory at crate root
621 
622```rust
623// src/ops/files/share/action.rs
624 
625#[cfg(test)]
626mod tests {
627 use super::*;
628 
629 #[tokio::test]
630 async fn test_share_file() {
631 let input = ShareFileInput {
632 file_id: 1,
633 recipient: "test@example.com".to_string(),
634 };
635 
636 let output = share_file(input).await.unwrap();
637 assert!(!output.share_id.is_empty());
638 }
639}
640```
641 
642### Running Tests
643 
644```bash
645cargo test # All tests
646cargo test test_share_file # Specific test
647cargo test --lib # Library tests only
648cargo test -- --nocapture # Show output
649```
650 
651## Task Tracking
652 
653Spacedrive uses a file-based task system in `/.tasks/` to track features, epics, and development work. All task files are version-controlled alongside the code.
654 
655### When to Create Tasks
656 
657Create tasks for work that:
658 
659- Introduces a new feature or capability
660- Refactors a significant system or module
661- Fixes a bug requiring architectural changes
662- Implements a whitepaper specification
663 
664Do not create tasks for:
665 
666- Routine code formatting or style fixes
667- Trivial bug fixes (single line changes)
668- Documentation updates to existing features
669- Dependency version bumps
670 
671### Task Structure
672 
673Each task is a Markdown file: `CATEGORY-###-title-slug.md`
674 
675```yaml
676---
677id: CORE-042
678title: "Implement file sharing API"
679status: "In Progress"
680assignee: "james"
681priority: "High"
682tags: ["core", "networking"]
683whitepaper: "Section 4.2" # And/or design_doc: DESIGN_DOC_NAME.md
684---
685 
686## Description
687Brief overview of what needs to be done and why.
688 
689## Implementation Steps
690- [ ] Create share action in src/ops/files/share
691- [ ] Add database schema for shares table
692- [ ] Implement expiration logic
693 
694## Acceptance Criteria
695- Share links work across all platforms
696- Expired shares return 404
697- Tests cover edge cases
698```
699 
700### Managing Tasks
701 
702```bash
703# List your active tasks
704cargo run -p task-validator -- list --assignee "yourname" --status "In Progress"
705 
706# List high priority tasks
707cargo run -p task-validator -- list --priority "High" --sort-by id
708 
709# Validate before committing (automatic via git hook)
710cargo run -p task-validator -- validate
711```
712 
713### Task Lifecycle
714 
7151. Create task file in `/.tasks/` with `status: "To Do"`
7162. Update status to `"In Progress"` when you start work
7173. Complete implementation and tests
7184. Update status to `"Done"` and commit
719 
720Full documentation: `/docs/core/task-tracking.md`
721 
722## Debugging
723 
724### Log Files
725 
726Job logs live in the `job_logs` directory in the data folder root.
727 
728### Daemon Restart
729 
730After rebuilding, restart the daemon to use the latest code:
731 
732```bash
733cargo build
734cargo run --bin sd-cli -- restart
735```
736 
737### Verbose Logging
738 
739```bash
740RUST_LOG=debug cargo run --bin sd-daemon
741RUST_LOG=sd_core::jobs=trace cargo run
742```
743 
744## Documentation Locations
745 
746- Core architecture: `/docs/core/`
747- Design docs and RFCs: `/docs/core/design/`
748- Application docs: `/docs/`
749- Daemon details: `/docs/core/daemon.md`
750- Task tracking: `/docs/core/task-tracking.md`
751 
spacedriveapp/spacedrive · core/AGENTS.md
@@ +1 @@
1# AGENTS.md - Spacedrive Core v2
2 
3## Build/Test Commands
4 
5- `cargo build` - Build the project
6- `cargo test` - Run all tests
7- `cargo test <test_name>` - Run specific test (e.g., `cargo test library_test`)
8- `cargo clippy` - Lint code
9- `cargo fmt` - Format code
10- `cargo run --bin sd-cli -- <command>` - Run CLI (note: binary is `sd-cli`, not `spacedrive`)
11 
12## Code Style
 
 
 
 
13 
14- **Imports**: Group std, external crates, then local modules with blank lines between
15- **Formatting**: Use `cargo fmt` - tabs for indentation, snake_case for variables/functions. DO NOT use emojis at all.
16- **Types**: Explicit types preferred, use `Result<T, E>` for error handling with `thiserror`
17- **Naming**: snake_case for functions/variables, PascalCase for types, SCREAMING_SNAKE_CASE for constants
18- **Error Handling**: Use `Result` types, `thiserror` for custom errors, `anyhow` for application errors
19- **Async**: Use `async/await`, prefer `tokio` primitives, avoid blocking operations
20- **Resumable Jobs**: For long-running jobs that need to be resumable, store the job's state within the job's struct itself. Use `#[serde(skip)]` for fields that should not be persisted. For example, in a file copy job, the list of already copied files can be stored to allow the job to resume from where it left off.
21- **Documentation**: Use `//!` for module docs, `///` for public items, include examples
22- **Architecture**: Follow a Command Query Responsibility Segregation (CQRS) and Domain-Driven Design (DDD) pattern.
23 - **Domain**: Core data structures and business logic are located in `src/domain/`. These are the "nouns" of your system.
24 - **Operations**: State-changing commands (actions) and data-retrieving queries are located in `src/ops/`. These are the "verbs" of your system.
25 - **Actions**: Operations that modify the state of the application. They should be self-contained and transactional.
26 - **Queries**: Operations that retrieve data without modifying state. They should be efficient and optimized for reading.
27- **Feature Modules**: Each new feature should be implemented in its own module within the `src/ops/` directory. For example, a new "share" feature would live in `src/ops/files/share`. Each feature module should contain the following files where applicable:
28 - `action.rs`: The main logic for the state-changing operation.
29 - `input.rs`: Data structures for the action's input.
30 - `output.rs`: Data structures for the action's output.
31 - `job.rs`: If the action is long-running, the job implementation.
32- **Database**: Use SeaORM entities, async queries, proper error propagation
33- **Comments**: Minimal inline comments, focus on why not what, no TODO comments in production code
34 
35## Daemon Architecture
 
 
 
 
 
 
 
36 
37Spacedrive uses a **daemon-client architecture** where a single daemon process manages the core functionality and multiple client applications (CLI, GraphQL server, desktop app) connect to it via Unix domain sockets.
38 
39> **For detailed daemon architecture documentation, see [/docs/core/daemon.md](/docs/core/daemon.md)**
 
 
 
 
40 
41### **The `Wire` Trait**
42 
43All actions and queries must implement the `Wire` trait to enable type-safe client-daemon communication:
 
 
 
44 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45```rust
46pub trait Wire {
47 const METHOD: &'static str;
 
 
 
48}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49```
50 
51### **Registration Macros**
52 
53Instead of manually implementing `Wire`, use these registration macros that automatically:
54 
551. Implement the `Wire` trait with the correct method string
562. Register the operation in the global registry using the `inventory` crate
57 
58**For Queries:**
59 
 
 
 
 
60```rust
 
61crate::register_query!(NetworkStatusQuery, "network.status");
62// Generates method: "query:network.status"
 
 
 
 
 
 
 
 
63```
64 
65**For Library Actions:**
66 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67```rust
68crate::register_library_action!(FileCopyAction, "files.copy");
69// Generates method: "action:files.copy.input"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70```
71 
72**For Core Actions:**
73 
 
 
74```rust
75crate::register_core_action!(LibraryCreateAction, "libraries.create");
76// Generates method: "action:libraries.create.input"
 
 
 
 
 
 
 
 
 
77```
78 
79### **Registry System**
80 
81- **Location**: `core/src/ops/registry.rs`
82- **Mechanism**: Uses the `inventory` crate for compile-time registration
83- **Global Maps**: `QUERIES` and `ACTIONS` hashmaps populated at startup
84- **Handler Functions**: Generic handlers that decode payloads, execute operations, and encode results
85 
86## Logging Standards
 
87 
88- **Setup**: Use `tracing_subscriber::fmt()` with env filter for structured logging
89- **Macros**: Use `info!`, `warn!`, `error!`, `debug!` from `tracing` crate, not `println!`
90- **Job Context**: Use `ctx.log()` in jobs for job-specific logging with automatic job_id tagging
91- **Structured**: Include relevant context fields: `debug!(job_id = %self.id, "message")`
92- **Levels**: debug for detailed flow, info for user-relevant events, warn for recoverable issues, error for failures
93- **Format**: `tracing_subscriber::fmt().with_env_filter(env_filter).init()` in main/examples
94- **Environment**: Respect `RUST_LOG` env var, fallback to module-specific filters like `sd_core=info`
95 
96## Documentation
97 
98- **Core level docs**: Live in `/docs/core` - comprehensive architecture and implementation guides
99- **Core design docs**: Live in `/docs/core/design` - planning documents, RFCs, and design decisions
100- **Application level docs**: Live in `/docs`
101- **Code docs**: Use `///` for public APIs, `//!` for module overviews, include examples
 
102 
103## Debug Instructions
104 
105- You can view the logs of a job in the job_logs directory in the root of the data folder
106- When testing the CLI, after compiling you must first use the `restart` command to ensure the Spacedrive daemon is using the latest build.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107 
@@ −1 +1 @@
1−# Spacedrive Core v2 Development Guide
1+# AGENTS.md - Spacedrive Core v2
22  
3−## Quick Start
3+## Build/Test Commands
44  
5−### Development Workflow
5+- `cargo build` - Build the project
6+- `cargo test` - Run all tests
7+- `cargo test <test_name>` - Run specific test (e.g., `cargo test library_test`)
8+- `cargo clippy` - Lint code
9+- `cargo fmt` - Format code
10+- `cargo run --bin sd-cli -- <command>` - Run CLI (note: binary is `sd-cli`, not `spacedrive`)
611  
7−1. Start daemon: `cargo run --bin sd-daemon`
8−2. Make code changes
9−3. Run tests: `cargo test`
10−4. Rebuild and restart: `cargo run --bin sd-cli -- restart`
11−5. Test via CLI: `cargo run --bin sd-cli -- <command>`
12+## Code Style
1213  
13−### Common Commands
14+- **Imports**: Group std, external crates, then local modules with blank lines between
15+- **Formatting**: Use `cargo fmt` - tabs for indentation, snake_case for variables/functions. DO NOT use emojis at all.
16+- **Types**: Explicit types preferred, use `Result<T, E>` for error handling with `thiserror`
17+- **Naming**: snake_case for functions/variables, PascalCase for types, SCREAMING_SNAKE_CASE for constants
18+- **Error Handling**: Use `Result` types, `thiserror` for custom errors, `anyhow` for application errors
19+- **Async**: Use `async/await`, prefer `tokio` primitives, avoid blocking operations
20+- **Resumable Jobs**: For long-running jobs that need to be resumable, store the job's state within the job's struct itself. Use `#[serde(skip)]` for fields that should not be persisted. For example, in a file copy job, the list of already copied files can be stored to allow the job to resume from where it left off.
21+- **Documentation**: Use `//!` for module docs, `///` for public items, include examples
22+- **Architecture**: Follow a Command Query Responsibility Segregation (CQRS) and Domain-Driven Design (DDD) pattern.
23+ - **Domain**: Core data structures and business logic are located in `src/domain/`. These are the "nouns" of your system.
24+ - **Operations**: State-changing commands (actions) and data-retrieving queries are located in `src/ops/`. These are the "verbs" of your system.
25+ - **Actions**: Operations that modify the state of the application. They should be self-contained and transactional.
26+ - **Queries**: Operations that retrieve data without modifying state. They should be efficient and optimized for reading.
27+- **Feature Modules**: Each new feature should be implemented in its own module within the `src/ops/` directory. For example, a new "share" feature would live in `src/ops/files/share`. Each feature module should contain the following files where applicable:
28+ - `action.rs`: The main logic for the state-changing operation.
29+ - `input.rs`: Data structures for the action's input.
30+ - `output.rs`: Data structures for the action's output.
31+ - `job.rs`: If the action is long-running, the job implementation.
32+- **Database**: Use SeaORM entities, async queries, proper error propagation
33+- **Comments**: Minimal inline comments, focus on why not what, no TODO comments in production code
1434  
15−```bash
16−cargo build # Build the project
17−cargo test # Run all tests
18−cargo test <test_name> # Run specific test
19−cargo clippy # Lint code
20−cargo fmt # Format code
21−cargo run --bin sd-cli -- <command> # Run CLI (binary is sd-cli, not spacedrive)
22−```
35+## Daemon Architecture
2336  
24−### Common Mistakes
37+Spacedrive uses a **daemon-client architecture** where a single daemon process manages the core functionality and multiple client applications (CLI, GraphQL server, desktop app) connect to it via Unix domain sockets.
2538  
26−- Running `spacedrive` instead of `sd-cli` (the binary name is `sd-cli`)
27−- Forgetting to restart daemon after rebuilding
28−- Using `println!` instead of `tracing` macros (`info!`, `debug!`, etc)
29−- Implementing `Wire` manually instead of using `register_*` macros
30−- Blocking the async runtime with synchronous I/O operations
39+> **For detailed daemon architecture documentation, see [/docs/core/daemon.md](/docs/core/daemon.md)**
3140  
32−### Quick tips
41+### **The `Wire` Trait**
3342  
34−- On frontend apps, such as the interface in React, you must ALWAYS ensure type-safety based on the auto generated TypeScript types from `ts-client`. Never cast to as any or redefine backend types. our hooks are typesafe with correct input/output types, but sometimes you might need to access types directly from the `ts-client`.
35−- If you have changed types on the backend that are public to the frontend (have `Type` derive), then you must regenerate the types using `cargo run --bin generate_typescript_types`
36−- Read the `.mdx` files in /docs for context on any part of the app, they are kept up to date.
37−-
43+All actions and queries must implement the `Wire` trait to enable type-safe client-daemon communication:
3844  
39−## Architecture Overview
40− 
41−Spacedrive uses daemon-client architecture. A single daemon process manages core functionality. Multiple clients (CLI, GraphQL server, desktop app) connect via Unix domain sockets.
42− 
43−### CQRS and DDD Pattern
44− 
45−- **Domain** (`src/domain/`): Core data structures and business logic (nouns)
46−- **Operations** (`src/ops/`): Actions and queries (verbs)
47−- **Actions**: State-changing operations (writes)
48−- **Queries**: Data retrieval without state changes (reads)
49− 
50−### Feature Module Structure
51− 
52−Each feature lives in its own module under `src/ops/`. Example: `src/ops/files/share`
53− 
54−```
55−src/ops/files/share/
56−├── action.rs # State-changing logic
57−├── input.rs # Action input structures
58−├── output.rs # Action output structures
59−└── job.rs # Long-running job implementation (if needed)
60−```
61− 
62−Complete feature example:
63− 
6445 ```rust
65−// src/ops/files/share/input.rs
66−#[derive(Debug, Serialize, Deserialize)]
67−pub struct ShareFileInput {
68− pub file_id: i32,
69− pub recipient: String,
46+pub trait Wire {
47+ const METHOD: &'static str;
7048 }
71− 
72−// src/ops/files/share/output.rs
73−#[derive(Debug, Serialize, Deserialize)]
74−pub struct ShareFileOutput {
75− pub share_id: String,
76− pub url: String,
77−}
78− 
79−// src/ops/files/share/action.rs
80−use super::{ShareFileInput, ShareFileOutput};
81− 
82−pub struct ShareFileAction;
83− 
84−crate::register_library_action!(ShareFileAction, "files.share");
85− 
86−impl Action for ShareFileAction {
87− type Input = ShareFileInput;
88− type Output = ShareFileOutput;
89− 
90− async fn run(input: Self::Input, ctx: &ActionContext) -> Result<Self::Output> {
91− // Implementation
92− }
93−}
9449 ```
9550  
96−## Communication Architecture
51+### **Registration Macros**
9752  
98−Spacedrive supports multiple communication patterns for different platforms and use cases.
53+Instead of manually implementing `Wire`, use these registration macros that automatically:
9954  
100−### Daemon-Client Communication (Tauri Desktop, CLI, Web)
55+1. Implement the `Wire` trait with the correct method string
56+2. Register the operation in the global registry using the `inventory` crate
10157  
102−The Tauri desktop app, CLI, and web interface connect to a daemon process via Unix domain sockets (or WebSockets for web). Communication uses JSON-RPC 2.0 with Wire method strings.
58+**For Queries:**
10359  
104−**Registration Macros:**
105− 
106−Never implement `Wire` manually. Use registration macros:
107− 
10860 ```rust
109−// Queries
11061 crate::register_query!(NetworkStatusQuery, "network.status");
111−// Generates: "query:network.status"
112− 
113−// Library Actions
114−crate::register_library_action!(FileCopyAction, "files.copy");
115−// Generates: "action:files.copy.input"
116− 
117−// Core Actions
118−crate::register_core_action!(LibraryCreateAction, "libraries.create");
119−// Generates: "action:libraries.create.input"
62+// Generates method: "query:network.status"
12063 ```
12164  
122−**Registry System:**
65+**For Library Actions:**
12366  
124−The `inventory` crate collects operations at compile time. When you use `register_query!` or `register_library_action!`, the operation automatically appears in global `QUERIES` and `ACTIONS` hashmaps at startup. You never manually register operations.
125− 
126−Location: `core/src/ops/registry.rs`
127− 
128−### Tauri Desktop Development
129− 
130−The Tauri app (`apps/tauri/`) is the primary desktop application for Spacedrive. It connects to the daemon via the TypeScript client.
131− 
132−**Development Workflow:**
133− 
134−```bash
135−# Install dependencies
136−bun install
137− 
138−# Run Tauri app in dev mode (auto-starts daemon)
139−cd apps/tauri
140−bun run tauri:dev
141− 
142−# Build for production
143−bun run tauri:build
144−```
145− 
146−**TypeScript Client:**
147− 
148−The TypeScript client (`packages/ts-client/`) is auto-generated from Rust types using Specta:
149− 
150−```bash
151−# Generate TypeScript types
152−cargo run --bin generate_typescript_types
153−```
154− 
155−**Output:** `packages/ts-client/src/generated.ts`
156− 
157−**Architecture:**
158− 
159−```
160−Tauri App (React)
161− ↓
162−@sd/ts-client (TypeScript)
163− ↓
164−Daemon (Unix Socket / IPC)
165− ↓
166−RpcServer (Rust)
167− ↓
168−Operation Registry
169−```
170− 
171−### Native Prototypes (iOS, macOS)
172− 
173−**Note:** iOS and macOS apps are experimental prototypes, not production apps.
174− 
175−Native prototypes embed the core directly as a library via FFI rather than connecting to a daemon. These are located in `apps/ios/` and `apps/macos/` but are private and not documented for public use.
176− 
177−**Swift Client Generation:**
178− 
179−For the prototypes, Swift types can be generated:
180− 
181−```bash
182−cargo run --bin generate_swift_types
183−```
184− 
185−Output: `packages/swift-client/Sources/SpacedriveClient/`
186− 
187−### Extension System (WASM)
188− 
189−Extensions run as sandboxed WASM modules that interact with Spacedrive core via host functions. Extensions are distributed as compiled `.wasm` files.
190− 
191−**Architecture:**
192− 
193−```
194−Extension.wasm (compiled Rust)
195− ↓
196−spacedrive-sdk (Rust crate)
197− ↓
198−Host Functions (FFI boundary)
199− ↓
200−Core (VDFS, Jobs, AI, etc.)
201−```
202− 
203−**Key Components:**
204− 
205−**SDK Location:** `crates/sdk/`
206− 
207−- High-level Rust API abstracting FFI details
208−- Procedural macros for extension definition
209−- Type-safe job, model, and action builders
210− 
211−**Extension Development:**
212− 
213−Extensions use procedural macros to minimize boilerplate:
214− 
21567 ```rust
216−use spacedrive_sdk::prelude::*;
217− 
218−#[extension(
219− id = "test-extension",
220− name = "Test Extension",
221− version = "0.1.0",
222− jobs = [test_counter],
223−)]
224−struct TestExtension;
225− 
226−#[derive(Serialize, Deserialize, Default)]
227−pub struct CounterState {
228− pub current: u32,
229− pub target: u32,
230− pub processed: Vec<String>,
231−}
232− 
233−#[job(name = "counter")]
234−fn test_counter(ctx: &JobContext, state: &mut CounterState) -> Result<()> {
235− ctx.log(&format!("Starting counter (current: {}, target: {})",
236− state.current, state.target));
237− 
238− while state.current < state.target {
239− if ctx.check_interrupt() {
240− ctx.checkpoint(state)?;
241− return Err(Error::OperationFailed("Interrupted".into()));
242− }
243− 
244− state.current += 1;
245− ctx.report_progress(
246− state.current as f32 / state.target as f32,
247− &format!("Counted {}/{}", state.current, state.target),
248− );
249− 
250− if state.current % 10 == 0 {
251− ctx.checkpoint(state)?;
252− }
253− }
254− 
255− Ok(())
256−}
68+crate::register_library_action!(FileCopyAction, "files.copy");
69+// Generates method: "action:files.copy.input"
25770 ```
25871  
259−**Host Functions:**
72+**For Core Actions:**
26073  
261−Extensions import minimal FFI functions:
262− 
26374 ```rust
264−#[link(wasm_import_module = "spacedrive")]
265−extern "C" {
266− fn spacedrive_log(level: u32, msg_ptr: *const u8, msg_len: usize);
267− fn register_job(
268− job_name_ptr: *const u8,
269− job_name_len: u32,
270− export_fn_ptr: *const u8,
271− export_fn_len: u32,
272− resumable: u32,
273− ) -> i32;
274−}
75+crate::register_core_action!(LibraryCreateAction, "libraries.create");
76+// Generates method: "action:libraries.create.input"
27577 ```
27678  
277−**Building Extensions:**
79+### **Registry System**
27880  
279−```bash
280−# From extension directory
281−cargo build --target wasm32-unknown-unknown --release
81+- **Location**: `core/src/ops/registry.rs`
82+- **Mechanism**: Uses the `inventory` crate for compile-time registration
83+- **Global Maps**: `QUERIES` and `ACTIONS` hashmaps populated at startup
84+- **Handler Functions**: Generic handlers that decode payloads, execute operations, and encode results
28285  
283−# Output: target/wasm32-unknown-unknown/release/extension_name.wasm
284−```
86+## Logging Standards
28587  
286−**Extension Capabilities:**
88+- **Setup**: Use `tracing_subscriber::fmt()` with env filter for structured logging
89+- **Macros**: Use `info!`, `warn!`, `error!`, `debug!` from `tracing` crate, not `println!`
90+- **Job Context**: Use `ctx.log()` in jobs for job-specific logging with automatic job_id tagging
91+- **Structured**: Include relevant context fields: `debug!(job_id = %self.id, "message")`
92+- **Levels**: debug for detailed flow, info for user-relevant events, warn for recoverable issues, error for failures
93+- **Format**: `tracing_subscriber::fmt().with_env_filter(env_filter).init()` in main/examples
94+- **Environment**: Respect `RUST_LOG` env var, fallback to module-specific filters like `sd_core=info`
28795  
288−Extensions can define:
96+## Documentation
28997  
290−- Models: Data structures stored in `models` table (content-scoped, standalone, or entry-scoped)
291−- Jobs: Long-running resumable operations
292−- Actions: User-invoked operations with preview-commit workflow
293−- Agents: Autonomous logic with memory and event handling
294−- UI: Custom views via `ui_manifest.json`
98+- **Core level docs**: Live in `/docs/core` - comprehensive architecture and implementation guides
99+- **Core design docs**: Live in `/docs/core/design` - planning documents, RFCs, and design decisions
100+- **Application level docs**: Live in `/docs`
101+- **Code docs**: Use `///` for public APIs, `//!` for module overviews, include examples
295102  
296−**Example Use Cases:**
103+## Debug Instructions
297104  
298−- Photos extension: Face detection, scene tagging, album organization
299−- Finance extension: Receipt extraction, expense tracking
300−- Research extension: Citation extraction, knowledge graphs
301− 
302−**Key Benefits:**
303− 
304−- Single `.wasm` file works on all platforms
305−- True sandboxing (WASM isolation)
306−- Resumable jobs with checkpointing
307−- Type-safe API with procedural macros
308−- No core modifications needed for new features
309− 
310−**Documentation:**
311− 
312−- `/docs/sdk/sdk.md` - Complete SDK specification and API reference
313−- `extensions/test-extension/` - Working example extension
314−- `crates/sdk/` - SDK implementation
315−- `crates/sdk-macros/` - SDK procedural macros
316− 
317−**Status:** SDK implementation in progress. Test extension compiles to WASM successfully. Core integration for loading and executing WASM modules is next phase.
318− 
319−## Code Standards
320− 
321−### Import Organization
322− 
323−Group imports with blank lines between groups:
324− 
325−```rust
326−// Standard library
327−use std::path::PathBuf;
328−use std::sync::Arc;
329− 
330−// External crates
331−use serde::{Deserialize, Serialize};
332−use tokio::sync::RwLock;
333− 
334−// Local modules
335−use crate::domain::library::Library;
336−use crate::ops::Action;
337−```
338− 
339−### Naming Conventions
340− 
341−- Functions/variables: `snake_case`
342−- Types: `PascalCase`
343−- Constants: `SCREAMING_SNAKE_CASE`
344− 
345−### Error Handling
346− 
347−Use `Result<T, E>` for all fallible operations. Use `thiserror` for custom errors, `anyhow` for application errors.
348− 
349−```rust
350−use thiserror::Error;
351− 
352−#[derive(Error, Debug)]
353−pub enum ShareError {
354− #[error("File not found: {0}")]
355− FileNotFound(i32),
356− 
357− #[error("Permission denied")]
358− PermissionDenied,
359− 
360− #[error("Database error: {0}")]
361− Database(#[from] sea_orm::DbErr),
362−}
363− 
364−pub async fn share_file(id: i32) -> Result<String, ShareError> {
365− let file = find_file(id).await.ok_or(ShareError::FileNotFound(id))?;
366− // Implementation
367− Ok(share_url)
368−}
369−```
370− 
371−### Async Code
372− 
373−- Use `async/await` syntax
374−- Prefer `tokio` primitives (`tokio::sync::RwLock`, `tokio::spawn`)
375−- Avoid blocking operations (use `tokio::fs` not `std::fs`)
376−- Use `tokio::task::spawn_blocking` for CPU-intensive work
377− 
378−### Resumable Jobs
379− 
380−Store job state within the job struct. Use `#[serde(skip)]` for non-persistent fields.
381− 
382−```rust
383−#[derive(Serialize, Deserialize)]
384−pub struct FileCopyJob {
385− pub source: PathBuf,
386− pub destination: PathBuf,
387− pub copied_files: Vec<PathBuf>, // Persisted for resumability
388− 
389− #[serde(skip)]
390− pub progress_tx: Option<tokio::sync::mpsc::Sender<Progress>>, // Not persisted
391−}
392− 
393−impl Job for FileCopyJob {
394− async fn run(&mut self, ctx: &JobContext) -> Result<()> {
395− ctx.log().info("Starting file copy job");
396− 
397− for file in &self.files_to_copy {
398− if self.copied_files.contains(file) {
399− continue; // Skip already copied files on resume
400− }
401− 
402− copy_file(file).await?;
403− self.copied_files.push(file.clone());
404− }
405− 
406− Ok(())
407− }
408−}
409−```
410− 
411−### Documentation
412− 
413−**Core principle:** Explain WHY, not WHAT. Keep comments as short as possible. One sentence explaining rationale beats a paragraph restating code.
414− 
415−**Module docs (`//!`):**
416−- Add a title with `#` for the module name
417−- Explain what the module does in plain language (not bullet points)
418−- Include design rationale naturally in prose
419−- Add runnable code examples showing usage
420− 
421−````rust
422−//! # File Sharing System
423−//!
424−//! `core::ops::files::share` provides temporary file sharing via signed URLs.
425−//! Share links expire after 7 days by default to prevent indefinite access to
426−//! private files. UUID v5 deterministic IDs ensure the same file generates
427−//! consistent share URLs across devices without coordination.
428−//!
429−//! ## Example
430−//! ```rust,no_run
431−//! use spacedrive_core::ops::files::share::{ShareFileAction, ShareFileInput};
432−//!
433−//! let input = ShareFileInput { file_id: 123, recipient: "user@example.com" };
434−//! let output = ShareFileAction::run(input, &ctx).await?;
435−//! ```
436−````
437− 
438−**Function docs (`///`):**
439−- First line: brief one-liner
440−- Second paragraph: explain design rationale and why this exists
441−- Document error handling philosophy when relevant
442−- Explain non-obvious behavior and platform differences
443− 
444−```rust
445−/// Creates a share link with automatic expiration.
446−///
447−/// Share links use signed JWTs so the daemon can validate them without
448−/// database lookups on every request. Expiration is enforced server-side
449−/// to prevent timezone manipulation. Recipients without library access
450−/// get read-only access to the specific file only.
451−///
452−/// Returns `ShareError::PermissionDenied` if the file is private and
453−/// the recipient isn't a library member. The share is still created
454−/// but marked inactive for audit logging.
455−pub async fn share_file(input: ShareFileInput) -> Result<ShareFileOutput>
456−```
457− 
458−**Inline comments:**
459−- Delete comments that restate obvious code
460−- Explain WHY for decisions, not WHAT the code does
461−- Use one sentence when possible
462−- Only expand for truly non-obvious consequences
463− 
464−```rust
465−// Good: explains WHY
466−// Lowercase for case-insensitive search matching.
467−let ext = path.extension().map(|e| e.to_lowercase());
468− 
469−// Bad: restates code
470−// Extract file extension and convert to lowercase
471−let ext = path.extension().map(|e| e.to_lowercase());
472− 
473−// Good: explains consequence
474−// Preserve ephemeral UUIDs so tags attached during browsing survive promotion to managed location.
475−let uuid = ephemeral_cache.get(path).unwrap_or_else(|| Uuid::new_v4());
476− 
477−// Bad: verbose explanation of obvious behavior
478−// UUID assignment strategy:
479−// 1. First check if there's an ephemeral UUID
480−// 2. If not, generate a new one
481−let uuid = ephemeral_cache.get(path).unwrap_or_else(|| Uuid::new_v4());
482−```
483− 
484−**Error handling comments:**
485−Explain strategy and recovery, not just "log and continue".
486− 
487−```rust
488−// Good: explains recovery
489−// Best-effort: continue with remaining moves, stale paths cleaned up on next reindex.
490−Err(e) => ctx.log(format!("Failed to move: {}", e)),
491− 
492−// Bad: states the obvious
493−// Log error but continue
494−Err(e) => ctx.log(format!("Failed to move: {}", e)),
495−```
496− 
497−**Platform-specific comments:**
498−Explain consequences, not implementation blockers.
499− 
500−```rust
501−// Good: explains why and fallback
502−#[cfg(windows)]
503−pub fn get_inode(_metadata: &std::fs::Metadata) -> Option<u64> {
504− // Windows file indices are unstable across reboots; fall back to path-only matching.
505− None
506−}
507− 
508−// Bad: over-explains implementation details
509−#[cfg(windows)]
510−pub fn get_inode(_metadata: &std::fs::Metadata) -> Option<u64> {
511− // Windows doesn't have inodes.
512− // The method `file_index()` is unstable (issue #63010).
513− // Returning None is safe as the field is Optional.
514− None
515−}
516−```
517− 
518−**Never use:**
519−- Placeholder comments ("for now", "TODO: extract this later")
520−- Markdown formatting (`**bold**`, `_italic_`) in code comments
521−- ASCII diagrams (put those in `/docs/` if needed)
522−- Section divider comments (`// ========== Section ==========`)
523−- Comments explaining removed code during refactors
524− 
525−Track future work in GitHub issues, not code comments.
526− 
527−### Formatting
528− 
529−Run `cargo fmt` before committing. Tabs for indentation. No emojis.
530− 
531−## Logging
532− 
533−### Setup
534− 
535−Use `tracing_subscriber` in main or examples:
536− 
537−```rust
538−use tracing_subscriber::EnvFilter;
539− 
540−fn main() {
541− tracing_subscriber::fmt()
542− .with_env_filter(
543− EnvFilter::try_from_default_env()
544− .unwrap_or_else(|_| EnvFilter::new("sd_core=info"))
545− )
546− .init();
547−}
548−```
549− 
550−## Writing Style
551− 
552−This applies to all documentation, code comments, and design documents.
553− 
554−Use clear, simple language. Write short, impactful sentences. Use active voice. Focus on practical, actionable information.
555− 
556−Address the reader directly with "you" and "your". Support claims with data and examples when possible.
557− 
558−Avoid these constructions:
559− 
560−- Em dashes (use commas or periods)
561−- "Not only this, but also this"
562−- Metaphors and cliches
563−- Generalizations
564−- Setup language like "in conclusion"
565−- Unnecessary adjectives and adverbs
566−- Emojis, hashtags, markdown formatting in prose
567− 
568−Avoid these words:
569−comprehensive, delve, utilize, harness, realm, tapestry, unlock, revolutionary, groundbreaking, remarkable, pivotal
570− 
571−### Macros
572− 
573−Use `tracing` macros, never `println!`:
574− 
575−```rust
576−use tracing::{info, warn, error, debug};
577− 
578−info!("Server started on port {}", port);
579−debug!(file_id = %id, "Processing file");
580−warn!(error = %e, "Retrying operation");
581−error!("Failed to connect to database");
582−```
583− 
584−### Job Logging
585− 
586−Use `ctx.log()` in job implementations for automatic `job_id` tagging:
587− 
588−```rust
589−impl Job for MyJob {
590− async fn run(&mut self, ctx: &JobContext) -> Result<()> {
591− ctx.log().info("Job started");
592− ctx.log().debug!(progress = %self.progress, "Processing");
593− Ok(())
594− }
595−}
596−```
597− 
598−### Log Levels
599− 
600−- `debug`: Detailed flow for troubleshooting
601−- `info`: User-relevant events (server start, job completion)
602−- `warn`: Recoverable issues (retry, fallback)
603−- `error`: Failures requiring attention
604− 
605−### Environment Control
606− 
607−Use `RUST_LOG` environment variable:
608− 
609−```bash
610−RUST_LOG=debug cargo run --bin sd-cli
611−RUST_LOG=sd_core=trace cargo run
612−RUST_LOG=sd_core::ops=debug cargo run
613−```
614− 
615−## Testing
616− 
617−### Test Organization
618− 
619−- Unit tests: Colocated in `#[cfg(test)]` modules
620−- Integration tests: `tests/` directory at crate root
621− 
622−```rust
623−// src/ops/files/share/action.rs
624− 
625−#[cfg(test)]
626−mod tests {
627− use super::*;
628− 
629− #[tokio::test]
630− async fn test_share_file() {
631− let input = ShareFileInput {
632− file_id: 1,
633− recipient: "test@example.com".to_string(),
634− };
635− 
636− let output = share_file(input).await.unwrap();
637− assert!(!output.share_id.is_empty());
638− }
639−}
640−```
641− 
642−### Running Tests
643− 
644−```bash
645−cargo test # All tests
646−cargo test test_share_file # Specific test
647−cargo test --lib # Library tests only
648−cargo test -- --nocapture # Show output
649−```
650− 
651−## Task Tracking
652− 
653−Spacedrive uses a file-based task system in `/.tasks/` to track features, epics, and development work. All task files are version-controlled alongside the code.
654− 
655−### When to Create Tasks
656− 
657−Create tasks for work that:
658− 
659−- Introduces a new feature or capability
660−- Refactors a significant system or module
661−- Fixes a bug requiring architectural changes
662−- Implements a whitepaper specification
663− 
664−Do not create tasks for:
665− 
666−- Routine code formatting or style fixes
667−- Trivial bug fixes (single line changes)
668−- Documentation updates to existing features
669−- Dependency version bumps
670− 
671−### Task Structure
672− 
673−Each task is a Markdown file: `CATEGORY-###-title-slug.md`
674− 
675−```yaml
676−---
677−id: CORE-042
678−title: "Implement file sharing API"
679−status: "In Progress"
680−assignee: "james"
681−priority: "High"
682−tags: ["core", "networking"]
683−whitepaper: "Section 4.2" # And/or design_doc: DESIGN_DOC_NAME.md
684−---
685− 
686−## Description
687−Brief overview of what needs to be done and why.
688− 
689−## Implementation Steps
690−- [ ] Create share action in src/ops/files/share
691−- [ ] Add database schema for shares table
692−- [ ] Implement expiration logic
693− 
694−## Acceptance Criteria
695−- Share links work across all platforms
696−- Expired shares return 404
697−- Tests cover edge cases
698−```
699− 
700−### Managing Tasks
701− 
702−```bash
703−# List your active tasks
704−cargo run -p task-validator -- list --assignee "yourname" --status "In Progress"
705− 
706−# List high priority tasks
707−cargo run -p task-validator -- list --priority "High" --sort-by id
708− 
709−# Validate before committing (automatic via git hook)
710−cargo run -p task-validator -- validate
711−```
712− 
713−### Task Lifecycle
714− 
715−1. Create task file in `/.tasks/` with `status: "To Do"`
716−2. Update status to `"In Progress"` when you start work
717−3. Complete implementation and tests
718−4. Update status to `"Done"` and commit
719− 
720−Full documentation: `/docs/core/task-tracking.md`
721− 
722−## Debugging
723− 
724−### Log Files
725− 
726−Job logs live in the `job_logs` directory in the data folder root.
727− 
728−### Daemon Restart
729− 
730−After rebuilding, restart the daemon to use the latest code:
731− 
732−```bash
733−cargo build
734−cargo run --bin sd-cli -- restart
735−```
736− 
737−### Verbose Logging
738− 
739−```bash
740−RUST_LOG=debug cargo run --bin sd-daemon
741−RUST_LOG=sd_core::jobs=trace cargo run
742−```
743− 
744−## Documentation Locations
745− 
746−- Core architecture: `/docs/core/`
747−- Design docs and RFCs: `/docs/core/design/`
748−- Application docs: `/docs/`
749−- Daemon details: `/docs/core/daemon.md`
750−- Task tracking: `/docs/core/task-tracking.md`
105+- You can view the logs of a job in the job_logs directory in the root of the data folder
106+- When testing the CLI, after compiling you must first use the `restart` command to ensure the Spacedrive daemon is using the latest build.
751107  

Also from Kynth Studios

Built for the same person as RuleStack

ToolDrift

What the AI coding tools changed last night

tooldrift.kynth.studio

StillShipping

Which agent tools have stopped shipping

stillshipping.kynth.studio

BlockDex

Search inside every shadcn registry

blockdex.kynth.studio

The studio list

One product, taken apart, once a month

Kynth Studios pulls one shipped product open every month — what it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did. One email a month, nothing in between.

Double opt-in — we send one confirmation link and nothing else until you click it.

RuleStack

Built by

Kynth Studios

the studio behind ToolDrift, StillShipping and BlockDex

part of Toolproof, the measurement layer for AI agent tooling

Directory

Configs
Stacks
Compare formats
AGENTS.md vs CLAUDE.md
Cursor rules alternatives
Diff two configs
Best AGENTS.md examples
Best Cursor rules examples
What goes in a CLAUDE.md

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

© 2026 RuleStack. A Kynth Studios product. Changelog

RuleStack

The studio list

One product, taken apart, once a month

Kynth Studios pulls one shipped product open every month — what it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did. One email a month, nothing in between.

Double opt-in — we send one confirmation link and nothing else until you click it.

RuleStack

Built by

Kynth Studios

the studio behind ToolDrift, StillShipping and BlockDex

part of Toolproof, the measurement layer for AI agent tooling

Directory

Configs
Stacks
Compare formats
AGENTS.md vs CLAUDE.md
Cursor rules alternatives
Diff two configs
Best AGENTS.md examples
Best Cursor rules examples
What goes in a CLAUDE.md

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

© 2026 RuleStack. A Kynth Studios product. Changelog

RuleStack

The studio list

One product, taken apart, once a month

Kynth Studios pulls one shipped product open every month — what it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did. One email a month, nothing in between.

Double opt-in — we send one confirmation link and nothing else until you click it.

RuleStack

Built by

Kynth Studios

the studio behind ToolDrift, StillShipping and BlockDex

part of Toolproof, the measurement layer for AI agent tooling

Directory

Configs
Stacks
Compare formats
AGENTS.md vs CLAUDE.md
Cursor rules alternatives
Diff two configs
Best AGENTS.md examples
Best Cursor rules examples
What goes in a CLAUDE.md

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

© 2026 RuleStack. A Kynth Studios product. Changelog

RuleStack