Installation

Prerequisites

  • Node.js 20+ (as specified in .node-version)
  • npm 10+ (package manager)

Clone & Install

git clone https://github.com/plcunha/plfy.git
cd plfy
npm install

Quick Start

# Build the main process first (required before dev)
npm run build:main

# Start development server (opens the app automatically)
npm run dev
Note The first run compiles TypeScript and starts Vite + Electron. Hot module replacement is active for the renderer process.

Building for Production

# Build for current platform
npm run package

# Build for specific platforms
npm run package:win    # Windows (.exe)
npm run package:mac    # macOS (.dmg)
npm run package:linux  # Linux (.AppImage, .deb)

Architecture Overview

Plfy is built on Electron 40 with a clear separation between main process, preload bridge, and renderer.

src/
├── app/
│   ├── backlinks/       → Bidirectional link tracking
│   ├── commands/        → Command palette & registration
│   ├── daily/           → Daily notes automation
│   ├── editor/          → CodeMirror 6 markdown editor
│   ├── explorer/        → File tree with CRUD operations
│   ├── export/          → PDF, HTML, Markdown export
│   ├── indexer/         → Full-text search & indexing
│   ├── outline/         → Document structure navigation
│   ├── plugins/
│   │   ├── api/         → Plugin API interfaces
│   │   ├── loader/      → Dynamic plugin loading
│   │   └── runtime/     → Plugin execution sandbox
│   ├── search/          → Advanced search (regex, operators)
│   ├── settings/        → User preferences & persistence
│   ├── settings-panel/  → Settings UI panel
│   ├── switcher/        → Quick file switcher
│   ├── sync/            → Cloud sync (Supabase + Yjs)
│   │   └── encryption/  → AES-256-GCM + PBKDF2
│   ├── tabs/            → Workspace tab management
│   ├── tags/            → Tag management & browsing
│   ├── templates/       → Note templates with variables
│   ├── ui/              → 13 extracted UI components
│   └── workspace/       → State management & coordination
├── shared/
│   ├── Config.ts        → App configuration
│   ├── FileSystem.ts    → File operations with caching
│   ├── IPCFileSystem.ts → IPC-based file system bridge
│   ├── Logger.ts        → Structured logging
│   └── Validation.ts    → Input validation utilities
├── styles/              → 8 external CSS files
│   ├── index.css        → Entry point (@import chain)
│   ├── base.css         → Reset, scrollbar, focus states
│   ├── themes.css       → CSS variables (light/dark)
│   ├── layout.css       → App shell, titlebar, grid
│   ├── sidebar.css      → Sidebar tabs, file tree
│   ├── editor.css       → Tabs bar, editor area, graph
│   ├── components.css   → Buttons, modals, toasts
│   └── animations.css   → 17 @keyframes
├── types/
│   └── index.ts         → TypeScript type definitions
├── main.ts              → Electron main process
├── preload.ts           → Secure IPC bridge
└── renderer.ts          → Renderer entry point

UI Components

The UI layer was refactored from a monolithic 5,500-line file into 13 focused components using a dependency injection pattern (callbacks interfaces):

Component Responsibility Lines
ContextMenu Right-click context menus, escapeHtml() utility ~634
SupabaseSyncUI Sync settings, vault linking, conflict resolution ~580
FileTreeUI File explorer tree rendering & interaction ~310
RightSidebar Backlinks, outline, graph tabs ~327
SearchUI Search panel with filters & results ~212
SettingsModal Settings modal dialog ~175
NoteHeaderUI Note title & breadcrumb ~137
CommandPaletteUI Fuzzy command search & execution ~130
StatusBarUI Bottom status bar (word count, sync) ~105
ThemeManager Theme detection & switching ~98
GraphView D3 force-directed canvas graph ~505
SidebarTabsUI Sidebar tab switcher ~48
ResizersUI Panel resize handles ~48
ToastUI Toast notifications ~42

CSS Architecture

All styles live in src/styles/ and are imported via index.css in the renderer entry point. No inline CSS injection at runtime.

File Purpose
base.css Reset, scrollbar, selection, focus states
themes.css CSS variables for light/dark, prefers-color-scheme
layout.css App shell, titlebar (mac/win), main grid, sidebar, resizer, status bar
sidebar.css Sidebar tabs, file tree, folders, chevrons, search panel
editor.css Tabs bar, editor area, note header, breadcrumb, backlinks, outline, graph panel
components.css Buttons, inputs, modals, command palette, context menu, toast, settings
animations.css 17 deduplicated @keyframes

Markdown Editor

Built on CodeMirror 6 with full syntax highlighting, bracket matching, auto-indentation, and Markdown-specific extensions. Supports:

  • GFM (GitHub Flavored Markdown) syntax
  • Wiki-style [[links]] with auto-completion
  • Live preview mode
  • Auto-save with configurable interval
  • Find & replace (Ctrl+F, Ctrl+H)

Knowledge Graph

The GraphView component renders note connections as an interactive force-directed graph on HTML5 <canvas>:

  • D3-force simulation with charge, link, and center forces
  • Mouse hover shows note name tooltip
  • Click to open the note in the editor
  • Scroll to zoom, drag to pan
  • Automatic resize via ResizeObserver
  • Accessible in the right sidebar under the "Graph" tab

Full-text search powered by the Indexer module with support for:

  • Boolean operators: AND, OR, NOT
  • Regex pattern matching
  • Case sensitivity toggle
  • Whole word matching
  • Filter by file name, content, or tags

Cloud Sync

Local-first sync architecture built on Supabase + Yjs CRDTs:

  • Offline-first with local IndexedDB persistence
  • Conflict-free merging via Yjs CRDT documents
  • End-to-end encryption (AES-256-GCM key derived via PBKDF2)
  • Vault linking & device management
  • Sync status indicator in the status bar
Beta Cloud sync is architecturally complete but the Supabase backend requires configuration. See the design doc for details.

Export

Export notes from the command palette or context menu:

  • PDF — Print-quality output with proper formatting
  • HTML — Standalone HTML file with embedded styles
  • Markdown — Raw Markdown with front-matter preserved

Creating a Plugin

Plfy's plugin system lets you extend every aspect of the application.

1. Create plugin directory

mkdir plugins/my-plugin

2. Add manifest.json

{
  "id": "my-plugin",
  "name": "My Plugin",
  "version": "1.0.0",
  "minAppVersion": "1.0.0",
  "description": "Does amazing things",
  "author": "Your Name",
  "permissions": ["notes:read", "commands:register"]
}

3. Implement main.ts

import { Plugin } from 'plfy/plugins';

export default class MyPlugin extends Plugin {
  async onLoad() {
    this.app.commands.register({
      id: 'my-plugin:greet',
      name: 'Say Hello',
      callback: () => console.log('Hello from my plugin!'),
    });

    this.app.events.on('note:open', (note) => {
      console.log(`Opened: ${note.path}`);
    });
  }

  async onUnload() {
    // Cleanup resources
  }
}

Plugin API

API Description
app.workspace Open/close notes, manage layout
app.notes CRUD operations on notes
app.commands Register and execute commands
app.events Subscribe to application events
app.storage Persist plugin data

Permissions

Plugins must declare required permissions in their manifest:

  • notes:read / notes:write / notes:delete
  • graph:read / graph:modify
  • commands:register
  • workspace:read / workspace:modify
  • storage:read / storage:write
  • ui:ribbon / ui:statusbar / ui:sidebar
  • network:fetch
  • filesystem:vault

Keyboard Shortcuts

Shortcut Action
Ctrl+P Open command palette
Ctrl+N Create new note
Ctrl+S Save current note
Ctrl+O Open vault
Ctrl+\ Toggle left sidebar
Ctrl+Shift+\ Toggle right sidebar
Ctrl+G Open graph view
Ctrl+F Find in note
Ctrl+H Find and replace

Configuration

Editor Settings

{
  editor: {
    fontSize: 16,
    fontFamily: "'JetBrains Mono', monospace",
    lineNumbers: true,
    lineWrapping: true,
    tabSize: 2,
    autoSave: true,
    autoSaveInterval: 1000,
    spellcheck: false,
  }
}

Appearance

{
  appearance: {
    theme: 'system', // 'light' | 'dark' | 'system'
    accentColor: '#3b82f6',
    sidebarWidth: 280,
  }
}

Development Commands

Command Description
npm run dev Start development with hot reload
npm run build Build for production (3 stages)
npm run typecheck Run TypeScript type checking
npm run lint Run ESLint
npm run lint:fix Auto-fix ESLint issues
npm run format Format with Prettier
npm run test Run tests (2,607 tests, 60 files)
npm run test:coverage Run tests with coverage report
npm run package Package for current platform