-
Notifications
You must be signed in to change notification settings - Fork 11
[PROTOTYPE] CRDT Collaborative Editing with Yjs #2272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
jkomoros
wants to merge
10
commits into
main
Choose a base branch
from
feature/crdt-collaborative-editing
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Planning document for adding real-time collaborative editing to ct-code-editor and a new ct-richtext-editor component using Yjs. Key decisions: - Use Yjs (not Automerge) - complementary to existing Cell system - Component-level integration (not framework-wide) - Cell stores plain text/HTML (no CRDT persistence) - Zero changes to Chronicle, Cell, or transaction system Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
Decisions made: - Embed y-websocket in toolshed (not separate process) - Use direct Cell entity ID for room IDs - Reuse toolshed auth for WebSocket - Server initializes Y.Doc from Cell on room creation Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
Phase 1 & 2 of CRDT collaborative editing implementation: Server-side (toolshed): - Add Yjs WebSocket server at /api/collab/:roomId - Add yjs, y-protocols, lib0 dependencies - Endpoints: GET /api/collab/stats, WebSocket upgrade, POST init Client-side (ct-code-editor): - Add collaborative, roomId, collabUrl, userName, userColor props - Integrate y-codemirror.next for real-time sync - Add yjs, y-codemirror.next, y-websocket, lib0 dependencies - Update JSX type definitions for new props Uses Yjs (not Automerge) as a thin sync layer that complements existing Cell system. Cell handles persistence, Yjs handles real-time sync. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
Add a new TipTap-based rich text editor component with real-time collaborative editing support via Yjs: - ct-richtext-editor: TipTap editor with StarterKit extensions - Collaboration extension for real-time sync via y-prosemirror - CollaborationCursor extension for cursor presence - Full rich text support (headings, bold, italic, lists, code, etc.) - Same collaborative API as ct-code-editor (collaborative, roomId, etc.) New dependencies: - @tiptap/core, @tiptap/pm, @tiptap/starter-kit - @tiptap/extension-collaboration, @tiptap/extension-collaboration-cursor - y-prosemirror Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
- Add _initializeRoomOnServer method to ct-code-editor and ct-richtext-editor - Add security documentation in collab.index.ts (auth TODO for production) - Add bundle optimization notes in component imports - Update session doc with Phase 4 progress Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
Server changes: - Rename initializeRoomContent -> initializeTextField (generic field name) - Rename getRoomContent -> getTextField (generic field name) - Remove component-specific knowledge (codemirror/prosemirror types) - Server is now a pure Yjs sync relay Client changes: - Remove _initializeRoomOnServer method (not needed) - Add sync-based initialization (clients init from Cell on first sync) - All component-specific logic now lives in the components This keeps the server simple and idiomatic while putting complexity where it belongs - in the client components. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
- Mark all polish items as complete - Update status to ready for review - Document client-side initialization approach - Note server simplification Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
Implements identity-based authentication for collaborative WebSocket connections: Server-side (toolshed): - Add collab.auth.ts with CollabAuthToken verification using VerifierIdentity - Update handler to extract and verify auth tokens from URL params - Pass authenticated userIdentity to YjsServer for logging - Tokens are signed payloads with roomId, timestamp, userDid Client-side (ui): - Add collab-auth.ts helper to sign auth tokens using Cell's Signer - Update ct-code-editor and ct-richtext-editor to sign and pass tokens - Auth tokens appended as URL query params (?payload=&sig=&did=) Auth flow: 1. Component gets Signer from cell.runtime.storageManager.as 2. Signs payload with roomId, timestamp, userDid 3. Passes token in WebSocket URL 4. Server verifies signature using VerifierIdentity.fromDid() 5. Anonymous connections still allowed for now (TODO: enforce when ready) Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
Adds documentation explaining that collaborative mode implies full presence sharing (cursor visibility = consent): - Session log: Added "Presence/Privacy Model" decision section - Component JSDoc: Added PRIVACY NOTE to collaborative prop documentation explaining that cursor position and userName are visible to all room members The distinctive colored cursors serve as the visual consent indicator - users who see collaborative cursors know they are in a shared session. This follows the Google Docs model. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <[email protected]> Co-Authored-By: Happy <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is an exploration/proof-of-concept, not a proposal to merge. The goal was to understand how real-time collaborative editing could integrate with the existing architecture.
What This Explores
Adds CRDT-based real-time collaborative editing to
ct-code-editorand a newct-richtext-editorcomponent using Yjs.Key Components
Server (toolshed):
/api/collab/:roomIdClient (ui):
ct-code-editor- addedcollaborativeprop with y-codemirror.nextct-richtext-editor- new TipTap-based component with Yjs collaborationcell.runtime.storageManager.asDesign Decisions Explored
What's Working
Open Questions / Not Addressed
Files Changed
See
docs/SESSION-crdt-collaborative-editing.mdfor detailed implementation notes and decisions.🤖 Generated with Claude Code
Summary by cubic
Adds Yjs-based real-time collaboration to code and rich text editors, backed by a simple WebSocket relay in toolshed with optional identity-based auth. Enables multi-user live sync, cursors, and initial content sync from Cells without touching Chronicle.
New Features
Refactors
Written for commit a1d3342. Summary will update automatically on new commits.