Files
shard-wiki/research/260614-localfirst-workspaces-deep-dive/findings.md
tegwick 3e0c05a2b3 research: local-first workspaces cohort deep dive (Anytype/AFFiNE/AppFlowy) — CRDT substrate; UC-64/65
Combined cohort memo for the three open-source local-first all-in-one
workspaces, studied together because they share the trait none of the
prior eleven systems had: the store is a CRDT (Anytype any-sync, AFFiNE
Yjs/y-octo, AppFlowy Yrs). The cohort thesis: CRDT changes the adapter
math — the backend performs conflict-free merge itself (shard-wiki must
not impose git/text merge; speak the CRDT via a replica or stay
projection/overlay), history is a CRDT update log (supplement not git),
and the attach surface is a replica or self-host sync endpoint, with
Anytype adding P2P (no single endpoint) + E2EE (opaque). Added UC-64
(CRDT-synced shard with native merge), UC-65 (P2P/decentralized shard,
no single canonical endpoint); enriched UC-36/47/48/51/55/57/58/61.
Catalog now 65 UCs. Architecture for SHARD-WP-0002 T11/T14: merge-model
capability (proposed 13th spectrum: none/git/native-CRDT), CRDT-replica
substrate + P2P/no-central-endpoint attach mode, endpoint-model
capability, MCP as an integration surface. Boundary: CRDT local-first
candidate shards — attach a replica/projection as pages, respect native
merge, never re-drive their sync; not substrates and not the federation
layer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 16:21:08 +02:00

262 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Findings — Anytype, AFFiNE, AppFlowy: the CRDT local-first workspace cohort
Date: 2026-06-14
Source kind: **modern shipped products (cohort dive)** — three open-source, local-first
"all-in-one workspace" tools studied together; candidate shards of a **new substrate
family: CRDT-synced local-first stores**
Lens: shard-wiki — the CRDT substrate and its native-merge / P2P / E2EE implications for
the adapter contract
> Why one combined memo. Anytype, AFFiNE, and AppFlowy are the open-source local-first
> Notion/Miro alternatives, and they share the one trait the prior eleven systems never
> had: **the store is a CRDT** (Anytype's *any-sync*, AFFiNE's *Yjs/y-octo*, AppFlowy's
> *Yrs*). That single fact changes the adapter math — **the backend performs conflict-
> free merge itself**, history is a CRDT update log (not git), and content arrives as a
> replica/export, not files or rows. Studying them together isolates the *substrate*
> contribution from each tool's surface features and avoids triplicating boilerplate.
> Per-tool sections (§1§3), then the cohort thesis and what it means for shard-wiki
> (§4 onward).
Contrast set: file-store (Obsidian/Logseq), client-DB (Roam), hosted-DB (Notion),
SQLite-local+file-sync (Joplin). This cohort adds **CRDT-replica** as a substrate.
---
## 1. Anytype — P2P, E2EE, typed object graph (any-sync)
- **Substrate:** the open **any-sync** protocol — **local-first, peer-to-peer,
end-to-end encrypted** CRDT. Infrastructure is four node types: **sync, file,
consensus, coordinator**; **backup nodes store ciphertext they cannot read**. Every
change is **encrypted and signed with the user's private key**, verified via a shared
public key. Files via **IPFS**.
- **Data model:** **spaces** = graph-based databases; users define **custom object
types with relations** ("everything is an object"; a user-editable **ontology**).
Closest to Notion's typed model but **local-first + E2EE + user-owned schema**.
- **Extension:** an **open API** for integrations, **plus MCP support** (AI-agent
collaboration) — a notable modern surface (a shard speaking MCP).
- shard-wiki read: the **most decentralized + encrypted** shard yet — no single
canonical endpoint (attach a local replica or a node), content opaque without keys
(UC-61), typed object graph (UC-58), CRDT merge (UC-64).
## 2. AFFiNE — docs + whiteboard + DB as views of one block set (Yjs/BlockSuite)
- **Substrate:** **Yjs CRDT** via **y-octo** (native Rust Yjs) over **OctoBase** (Rust
local-first engine). Local-first by default; optional **WebSocket realtime** sync to
AFFiNE Cloud or self-host (MPL-2.0, Docker).
- **Editor:** **BlockSuite** — an open block-editor framework providing the **page
editor, the edgeless canvas, and block types (incl. databases/embeds)**.
- **Headline:** **docs, whiteboards, and databases are *views of the same underlying
data*** — one block set rendered as page mode, edgeless canvas, or DB views. CRDT
guarantees offline edits "merge mathematically perfectly" on reconnect.
- shard-wiki read: the **one-data-many-renderings** model shipped (ZigZag dimensions,
UC-47/48), with **non-Markdown spatial content** (edgeless canvas, UC-55) and CRDT
merge (UC-64).
## 3. AppFlowy — Rust/Flutter, Notion-style DBs over Yrs CRDT
- **Substrate:** **Yrs** (Rust Yjs) wrapped as **AppFlowy-Collab** — CRDT primitives +
persistence + domain objects (documents, **databases**, folders, importers, plugins,
user state). **Pluggable storage/sync:** RocksDB (native) / IndexedDB (wasm) locally;
**Supabase or AppFlowy Cloud** (self-hostable) for sync, via **trait-based local-only
vs cloud**.
- **Data model:** Notion-like **databases with views** (grid/board/calendar), typed
fields. Flutter UI + Rust core, modular.
- shard-wiki read: a **self-hostable CRDT Notion** — typed DBs + views (UC-58, UC-54),
CRDT merge (UC-64), self-host sync endpoint (UC-57).
---
## 4. The cohort thesis — CRDT changes the adapter math
All three converge on **CRDT-synced, local-first, open-source, self-hostable** stores
with **typed/database object models** and **non-Markdown content** (canvas/DB). The
*substrate* is the new thing, and it has four consequences shard-wiki must absorb:
1. **Native, conflict-free merge (UC-64).** The backend resolves concurrent edits
itself (Yjs/Yrs/any-sync). shard-wiki must **not impose git/text merge** on a CRDT
shard; it either speaks the CRDT (replica) or stays a **projection/overlay** that
respects CRDT semantics. This adds a **merge-model** capability:
`none → git/text → native-CRDT` — a candidate **thirteenth spectrum** for the
contract (after Joplin's content-opacity twelfth).
2. **History is a CRDT update log, not git (UC-36).** No portable commit history; the
coordination journal **supplements** (like Notion/Joplin), or shard-wiki snapshots
the replica over time.
3. **The attach surface is a replica or a sync endpoint, not files/rows.** Attach a
**local CRDT replica** (offline, full state) or the **self-host sync server's API**
(AFFiNE Cloud / AppFlowy Cloud / any-sync node). Anytype adds **P2P with no single
canonical endpoint** (UC-65) and **E2EE content opacity** (UC-61).
4. **Typed object graphs + multi-view (UC-58, UC-47/48, UC-55).** User-editable
ontologies (Anytype types/relations), Notion-style DBs (AppFlowy), and one-block-set-
many-renderings (AFFiNE page/canvas/DB) — the structured + dimensional demands the
prior dives raised, now local-first.
These are **sync layers** (any-sync, Yjs sync, AppFlowy Cloud) — like Joplin, the
**not-a-file-sync-daemon** boundary applies: shard-wiki attaches a **replica/projection
as pages** and does **not** re-implement or re-drive their CRDT sync.
---
## 5. Comparative matrix
| | Anytype | AFFiNE | AppFlowy |
|---|---------|--------|----------|
| CRDT | any-sync (custom) | Yjs (y-octo) | Yrs |
| Sync | **P2P + nodes, E2EE** | WebSocket, cloud/self-host | RocksDB local + cloud/Supabase |
| Encryption | **E2EE (default)** | optional (transport/self-host) | self-host boundary |
| Local engine | local + IPFS files | OctoBase (Rust) | RocksDB / IndexedDB |
| Data model | **typed object graph (ontology)** | blocks; **doc/canvas/DB = one data, many views** | Notion-style **DBs + views** |
| Non-MD content | objects, files | **edgeless canvas** | board/calendar/grid |
| Extension | **open API + MCP** | BlockSuite framework | Flutter/Rust modules; plugins (roadmap) |
| Self-host | backup/sync nodes | Docker (MPL-2.0) | AppFlowy Cloud |
| Markdown | export (lossy) | import/export (lossy) | import/export (lossy) |
---
## 6. Combined capability profile (as a shard)
| Capability | This cohort | Notes for the adapter contract |
|------------|-------------|--------------------------------|
| Read | yes (replica or sync API) | local CRDT replica (offline) or self-host/P2P endpoint |
| Write | yes, **CRDT-mediated** | writes are CRDT ops; respect merge — don't overwrite |
| Merge | **native CRDT (conflict-free)** | **new capability**: backend owns merge; no external git merge (UC-64) |
| Write granularity | block/object | fine-grained |
| Identity / addressing | object/block IDs (CRDT-assigned) | fine-grained, store-minted (UC-51) |
| Structure | **typed object graph / DBs + relations** | user-editable ontology (Anytype); DB views (AppFlowy) (UC-58) |
| History | **CRDT update log, not git** | supplement / snapshot (UC-36) |
| Native query | varies (graph/DB filters) | delegate where present (UC-52) |
| Subscribe | realtime CRDT sync / P2P | push by nature; attach as replica (UC-31) |
| Content opacity | **Anytype E2EE → ciphertext** | opaque without keys (UC-61) |
| Endpoint model | **replica / self-host server / P2P (Anytype)** | no single canonical URL for P2P (UC-65) |
| Content types | docs + **canvas/DB/objects** | non-Markdown (UC-55); multi-view (UC-47/48) |
| Markdown | lossy export | fidelity report (UC-59) |
| Attach modes | CRDT replica · self-host API · (Anytype) MCP/open API | new substrate row in the taxonomy |
Verdict: a **demanding but coherent new family** — best attached as a **local replica
(offline, full CRDT state)** projected to pages, or via a **self-host sync endpoint**;
Anytype additionally **P2P + E2EE** (replica-only/opaque). Standout demands:
**native-CRDT merge** (UC-64) and **P2P/no-central-endpoint + E2EE** (UC-65/UC-61).
---
## 7. Mapping to shard-wiki INTENT (compare, do not equate)
### 7.1 Reinforcements
- **Local-first sovereignty** is the cohort's whole pitch — strong INTENT alignment;
each is a legitimate sovereign shard with user-owned data.
- **Self-hostable + open-source** means shard-wiki can attach within a user's trust
boundary (good for the L0→L4 authz ladder).
- **One-data-many-views** (AFFiNE) and **typed object graphs** (Anytype/AppFlowy) are
the dimensional (UC-47/48) and structured (UC-58) demands, now validated local-first.
### 7.2 Deliberate divergences (design bugs if conflated)
1. **Do not impose git/text merge on a CRDT shard.** The backend merges; shard-wiki
respects CRDT semantics or stays a projection/overlay (UC-64). Treating a CRDT shard
like a file shard corrupts it.
2. **Not a sync daemon.** any-sync/Yjs/AppFlowy Cloud already sync; shard-wiki attaches
a **replica as pages**, never re-drives their sync (INTENT not-a-file-sync-daemon).
3. **P2P has no canonical endpoint.** Don't model the shard as a URL; attach a replica
or a named peer/node (UC-65).
4. **E2EE shards are opaque** without keys — backup/structure-shell only (UC-61).
5. **Proprietary CRDT/object formats are lossy to Markdown** — translate with a fidelity
report (UC-59), one workspace = one shard, not the federation layer.
### 7.3 What the cohort teaches that shard-wiki should keep
- Add a **merge-model** capability (`none / git / native-CRDT`) so CRDT shards are
handled correctly (UC-64) — a thirteenth capability spectrum.
- Add **CRDT-replica** to the substrate/attachment taxonomy, and **P2P/no-central-
endpoint** as a binding mode (UC-64/65).
- **MCP as an integration surface** (Anytype) is worth noting — a shard may expose an
AI-agent protocol shard-wiki could consume or coexist with.
---
## 8. Use-case seeds → catalog (promoted 2026-06-14)
Last existing UC is **UC-63**. New UCs **UC-64, UC-65** added; existing UCs enriched.
| Seed | Catalog action |
|------|----------------|
| **Attach a CRDT-synced local-first shard** whose backend performs native conflict-free merge; respect CRDT semantics (no git merge), consume a replica/export, CRDT-log history (supplement) | **UC-64 (new)** |
| **Attach a peer-to-peer / decentralized shard with no single canonical endpoint** (Anytype any-sync: replica or peer/backup node; E2EE) | **UC-65 (new)** |
| Typed object graph / user-editable ontology + Notion-style DBs, local-first | **enriches UC-58** |
| E2EE content opacity (Anytype) reinforced; self-host trust boundary | **enriches UC-61** |
| CRDT update log ≠ portable git history → supplement | **enriches UC-36** |
| One block set rendered as page / canvas / DB views (AFFiNE) | **enriches UC-47, UC-48** |
| Edgeless canvas / board / objects = non-Markdown content | **enriches UC-55** |
| Self-host sync server (AFFiNE/AppFlowy Cloud) + Anytype open API/MCP as endpoints | **enriches UC-57** |
| Object/block IDs CRDT-assigned (fine-grained) | **enriches UC-51** |
| Lossy Markdown export | links UC-59 |
---
## 9. Architecture notes for SHARD-WP-0002 (no UC)
- **Merge-model capability** (`none / git-or-text / native-CRDT`) — proposed
**thirteenth spectrum** (with Joplin's content-opacity twelfth). CRDT shards reject
external merge; shard-wiki overlays must be CRDT-aware or remain projections. (T11.)
- **Substrate taxonomy gains CRDT-replica**; **attach modes gain "local CRDT replica"
and "P2P/no-central-endpoint"** beside file-store / in-engine-host / external-API.
(T14.)
- **Endpoint model** as a capability: single URL vs self-host server vs **P2P peer set**
(Anytype) — affects how a binding is addressed and how freshness/sync work. (T14.)
- **MCP / AI-agent protocol** as a possible shard integration surface (Anytype). Note
for the extension-surface catalogue. (T14.)
- These three plus Joplin and Logseq all argue the contract must treat **substrate as a
spectrum that tools migrate along and that shard-wiki must not hard-code**.
---
## 10. Open questions (for spec / workplans)
1. For a **CRDT shard** (UC-64), does shard-wiki embed a CRDT client (Yjs/Yrs) to hold a
live replica, or only consume periodic **exports/snapshots**? The former gives
live/writable; the latter is simpler but lossy on merge timing.
2. How are **overlays** expressed against a CRDT shard — as CRDT ops (requires the
client) or as out-of-band patches reconciled later (projection-only)?
3. For **P2P shards** (UC-65), what is the "address" of the shard — a space ID + a peer/
node, a local replica path, or an invite/key? How does this fit shard attachment
config?
4. Does shard-wiki ever hold **E2EE keys** (Anytype) to project content, or only ever
treat such shards as opaque replicas/backups (UC-61)?
5. Is the **self-host sync server** (AFFiNE/AppFlowy Cloud) attached as an external API
(UC-57) or by running a co-located replica?
---
## 11. Sources
| Source | Used for |
|--------|----------|
| Anytype any-sync — Protocol overview (https://tech.anytype.io/any-sync/overview) | Local-first/P2P/E2EE CRDT; sync/file/consensus/coordinator nodes; encrypted backup |
| anyproto/any-sync (https://github.com/anyproto/any-sync) | Protocol scope; keys signed/verified; IPFS files |
| Anytype Docs (https://doc.anytype.io/anytype-docs) | Spaces, object types + relations (ontology); open API + MCP |
| toeverything/AFFiNE + DeepWiki (https://deepwiki.com/toeverything/AFFiNE) | BlockSuite (page/edgeless/DB); y-octo Yjs; OctoBase; one-data-many-views; self-host |
| AFFiNE — interactive whiteboard / blog (https://affine.pro/blog/interactive-whiteboard-app) | Edgeless canvas; CRDT offline merge |
| AppFlowy-IO/AppFlowy-Collab (https://github.com/AppFlowy-IO/AppFlowy-Collab) | Yrs CRDT; collab domain objects (documents/databases/folders); persistence |
| AppFlowy Architecture Overview — DeepWiki (https://deepwiki.com/AppFlowy-IO/AppFlowy/2-architecture-overview) | Flutter/Rust layers; pluggable storage/sync (RocksDB/IndexedDB; Supabase/AppFlowy Cloud); local vs cloud trait |
| AFFiNE vs AppFlowy vs Anytype (https://affine.pro/blog/affine-vs-appflowy-vs-anytype) | Cohort comparison framing |
Cross-references: `research/260614-notion-deep-dive/findings.md` (typed DB, hosted
contrast), `research/260614-joplin-deep-dive/findings.md` (E2EE/content opacity, sync-
daemon boundary), `research/260614-shard-spectrum-synthesis/findings.md` (the spectra
this extends), `spec/UseCaseCatalog.md` (UC-36, UC-47, UC-48, UC-51, UC-55, UC-57,
UC-58, UC-61), `workplans/SHARD-WP-0002-federation-architecture.md` (T11, T14).
---
## 12. Traceability
- New UCs: **UC-64, UC-65**`spec/UseCaseCatalog.md`.
- Enriched UCs: **UC-36, UC-47, UC-48, UC-51, UC-55, UC-57, UC-58, UC-61** (links UC-59).
- Architecture (no UC): **merge-model** capability (proposed thirteenth spectrum);
CRDT-replica substrate + P2P/no-central-endpoint attach mode; endpoint-model capability;
MCP integration surface → `SHARD-WP-0002` (T11, T14).
- Boundary recorded: Anytype/AFFiNE/AppFlowy are **CRDT local-first candidate shards**
(attach a replica/projection as pages; respect native CRDT merge; never re-drive their
sync; P2P/E2EE shards are replica-only/opaque) — not substrates, not the federation
layer (INTENT not-a-sync-daemon, graceful degradation, no silent mutation).
</content>