# Textile core abstractions Textile separates **where files live**, **how document bytes sync**, and **how editing UI renders**. Each layer has a narrow job; concrete backends (Habitat PDS, Yjs, Zen/Tiling) plug in at the edges. ## FileSystemProvider **Role:** Talk to a **source** about the file tree and other top-level actions. - Lists entries (sidebar): names and stable ids - `createFile()` for new persisted entries (sidebar “New document”) - Readiness and auth hints (`isReady`, `subscribeReady`) - Does **not** open document contents or run merge/sync - Pairs with a `DocumentProvider` via `documents` + `defaultEditorKind` (injected in `App.tsx`) **Examples:** `habitat-docs` (PDS record listing), future disk roots. **Key types:** `FileSystemProvider`, `FileSystemEntry` — `src/filesystem/types.ts` ## DocumentProvider **Role:** Resolve a document from local or remote storage and keep its **contents** coherent. - `openDocument(entryId)` — load/sync for an entry from `listFiles` - `createDocument()` — new in-memory or persisted doc - Transport from the source (XRPC, filesystem reads, …) - Merge / sync when needed (e.g. Yjs CRDT via `docSession`, libp2p) - Exposes `DocumentHandle`: title, `loadPromise`, `release`, **`getEditorBinding()`** (data only, no React) **Does not:** render UI or own TipTap/Yjs editor widgets. **Examples:** `HabitatDocumentsProvider` — `src/documents/providers/` **Key types:** `DocumentProvider`, `DocumentHandle` — `src/documents/types.ts` ## Editor **Role:** The **UI** that displays and edits file contents. Deeply tied to the **sync method** (Yjs + TipTap today). - Registered in `src/editors/registry.ts` (`Editor`: `{ kind, Component }`) - Shared chrome and typography: `src/editors/ui/` - Per-backend wiring: `src/editors//` (e.g. `yjs/yjsDocumentEditor.tsx`) - Consumes `EditorBinding` from `getEditorBinding()`; only the matching editor reads `payload` **Does not:** fetch from PDS, run libp2p, or list the file tree. **Entry point for workspaces:** `DocumentPane` — `src/editors/DocumentPane.tsx` **Key types:** `Editor`, `EditorKind`, `EditorBinding`, `EditorProps` — `src/editors/types.ts` ## Workspace **Role:** How **open files** are arranged on screen (tiles, splits, empty states, workspace chrome). - Subscribes to open requests from the shell sidebar - Holds `DocumentHandle`(s) via `useDocumentSlot`, calls `release()` on switch/close - Renders `DocumentSlotView` inside layout — does not import Habitat or Yjs **Examples:** `ZenWorkspace`, `TilingWorkspace` — `src/workspaces/` ## Composition (`App.tsx`) ```ts const habitatDocuments = new HabitatDocumentsProvider(); new HabitatFilesystemProvider({ documents: habitatDocuments, defaultEditorKind: 'yjs', }); ``` Workspaces receive `resolveProvider` → `fs.documents.openDocument(entryId)` → `DocumentPane handle={…}`. ## Adding a new backend 1. **New source only (same Yjs docs):** new `FileSystemProvider` + reuse `HabitatDocumentsProvider` or a sibling `DocumentProvider`. 2. **New sync/editor (e.g. plain markdown):** new `DocumentProvider` (or branch in existing) returning `{ kind: 'markdown', payload }`; add `editors/markdown/` + register in `editors/registry.ts`. 3. **New layout:** new workspace under `src/workspaces/`; reuse `DocumentPane` and `DocumentHandle`.