xfiles

Crates.ioxfiles
lib.rsxfiles
version0.4.5
created_at2026-01-16 10:26:21.712158+00
updated_at2026-01-19 10:31:59.848263+00
descriptionPersistence of data using X, formerly known as Twitter, as a public filesystem.
homepagehttps://github.com/cryptopatrick/xfiles
repositoryhttps://github.com/cryptopatrick/xfiles
max_upload_size
id2048388
size194,340
CryptoPatrick (cryptopatrick)

documentation

https://docs.rs/xfiles

README


xfiles
XFILES

Twitter (X) as a public filesystem for AI agents.

Crates.io Downloads Documentation GitHub license

Author's bio: πŸ‘‹πŸ˜€ Hi, I'm CryptoPatrick! I'm currently enrolled as an Undergraduate student in Mathematics, at Chalmers & the University of Gothenburg, Sweden.
If you have any questions or need more info, then please join my Discord Channel: AiMath


What is xfiles β€’ Features β€’ How To Use β€’ Documentation β€’ License

πŸ›Ž Important Notices

  • Twitter API Required: Requires Twitter API v2 Bearer Token for production use
  • Storage: Uses Twitter threads as remote storage, SQLite for local indexing
  • Experimental: v0.1 is a proof-of-concept suitable for research and creative projects
  • Public by Default: All data is visible on Twitter (encryption coming in v0.2)

:pushpin: Table of Contents

Table of Contents
  1. What is xfiles
  2. Features
  3. Architecture
  4. How to Use
  5. Examples
  6. Testing
  7. Documentation
  8. License

πŸ€” What is xfiles

xfiles is a Rust library that treats Twitter as a public, append-only, log-structured filesystem. Tweets become "files", replies become "commits", and a local SQLite index keeps traversal fast.

Why? For transparent AI agents, public verifiability, distributed state, and creative experiments where Twitter serves as a globally verifiable shared memory bus.

Core Concept

Tweet (root)  β†’  File
Reply         β†’  Commit
Thread        β†’  Version history
SQLite        β†’  Local index/cache

Use Cases

  • AI Agent Memory: Agents persist state to Twitter for transparency and recovery
  • Multi-Agent Collaboration: Agents coordinate through shared Twitter threads
  • Public Audit Trails: All operations are publicly visible and timestamped
  • Distributed State: No single party controls the substrate
  • Creative Experiments: Explore novel uses of social platforms as infrastructure

πŸ“· Features

xfiles provides a complete filesystem abstraction over Twitter with persistent local caching:

πŸ”§ Core Functionality

  • Tweet as File Root: Each file starts with a root tweet
  • Reply as Commit: Updates are posted as replies, forming a version chain
  • Append-Only DAG: Git-like directed acyclic graph for version history
  • SQLite Indexing: Fast local queries without hitting Twitter API

πŸ“‚ Filesystem Operations

  • File Creation: open(path, Create) posts a root tweet
  • Reading: read() fetches content from Twitter (cached locally)
  • Writing: write(content) posts reply commits
  • History: history(path) retrieves full commit chain
  • Listing: list(dir) shows all files in a directory
  • Existence Checks: exists(path) queries local index

🐦 Twitter Integration

  • Twitter API v2: Full integration with modern Twitter API
  • Bearer Token Auth: Simple authentication with Bearer Tokens
  • Rate Limiting: Automatic backoff and retry logic
  • Chunking: Transparent splitting of content >280 characters
  • Error Handling: Robust error handling for API failures

πŸ’Ύ Persistence

  • SQLite Storage: Reliable file-based persistence
  • Commit Tracking: DAG of all commits with timestamps
  • Path Mapping: Files map to Twitter thread roots
  • Content Caching: Avoid redundant API calls
  • Session Continuity: Resume operations across restarts

πŸ“ Architecture

  1. πŸ› Overall Architecture
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           User Application (Agent/CLI/Backend)           β”‚
β”‚                Single call: fs.open().write()            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      XFS Component                       β”‚
β”‚  β€’ Open files (create root tweets)                      β”‚
β”‚  β€’ Read content (fetch from Twitter)                    β”‚
β”‚  β€’ Write updates (post reply tweets)                    β”‚
β”‚  β€’ List files (query SQLite index)                      β”‚
β”‚  β€’ Track history (traverse DAG)                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚                          β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚ Twitter Adapterβ”‚        β”‚  SQLite Store    β”‚
       β”‚  β€’ API calls   β”‚        β”‚  β€’ Commit index  β”‚
       β”‚  β€’ Rate limit  β”‚        β”‚  β€’ File mapping  β”‚
       β”‚  β€’ Chunking    β”‚        β”‚  β€’ Cache layer   β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚  Twitter API   β”‚
        β”‚  β€’ GET tweet   β”‚
        β”‚  β€’ POST tweet  β”‚
        β”‚  β€’ GET replies β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

User β†’ XFS β†’ SQLite Index + Twitter API β†’ Remote Storage

  1. πŸšƒ Data Flow Diagram
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚             file.write("Agent state v2")                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚  1. Compute     β”‚
              β”‚     Hash        β”‚
              β”‚  (blake3)       β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β”‚ content hash
                        β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚  2. Chunk          β”‚
              β”‚     Content        β”‚
              β”‚  (if >280 chars)   β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β”‚ chunks[]
                        β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚  3. Post Reply     β”‚
              β”‚     to Twitter     β”‚
              β”‚  (TwitterAdapter)  β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β”‚ tweet_id
                        β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚  4. Create Commit  β”‚
              β”‚  β€’ id = tweet_id   β”‚
              β”‚  β€’ parent = head   β”‚
              β”‚  β€’ hash, timestamp β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚  5. Store Commit   β”‚
              β”‚     in SQLite      β”‚
              β”‚  β€’ Update index    β”‚
              β”‚  β€’ Mark as head    β”‚
              β”‚  β€’ Cache content   β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. πŸ’Ύ Storage Layer Architecture
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                          XFS                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚                   Public API                        β”‚ β”‚
β”‚  β”‚  β€’ open(path, mode) β†’ XFile                         β”‚ β”‚
β”‚  β”‚  β€’ list(dir) β†’ Vec<String>                          β”‚ β”‚
β”‚  β”‚  β€’ history(path) β†’ Vec<Commit>                      β”‚ β”‚
β”‚  β”‚  β€’ exists(path) β†’ bool                              β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                               β”‚                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚               XFile Operations                       β”‚β”‚
β”‚  β”‚  β€’ read() β†’ Vec<u8>                                  β”‚β”‚
β”‚  β”‚  β€’ write(content) β†’ Result<()>                       β”‚β”‚
β”‚  β”‚  β€’ delete() β†’ Result<()>                             β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚        SQLite Database (file.db)     β”‚
              β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
              β”‚  β”‚            files                β”‚ β”‚
              β”‚  β”‚  - path (PK)                    β”‚ β”‚
              β”‚  β”‚  - root_tweet_id                β”‚ β”‚
              β”‚  β”‚  - created_at                   β”‚ β”‚
              β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
              β”‚                                      β”‚
              β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
              β”‚  β”‚           commits               β”‚ β”‚
              β”‚  β”‚  - tweet_id (PK)                β”‚ β”‚
              β”‚  β”‚  - parent_id (JSON array)       β”‚ β”‚
              β”‚  β”‚  - timestamp                    β”‚ β”‚
              β”‚  β”‚  - author                       β”‚ β”‚
              β”‚  β”‚  - hash (blake3)                β”‚ β”‚
              β”‚  β”‚  - mime                         β”‚ β”‚
              β”‚  β”‚  - size                         β”‚ β”‚
              β”‚  β”‚  - head (boolean)               β”‚ β”‚
              β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
              β”‚                                      β”‚
              β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
              β”‚  β”‚           chunks                β”‚ β”‚
              β”‚  β”‚  - tweet_id (PK)                β”‚ β”‚
              β”‚  β”‚  - parent_commit (FK)           β”‚ β”‚
              β”‚  β”‚  - idx (chunk order)            β”‚ β”‚
              β”‚  β”‚  - size, hash                   β”‚ β”‚
              β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. ⏳ Commit Lifecycle
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            User calls file.write(content)            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  1. Chunk Content                      β”‚
β”‚  β€’ Split into 280-byte chunks if needed                β”‚
β”‚  β€’ Compute blake3 hash of full content                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              2. Post to Twitter API                    β”‚
β”‚  β€’ Post first chunk as reply to current head           β”‚
β”‚  β€’ Post remaining chunks as reply chain                β”‚
β”‚  β€’ Receive tweet_id for each chunk                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 3. Create Commit Object                β”‚
β”‚  β€’ id = first chunk tweet_id                           β”‚
β”‚  β€’ parents = [current_head]                            β”‚
β”‚  β€’ hash = content hash                                 β”‚
β”‚  β€’ timestamp = now()                                   β”‚
β”‚  β€’ author = username                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              4. Persist to SQLite                      β”‚
β”‚  β€’ INSERT INTO commits                                 β”‚
β”‚  β€’ UPDATE files SET head                               β”‚
β”‚  β€’ Cache content for fast reads                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              5. Publicly Visible on Twitter            β”‚
β”‚  β€’ Tweet URL: https://twitter.com/i/web/status/{id}   β”‚
β”‚  β€’ Timestamped by Twitter                              β”‚
β”‚  β€’ Immutable and auditable                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš™ How to Use

Installation

Add xfiles to your Cargo.toml:

[dependencies]
xfiles = "0.1"
tokio = { version = "1", features = ["full"] }

Or install with cargo:

cargo add xfiles

Twitter API Setup

Before using xfiles with real Twitter, you need API credentials:

  1. Go to https://developer.twitter.com/en/portal/dashboard
  2. Create a project and app
  3. Generate Bearer Token under "Keys and tokens"
  4. See docs/TWITTER_SETUP.md for detailed instructions
export TWITTER_BEARER_TOKEN="your_bearer_token_here"
export TWITTER_USERNAME="your_username"

Basic Example (Mock Adapter)

use xfiles::*;
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<()> {
    // Use mock adapter for testing (no Twitter API needed)
    let adapter = Arc::new(MockAdapter::new());
    let mut fs = XFS::with_adapter("agent", adapter, Some(":memory:")).await?;

    // Create and write to file
    let mut file = fs.open("memory.txt", OpenMode::Create).await?;
    file.write(b"Agent state v1").await?;

    // Read it back
    let content = file.read().await?;
    println!("{}", String::from_utf8_lossy(&content));

    // Multiple writes create commit chain
    file.write(b"Agent state v2").await?;
    file.write(b"Agent state v3").await?;

    // Get history
    let history = fs.history("memory.txt").await?;
    println!("Total commits: {}", history.len());

    Ok(())
}

Real Twitter API Example

use xfiles::*;

#[tokio::main]
async fn main() -> Result<()> {
    let bearer_token = std::env::var("TWITTER_BEARER_TOKEN")?;

    // Connect with real Twitter API
    let mut fs = XFS::connect("@myagent", &bearer_token).await?;

    // Create file (posts root tweet)
    let mut file = fs.open("agent_memory.txt", OpenMode::Create).await?;

    // Write content (posts reply tweet)
    file.write(b"Day 1: Agent initialized").await?;

    // Read it back (fetches from Twitter)
    let content = file.read().await?;

    println!("Content: {}", String::from_utf8_lossy(&content));
    println!("Tweet URL: https://twitter.com/i/web/status/{}", file.head());

    Ok(())
}

Advanced Usage

use xfiles::*;

#[tokio::main]
async fn main() -> Result<()> {
    let bearer_token = std::env::var("TWITTER_BEARER_TOKEN")?;
    let mut fs = XFS::connect("@myagent", &bearer_token).await?;

    // Create multiple files
    let mut memory = fs.open("agent/memory.json", OpenMode::Create).await?;
    let mut log = fs.open("agent/debug.log", OpenMode::Create).await?;

    // Write to different files
    memory.write(br#"{"state": "active", "version": 1}"#).await?;
    log.write(b"[INFO] Agent started").await?;

    // List all files
    let files = fs.list("agent").await?;
    println!("Files in agent/: {:?}", files);

    // Get full history of a file
    let history = fs.history("agent/memory.json").await?;
    for (i, commit) in history.iter().enumerate() {
        println!("Commit {}: {} at {}",
            i + 1,
            commit.id,
            commit.timestamp
        );
    }

    // Check file existence
    if fs.exists("agent/config.toml").await? {
        println!("Config file exists");
    }

    Ok(())
}

πŸ§ͺ Examples

The repository includes several examples demonstrating different features:

# Mock adapter example (no Twitter API needed)
cargo run --example basic

# Real Twitter API example (requires credentials)
export TWITTER_BEARER_TOKEN="your_token"
cargo run --example twitter_real

Example Output

=== xfiles Basic Example ===

1. Creating a new file...
   βœ“ Created file: memory.txt

2. Writing to file...
   βœ“ Wrote initial content

3. Reading file content...
   Content: Day 1: Agent initialized

4. Writing multiple updates...
   βœ“ Created commit chain

5. Reading latest version...
   Latest: Day 3: Successfully stored memory

6. Getting file history...
   Total commits: 4
   Commit 1: mock_tweet_1 (2026-01-16 12:28:15 UTC)
   Commit 2: mock_tweet_2 (2026-01-16 12:28:15 UTC)
   Commit 3: mock_tweet_3 (2026-01-16 12:28:15 UTC)
   Commit 4: mock_tweet_4 (2026-01-16 12:28:15 UTC)

πŸ§ͺ Testing

Run the test suite:

# Run all tests (uses mock adapter)
cargo test

# Run specific test suite
cargo test --test tests

# Run with output
cargo test -- --nocapture

All tests use the MockAdapter, so no Twitter API credentials are needed for testing.

πŸ“š Documentation

Comprehensive documentation is available:

Key Concepts

  • Files: Mapped to Twitter thread roots, tracked in SQLite
  • Commits: Each write creates a new tweet reply
  • DAG: Git-like directed acyclic graph for version history
  • Chunking: Content >280 chars automatically split across multiple tweets
  • Caching: SQLite caches content to minimize API calls

Performance Notes

  • Reads: Cached in SQLite (no API call on cache hit)
  • Writes: Rate-limited by Twitter API (300 tweets/15min)
  • Chunking: Transparent for content > 280 chars
  • Rate Limiting: Automatic exponential backoff

Twitter API v2 Free Tier limits:

  • 50 tweet reads / 15 min
  • 300 tweet posts / 15 min

πŸ–Š Author

CryptoPatrick

Keybase Verification: https://keybase.io/cryptopatrick/sigs/8epNh5h2FtIX1UNNmf8YQ-k33M8J-Md4LnAN

🐣 Support

Leave a ⭐ if you think this project is cool.

πŸ—„ License

This project is licensed under MIT. See LICENSE for details.


Inspired by:

  • Git (DAG commits, history)
  • IPFS (content-addressed chunks)
  • CRDTs (distributed updates)
  • Blockchains (timestamped logs)

Made with β˜• for transparent AI agents

Commit count: 11

cargo fmt