Local-first markdown notes with peer-to-peer sync, designed to keep the repo approachable for junior contributors. This README focuses on the essentials you need to boot, extend, and reason about the codebase quickly.
- Local markdown editor with autosave + live preview.
- Wiki-style
[[links]]with inline suggestions and keyboard navigation. - Unified editor + preview safe-areas that prevent horizontal overflow and keep typography readable on every viewport.
- Pear-end vault sharing via
pearl-vault://links (create/join) with clipboard helpers. - Theme + font switcher backed by persisted preferences.
- P2P Hyperdrive/Hyperswarm sync that keeps each device’s writer key private.
- This repo is configured as a single-writer vault; peers replicate from a single writer rather than adding new writers automatically.
- Cross-platform compatibility with graceful degradation (window controls hidden on Linux due to Electron/Bare runtime limitations).
- Install dependencies
npm install
- Build the UI bundle
npm run build:ui
- Run the Pear desktop app (builds UI via
predevautomatically)Usenpm run dev
npm run watch:uiin another terminal for live esbuild updates while developing the React UI.
- macOS & Windows: Full functionality including window controls (minimize, maximize, close)
- Linux: Full functionality with window controls gracefully hidden due to Pear runtime limitations (Electron/Bare compatibility issues)
- React 18 + Markdown-It for the renderer.
- CSS Modules +
styles/global.cssfor styling. - Pear runtime (
pear-electron,pear-bridge) for the desktop shell. - Hyperdrive + Hyperswarm + Corestore for storage/replication.
lucide-reactfor consistent, accessible icons.- Brittle for lightweight unit tests.
.
├─ index.html / ui.js / styles/global.css # renderer shell
├─ index.js / run.js # main process entry points
├─ scripts/
│ └─ build-ui.mjs # esbuild config
├─ src/
│ ├─ core/
│ │ └─ pearlCore.js # window.Pearl surface
│ ├─ pear-end/
│ │ ├─ api.js # API layer
│ │ ├─ vault/
│ │ │ ├─ vaultConfig.js # vault configuration & links
│ │ │ ├─ hyperdriveClient.js # Hyperdrive client
│ │ │ └─ crypto.js # crypto utilities
│ │ ├─ notes/
│ │ │ ├─ notesStore.js # notes CRUD operations
│ │ │ ├─ notesSerialization.js # note serialization
│ │ │ ├─ notesExportConfig.js # export configuration
│ │ │ └─ notesMirror.js # notes mirroring to disk
│ │ └─ sync/
│ │ └─ sync.js # sync functionality
│ └─ ui/
│ ├─ App.jsx
│ ├─ components/
│ │ ├─ Sidebar/
│ │ │ ├─ Sidebar.jsx
│ │ │ ├─ Sidebar.module.css
│ │ │ └─ index.js
│ │ ├─ StatusBar/
│ │ │ ├─ StatusBar.jsx
│ │ │ ├─ StatusBar.module.css
│ │ │ └─ index.js
│ │ ├─ WindowControls/
│ │ │ ├─ WindowControls.jsx # minimize/maximize/close (platform-aware)
│ │ │ ├─ WindowControls.module.css
│ │ │ └─ index.js
│ │ └─ WikiLinkPaletteDropdown/
│ │ ├─ WikiLinkPaletteDropdown.jsx
│ │ ├─ WikiLinkPaletteDropdown.module.css
│ │ └─ index.js
│ ├─ hooks/
│ │ ├─ useNotesWorkspace/
│ │ │ ├─ useNotesWorkspace.js
│ │ │ └─ index.js
│ │ ├─ useVaultStatus/
│ │ │ ├─ useVaultStatus.js
│ │ │ └─ index.js
│ │ ├─ useWikiPalette/
│ │ │ ├─ useWikiPalette.js
│ │ │ └─ index.js
│ │ ├─ useMediaQuery/
│ │ │ ├─ useMediaQuery.js
│ │ │ └─ index.js
│ │ └─ useThemeState/
│ │ ├─ useThemeState.js
│ │ └─ index.js
│ ├─ utils/
│ │ ├─ wikiLinkPlugin.js
│ │ └─ ... other helpers (clipboard, vault, wiki, etc.)
│ └─ themeManager.js
└─ ui.js # boots React bundle from Pear
| Command | Description |
|---|---|
npm run build:ui |
Bundle src/ui with esbuild once |
npm run watch:ui |
Watch mode for iterative UI development |
npm run dev |
Launch Pear desktop app (runs build:ui first) |
npm test |
Run brittle tests (test/*.test.js) |
- Local-first autosave –
useNotesWorkspaceorchestrates editor state, schedules debounced saves via Hyperdrive, and keeps preview HTML in sync with Markdown-It. - Wiki links everywhere –
markdown/wikiLinkPlugin.jsrenders[[targets]], whileuseWikiPalette+WikiLinkPaletteDropdownprovide inline suggestions and keyboard navigation. - Vault sharing & status –
useVaultStatussurfaces clipboard copy, SweetAlert-based invite modals, and live sync text fromvault/vaultConfig.js/sync/sync.js. - Theme + font system –
themeManager.jstracks preferences and pushes them todocument.documentElement;StatusBarexposes the selectors. - Scoped styling – UI components own nearby
.module.cssfiles whilestyles/global.csskeeps theme tokens/reset utilities. - Icon system –
lucide-reactprovides shared glyphs for buttons, keeping the UI consistent and accessible.
React UI ──▶ src/core/pearlCore.js ──▶ src/pear-end/api.js
│ │
│ ├─ vault/
│ │ ├─ vaultConfig.js (drive selection + invites)
│ │ ├─ hyperdriveClient.js (Corestore/Hyperdrive handles)
│ │ └─ crypto.js (crypto utilities)
│ ├─ notes/
│ │ ├─ notesStore.js (CRUD operations)
│ │ ├─ notesSerialization.js (YAML frontmatter)
│ │ ├─ notesExportConfig.js (export paths)
│ │ └─ notesMirror.js (disk mirroring)
│ └─ sync/
│ └─ sync.js (Hyperswarm status)
│
└─ Hyperdrive updates reflected via useNotesWorkspace/useVaultStatus hooks
- vault/ - Vault management:
vaultConfig.jspersists the active drive key and parsespearl-vault://links;hyperdriveClient.jsowns Corestore/Hyperdrive handles and Hyperswarm replication;crypto.jsprovides crypto utilities. - notes/ - Notes management:
notesStore.jswrites/notes/<id>.mdblobs with YAML frontmatter;notesSerialization.jshandles parsing/serialization;notesExportConfig.jsmanages export paths;notesMirror.jsmirrors notes to disk. - sync/ - Sync management:
sync.jsrefreshes peer counts and timestamps, bubbling up through_setSyncStatusso the UI footer stays current.
For deeper roadmap, research, and acceptance criteria, see prd.md and implementation_plan.md. For known issues and troubleshooting, see issues.md.
This project is licensed under the MIT License - see the LICENSE file for details.