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

Open Questions & Future Considerations

Status: Resolved (future considerations tracked) Last Updated: 2025-12-28


This document captures previously open questions and design considerations. Unless explicitly marked as future, the items below are resolved.

Note: Final decisions live in the Architecture Decision Records.


Status: Resolved

Decision

  • Symlink support is a backend capability (via FsLink).
  • FileStorage resolves paths via pluggable PathResolver for non-SelfResolving backends.
  • The default IterativeResolver follows symlinks when FsLink is available. Custom resolvers can implement different behaviors.
  • SelfResolving backends delegate to the OS. strict-path prevents escapes.

Implications

  • If you need symlink-free semantics, use a backend that does not implement FsLink, or if using a backend that does implement FsLink, ensure no preexisting symlinks exist in the data (the FsLink trait provides creation capability, but you can choose not to call those methods).
  • Restrictions middleware controls permission-related operations only, not symlink creation (which is a trait-level capability).

Why

  • Virtual backends have no host filesystem to escape to; symlink resolution stays inside the virtual structure.
  • OS-backed backends cannot reliably disable symlink following without TOCTOU risks or platform-specific hacks.

Virtual vs Real Backends: Path Resolution

Status: Resolved (see also ADR-033 for PathResolver)

Question: Should path resolution logic be different for virtual backends (memory, SQLite) vs filesystem-based backends (StdFsBackend, VRootFsBackend)?

Resolution: FileStorage handles path resolution via pluggable PathResolver trait for non-SelfResolving backends. SelfResolving backends delegate to the OS, so FileStorage does not pre-resolve paths for them.

Backend TypePath ResolutionSymlink Handling
MemoryBackendPathResolver (default: IterativeResolver)Resolver follows symlinks
SqliteBackendPathResolver (default: IterativeResolver)Resolver follows symlinks
VRootFsBackendOS (implements SelfResolving)OS follows symlinks (strict-path prevents escapes)

Key design decisions:

  1. Backends that wrap a real filesystem implement the SelfResolving marker trait to tell FileStorage to skip resolution:
#![allow(unused)]
fn main() {
impl SelfResolving for VRootFsBackend {}
}
  1. Path resolution is pluggable via PathResolver trait (ADR-033). Built-in resolvers include:
    • IterativeResolver - default symlink-aware resolution (when backend implements FsLink)
    • NoOpResolver - for SelfResolving backends
    • CachingResolver - LRU cache wrapper around another resolver

Compression and Encryption

Question: Does the current design allow backends to compress/decompress or encrypt/decrypt files transparently?

Answer: Yes. The backend receives the data and stores it however it wants. A backend could:

  • Compress data before writing to SQLite
  • Encrypt blobs with a user-provided key
  • Use a remote object store with encryption at rest

This is an implementation detail of the backend, not visible to the FileStorage API.


Hooks and Callbacks

Question: Should AnyFS support hooks or callbacks for file operations (e.g., audit logging, validation)?

Considerations:

  • AgentFS (see comparison below) provides audit logging as a core feature
  • Hooks add complexity but enable powerful use cases
  • Could be implemented as a middleware pattern around FileStorage

Resolution: Implemented via Tracing middleware. Users can also wrap FileStorage or backends for custom hooks.


AgentFS Comparison

Note: There are two projects named “AgentFS”:

ProjectDescription
tursodatabase/agentfsFull AI agent runtime (Turso/libSQL)
cryptopatrick/agentfsRelated to AgentDB abstraction layer

This section focuses on Turso’s AgentFS, which has a published spec.

What AgentFS Provides

AgentFS is an agent runtime, not just a filesystem. It provides three integrated subsystems:

  1. Virtual Filesystem - POSIX-like, inode-based, chunked storage in SQLite
  2. Key-Value Store - Agent state and context storage
  3. Tool Call Audit Trail - Records all tool invocations for debugging/compliance

AnyFS vs AgentFS: Different Abstractions

ConcernAnyFSAgentFS
ScopeFilesystem abstractionAgent runtime
FilesystemFullFull
Key-Value storeNot our domainIncluded
Tool auditingTracing middlewareBuilt-in
BackendsMemory, SQLite, VRootFs, customSQLite only (spec)
MiddlewareComposable layersMonolithic

Relationship Options

AnyFS could be used BY AgentFS:

  • AgentFS could implement its filesystem portion using Fs trait
  • Our middleware (Quota, PathFilter, etc.) would work with their system

AgentFS-compatible backend for AnyFS:

  • Someone could implement Fs using AgentFS’s SQLite schema
  • Would enable interop with AgentFS tooling

What we should NOT do:

  • Add KV store to Fs (different abstraction, scope creep)
  • Add tool call auditing to core trait (that’s what Tracing middleware is for)

When to Use Which

Use CaseRecommendation
Need just filesystem operationsAnyFS
Need composable middleware (quota, sandboxing)AnyFS
Need full agent runtime (FS + KV + auditing)AgentFS
Need multiple backend types (memory, real FS)AnyFS
Need AgentFS-compatible SQLite formatAgentFS or custom AnyFS backend

Takeaway

AnyFS and AgentFS solve different problems at different layers:

  • AnyFS = filesystem abstraction with composable middleware
  • AgentFS = complete agent runtime with integrated storage

They can complement each other rather than compete.


VFS Crate Comparison

The vfs crate provides virtual filesystem abstractions with:

  • PhysicalFS: Host filesystem access
  • MemoryFS: In-memory storage
  • AltrootFS: Rooted filesystem (similar to our VRootFsBackend)
  • OverlayFS: Layered filesystem
  • EmbeddedFS: Compile resources into binary

Similarities with AnyFS:

  • Trait-based abstraction over storage
  • Memory and physical filesystem backends

Differences:

  • VFS doesn’t have SQLite backend
  • VFS doesn’t have policy/quota layer
  • AnyFS focuses on isolation and limits

Why not use VFS? VFS is a good library, but AnyFS’s design goals differ:

  1. We want SQLite as a first-class backend
  2. We need quota/limit enforcement
  3. We want feature whitelisting (least privilege)

FUSE Mount Support

Status: Designed - Part of anyfs crate (feature flags: fuse, winfsp)

What is FUSE? FUSE (Filesystem in Userspace) allows implementing filesystems in userspace rather than kernel code. It enables:

  • Mounting any backend as a real filesystem
  • Using standard Unix tools (ls, cat, etc.) on AnyFS containers
  • Integration with existing workflows

Resolution: Part of anyfs crate with feature flags:

  • Linux: FUSE (native) - fuse feature
  • macOS: macFUSE - fuse feature
  • Windows: WinFsp - winfsp feature

See Cross-Platform Mounting for full details.


Type-System Protection for Cross-Container Operations

Status: Resolved - User-defined wrapper types

Question: Should we use the type system to prevent accidentally mixing data between containers?

Resolution: Users who need type-safe domain separation can create wrapper types:

#![allow(unused)]
fn main() {
use anyfs_sqlite::SqliteBackend;  // Ecosystem crate

// User-defined wrapper types provide compile-time safety
struct SandboxFs(FileStorage<MemoryBackend>);
struct UserDataFs(FileStorage<SqliteBackend>);

let sandbox = SandboxFs(FileStorage::new(MemoryBackend::new()));
let userdata = UserDataFs(FileStorage::new(SqliteBackend::open("data.db")?));

fn process_sandbox(fs: &SandboxFs) { /* only accepts SandboxFs */ }

process_sandbox(&sandbox);   // OK
process_sandbox(&userdata);  // Compile error - different type!
}

This approach avoids generic parameter complexity while still enabling compile-time safety when needed. See FileStorage for details.


Naming Considerations

Based on review feedback, the following naming concerns were raised:

Current NameConcernAlternatives Considered
anyfs-traits“traits” is vagueanyfs-backend (adopted)
anyfs-containerCould imply DockerMerged into anyfs (adopted)
anyfsSounds like Hebrew “ani efes” (I am zero)anyfs retained for simplicity

Decision: Renamed anyfs-traits to anyfs-backend. Merged anyfs-container into anyfs.


POSIX Behavior

Question: How POSIX-compatible should AnyFS be?

Answer: AnyFS is not a POSIX emulator. We use std::fs-like naming and semantics for familiarity, but we don’t aim for full POSIX compliance. Specific differences:

  • Symlink-aware path resolution (FileStorage walks the virtual structure using metadata() and read_link())
  • No file descriptors or open file handles in the basic API
  • Simplified permissions model
  • No device files, FIFOs, or sockets

Async Support

Question: Should Fs traits be async?

Decision: Sync-first, async-ready (see ADR-010).

Rationale:

  • Built-in backends are naturally synchronous (std::fs, memory)
  • Ecosystem backends are also sync (e.g., rusqlite is sync)
  • No runtime dependency (tokio/async-std) required
  • Rust 1.75+ has native async traits, so adding later is low-cost

Async-ready design:

  • Traits require Send - compatible with async executors
  • Return types are Result<T, FsError> - works with async
  • No hidden blocking state
  • Methods are stateless per-call

Future path: When needed (e.g., S3/network backends), add parallel AsyncFs trait:

  • Separate trait, not replacing Fs
  • Blanket impl possible via spawn_blocking
  • No breaking changes to existing sync API

Summary

TopicDecision
Symlink securityBackend-defined (FsLink); VRootFsBackend uses strict-path for containment
Path resolutionFileStorage (symlink-aware); VRootFs = OS via SelfResolving
Compression/encryptionBackend responsibility
Hooks/callbacksTracing middleware
FUSE mountPart of anyfs crate (fuse, winfsp feature flags)
Type-system protectionUser-defined wrapper types (e.g., struct SandboxFs(FileStorage<B>))
POSIX compatibilityNot a goal
truncateAdded to FsWrite
sync / fsyncAdded to FsSync
Async supportSync-first, async-ready (ADR-010)
Layer traitTower-style composition (ADR-011)
LoggingTracing with tracing ecosystem (ADR-012)
Extension methodsFsExt (ADR-013)
Zero-copy bytesOptional bytes feature (ADR-014)
Error contextContextual FsError (ADR-015)
BackendStack builderFluent API via .layer()
Path-based access controlPathFilter middleware (ADR-016)
Read-only modeReadOnly middleware (ADR-017)
Rate limitingRateLimit middleware (ADR-018)
Dry-run testingDryRun middleware (ADR-019)
Read cachingCache middleware (ADR-020)
Union filesystemOverlay middleware (ADR-021)