Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

AnyFS - Technical Comparison with Alternatives

This document compares AnyFS with existing Rust filesystem abstractions.


Executive Summary

AnyFS is to filesystems what Axum/Tower is to HTTP: a composable middleware stack with pluggable backends.

Key differentiators:

  • Composable middleware - Stack quota, sandboxing, tracing, caching as independent layers
  • Backend agnostic - Swap Memory/SQLite/RealFS without code changes
  • Policy separation - Storage logic separate from policy enforcement
  • Third-party extensibility - Custom backends and middleware depend only on anyfs-backend

Compared Solutions

SolutionWhat it isMiddlewareMultiple Backends
vfsVFS trait + backendsNoYes
AgentFSSQLite agent runtimeNoNo (SQLite only)
OpenDALObject storage layerYesYes (cloud-focused)
AnyFSVFS + middleware stackYesYes

1. Architecture Comparison

vfs Crate

Path-based trait, no middleware pattern:

#![allow(unused)]
fn main() {
pub trait FileSystem: Send + Sync {
    fn read_dir(&self, path: &str) -> VfsResult<Box<dyn Iterator<Item = String>>>;
    fn open_file(&self, path: &str) -> VfsResult<Box<dyn SeekAndRead>>;
    fn create_file(&self, path: &str) -> VfsResult<Box<dyn SeekAndWrite>>;
    // ...
}
}

Limitations:

  • No standard way to add quotas, logging, sandboxing
  • Each concern must be built into backends or wrapped externally
  • Path validation is backend-specific

AgentFS

SQLite-based agent runtime:

#![allow(unused)]
fn main() {
// Fixed to SQLite, includes KV store and tool auditing
let fs = AgentFS::open("agent.db")?;
fs.write_file("/path", data)?;
fs.kv_set("key", "value")?;  // KV store bundled
fs.toolcall_start("tool")?;  // Auditing bundled
}

Limitations:

  • Locked to SQLite (no memory backend for testing, no real FS)
  • Monolithic design (can’t use FS without KV/auditing)
  • No composable middleware

AnyFS

Tower-style middleware + pluggable backends:

#![allow(unused)]
fn main() {
use anyfs::{MemoryBackend, QuotaLayer, PathFilterLayer, RestrictionsLayer, TracingLayer, FileStorage};

// Compose middleware stack
let backend = MemoryBackend::new()
    .layer(QuotaLayer::builder()
        .max_total_size(100 * 1024 * 1024)
        .build())
    .layer(PathFilterLayer::builder()
        .allow("/workspace/**")
        .deny("**/.env")
        .build())
    .layer(TracingLayer::new());

let fs = FileStorage::new(backend);
}

Advantages:

  • Add/remove middleware without touching backends
  • Swap backends without touching middleware
  • Third-party extensions via anyfs-backend trait

2. Feature Comparison

FeatureAnyFSvfsAgentFSOpenDAL
Middleware patternYesNoNoYes
Multiple backendsYesYesNoYes
SQLite backendYesNoYesNo
Memory backendYesYesNoYes
Real FS backendYesYesNoNo
Quota enforcementMiddlewareManualNoNo
Path sandboxingMiddlewareManualNoNo
Feature gatingMiddlewareNoNoNo
Rate limitingMiddlewareNoNoNo
Tracing/loggingMiddlewareManualBuilt-inMiddleware
Streaming I/OYesYesYesYes
Async APIFuturePartialNoYes
POSIX extensionFutureNoNoNo
FUSE mountableYesNoNoNo
KV storeNoNoYesNo

3. Middleware Stack

AnyFS middleware can intercept, transform, and control operations:

MiddlewareInterceptsAction
QuotaWritesReject if over limit
PathFilterAll opsBlock denied paths
RestrictionsPermission changesBlock via .deny_permissions()
RateLimitAll opsThrottle per second
ReadOnlyWritesBlock all writes
TracingAll opsLog with tracing crate
DryRunWritesLog without executing
CacheReadsLRU caching
OverlayAll opsUnion filesystem
CustomAnyEncryption, compression, …

4. Backend Trait

#![allow(unused)]
fn main() {
pub trait Fs: Send + Sync {
    fn read(&self, path: &Path) -> Result<Vec<u8>, FsError>;
    fn write(&self, path: &Path, data: &[u8]) -> Result<(), FsError>;
    fn open_read(&self, path: &Path) -> Result<Box<dyn Read + Send>, FsError>;
    fn open_write(&self, path: &Path) -> Result<Box<dyn Write + Send>, FsError>;
    // ... methods aligned with std::fs
}
}

Design principles:

  • &Path in core traits (object-safe); FileStorage/FsExt accept impl AsRef<Path> for ergonomics
  • Aligned with std::fs naming
  • Streaming I/O via open_read/open_write
  • Send bound for async compatibility

5. When to Use What

Use CaseRecommendation
Need composable middlewareAnyFS
Need backend flexibilityAnyFS
Need SQLite + Memory + RealFSAnyFS
Need just VFS abstraction (no policies)vfs
Need AI agent runtime with KV + auditingAgentFS
Need cloud object storageOpenDAL
Need async-first designOpenDAL (or wait for AnyFS async)

6. Deep Dive: vfs Crate Compatibility

The vfs crate is the most similar project. This section details why we don’t adopt their trait and how we’ll provide interop.

vfs::FileSystem Trait (Complete)

#![allow(unused)]
fn main() {
pub trait FileSystem: Send + Sync {
    // Required (9 methods)
    fn read_dir(&self, path: &str) -> VfsResult<Box<dyn Iterator<Item = String>>>;
    fn create_dir(&self, path: &str) -> VfsResult<()>;
    fn open_file(&self, path: &str) -> VfsResult<Box<dyn SeekAndRead>>;
    fn create_file(&self, path: &str) -> VfsResult<Box<dyn SeekAndWrite>>;
    fn append_file(&self, path: &str) -> VfsResult<Box<dyn SeekAndWrite>>;
    fn metadata(&self, path: &str) -> VfsResult<VfsMetadata>;
    fn exists(&self, path: &str) -> VfsResult<bool>;
    fn remove_file(&self, path: &str) -> VfsResult<()>;
    fn remove_dir(&self, path: &str) -> VfsResult<()>;

    // Optional - default to NotSupported (6 methods)
    fn set_creation_time(&self, path: &str, time: SystemTime) -> VfsResult<()>;
    fn set_modification_time(&self, path: &str, time: SystemTime) -> VfsResult<()>;
    fn set_access_time(&self, path: &str, time: SystemTime) -> VfsResult<()>;
    fn copy_file(&self, src: &str, dest: &str) -> VfsResult<()>;
    fn move_file(&self, src: &str, dest: &str) -> VfsResult<()>;
    fn move_dir(&self, src: &str, dest: &str) -> VfsResult<()>;
}
}

Feature Gap Analysis

FeaturevfsAnyFSGap
Basic read/writeYesYes-
Directory opsYesYes-
Streaming I/OYesYes-
renamemove_fileYes-
copycopy_fileYes-
SymlinksNoYesCritical
Hard linksNoYesCritical
PermissionsNoYesCritical
truncateNoYesMissing
sync/fsyncNoYesMissing
statfsNoYesMissing
read_rangeNoYesMissing
symlink_metadataNoYesMissing
Path type&str&Path (core) + impl AsRef<Path> in ergonomic layerDifferent
MiddlewareNoYesArchitectural

Why Not Adopt Their Trait?

  1. No symlinks/hardlinks - Can’t virtualize real filesystem semantics
  2. No permissions - Our Restrictions middleware needs set_permissions to gate
  3. No durability primitives - No sync/fsync for data integrity
  4. No middleware pattern - Their VfsPath bakes in behaviors we want composable
  5. &str paths - Core traits use &Path for object safety; ergonomics come from FileStorage/FsExt

Our trait is a strict superset. Everything vfs can do, we can do. The reverse is not true.

vfs Backends

vfs BackendAnyFS EquivalentNotes
PhysicalFSStdFsBackendBoth use real filesystem directly
MemoryFSMemoryBackendBoth in-memory
OverlayFSOverlay<B1,B2>Both union filesystems
AltrootFSVRootFsBackendBoth provide path containment
EmbeddedFS(none)Read-only embedded assets
(none)SqliteBackendWe have SQLite

Interoperability Plan

Future anyfs-vfs-compat crate provides bidirectional adapters:

#![allow(unused)]
fn main() {
use anyfs_vfs_compat::{VfsCompat, AnyFsCompat};

// Use a vfs backend in AnyFS
// Missing features return FsError::NotSupported
let backend = VfsCompat::new(vfs::MemoryFS::new());
let fs = FileStorage::new(backend);

// Use an AnyFS backend in vfs-based code
// Only exposes what vfs supports
let anyfs_backend = MemoryBackend::new();
let vfs_fs: Box<dyn vfs::FileSystem> = Box::new(AnyFsCompat::new(anyfs_backend));
}

Use cases:

  • Migrate from vfs to AnyFS incrementally
  • Use vfs::EmbeddedFS in AnyFS (read-only embedded assets)
  • Use AnyFS backends in projects depending on vfs

7. Tradeoffs

AnyFS Advantages

  • Composable middleware pattern
  • Backend-agnostic
  • Third-party extensibility
  • Clean separation of concerns
  • Full filesystem semantics (symlinks, permissions, durability)

AnyFS Limitations

  • Sync-first (async planned)
  • Smaller ecosystem (new project)
  • Not full POSIX emulation

If this document conflicts with AGENTS.md or src/architecture/design-overview.md, treat those as authoritative.