# Lightwrite: full documentation > AI-first, local-first notetaking over plain files you own. Docs are .md, boards are .json, pages are .html, all in a folder you control. Ships the `nekko` CLI and the `lightwrite-mcp` MCP server so AI agents use your vault as durable memory and a RAG corpus. MIT licensed. > Canonical source: https://github.com/nekko-labs/lightwrite/blob/main/docs ยท Site: https://lightwrite.app --- # Getting Started Lightwrite runs in your browser, as a desktop app, or fully self-hosted. First run is zero-config: a seeded demo vault loads with no account and no backend. ## Try it in the browser Open the live demo. Everything runs client-side (IndexedDB), so it is a real, fully functional app: ```text https://nekko-labs.github.io/lightwrite/app/ ``` ## Run from source Nekko is an npm-workspaces monorepo. Node 20+ and npm are required (not pnpm or yarn). ```bash git clone https://github.com/nekko-labs/lightwrite.git cd lightwrite npm install npm run dev ``` `npm run dev` starts the web app on http://localhost:5173 and the optional sync server together. Use `npm run dev:web` for the app alone. ## Install the desktop app Download the installer for Windows, macOS, or Linux from GitHub Releases: ```text https://github.com/nekko-labs/lightwrite/releases ``` The desktop app packages the same web app with a native shell, local file access, and a one-click bundled sync server. ## Link a real folder (own your data) By default the vault lives in browser storage. To make it a folder of real files on disk, open Settings, then "Vault location", and pick a folder. Notes mirror to `notes/*.md`, task boards to `tasks/*.json`, and HTML pages to `html/*.html` on every save. See [Vault format](vault-format.md). ## Import your existing notes Settings offers importers for: - Markdown files (any `.md`) - Apple Notes (exported `.html` or `.txt`) - Google Keep (the per-note `.json` files from Google Takeout) - Google Drive and OneDrive documents (OAuth, when configured) - GitHub issues (public repos, via the Connectors space) ## Set up AI (optional, bring your own) The app is fully usable with no AI configured (a deterministic mock answers instead). In Settings, choose a provider: - Claude (Anthropic API key) - OpenAI (API key) - A local model via Ollama or LM Studio (no key, nothing leaves your machine) - Apple Intelligence on-device (macOS/iOS app, no key) - Any custom OpenAI-compatible endpoint Keys are stored locally in your browser only. They are never synced or committed. --- # CLI Reference: `nekko` The `nekko` CLI reads and writes a Nekko vault (the folder of Markdown files) from the terminal. It is how scripts, cron jobs, and shell-based agents touch your notes. ## Install and point at a vault The CLI ships in the monorepo under `apps/cli`. Build it once, then set `NEKKO_VAULT` to your vault folder (default: `~/nekko-vault`). ```bash cd apps/cli && npm run build export NEKKO_VAULT="$HOME/nekko-vault" ``` ## List all notes Prints every note's id, title, status, tags, and due date as JSON. ```bash nekko list ``` ## Search notes by text Full-text search across titles, bodies, and tags. ```bash nekko search "travel plans" ``` ## Read one note as Markdown Prints the note's title and Markdown body. Use the id from `list` or `search`. ```bash nekko read ``` ## Create a note Creates a Markdown note in the vault and prints the new id. Add `--todo` to create it as a todo, and `--body` for content. ```bash nekko new Call the plumber --todo nekko new Meeting notes --body "Agenda: pricing, launch date" ``` ## Update a note's fields Sets status, priority, due date, or adds a tag. Statuses: `none`, `todo`, `in_progress`, `done`, `archived`. Priorities: `none`, `low`, `medium`, `high`, `urgent`. ```bash nekko set --status done nekko set --priority high --due 2026-07-15 nekko set --tag travel ``` ## Delete a note Removes the note's file from the vault. ```bash nekko rm ``` ## Use it from a script Everything prints JSON (or Markdown for `read`), so it composes with `jq`: ```bash nekko list | jq '.[] | select(.status == "todo") | .title' ``` --- # MCP Server: `lightwrite-mcp` Nekko ships a native MCP (Model Context Protocol) server so AI agents like Claude Code use your vault as durable memory and a RAG corpus. Agents can list, search, read, create, and update your notes, and manage your external connections, all over stdio with zero network. ## Connect Claude Code to your vault Add the server to your MCP configuration. `NEKKO_VAULT` points at the vault folder (default `~/nekko-vault`). ```json { "mcpServers": { "nekko": { "command": "npx", "args": ["-y", "lightwrite-mcp"], "env": { "NEKKO_VAULT": "/path/to/your/vault" } } } } ``` From a monorepo checkout, use the built binary instead: ```json { "mcpServers": { "nekko": { "command": "node", "args": ["/path/to/lightwrite/apps/cli/dist/mcp.js"], "env": { "NEKKO_VAULT": "/path/to/your/vault" } } } } ``` ## Note tools | Tool | Arguments | What it does | | --- | --- | --- | | `list_notes` | none | List all notes (id, title, status, tags, due) | | `search_notes` | `query` | Full-text search, returns matching notes | | `read_note` | `id` | Full title, Markdown body, and fields | | `create_note` | `title`, `body?`, `tags?`, `todo?`, `dueDate?` | Create a note (write agent memory); returns the new id | | `update_note` | `id`, plus any of `title`, `body`, `status`, `priority`, `tags`, `dueDate` | Patch a note's fields | | `delete_note` | `id` | Delete a note | `status` is one of `none`, `todo`, `in_progress`, `done`, `archived`. `priority` is one of `none`, `low`, `medium`, `high`, `urgent`. `dueDate` is `YYYY-MM-DD`. ## Connection tools The MCP is also the hub for managing Nekko's external connections (the Connectors space in the app): | Tool | Arguments | What it does | | --- | --- | --- | | `list_connections` | none | List connections (id, kind, label, status) | | `add_connection` | `kind`, `label?` | Connect a service (`github`, `gdrive`, `onedrive`, `ticktick`, `youtube`, `monday`, `linear`, `jira`, `instagram`) | | `set_connection_status` | `id`, `status` | Set `connected`, `disconnected`, or `error` | | `remove_connection` | `id` | Remove a connection | ## Agent recipes Give an agent standing memory by telling it where to write: ```text Whenever you learn a durable fact about this project, call create_note with tags: ["memory", "project-x"], and search_notes before answering questions about prior decisions. ``` Use the vault as a RAG corpus: ```text Before drafting, call search_notes with the key phrases from my request and ground your answer in read_note results. Cite note titles. ``` ## Why files matter here Every note the agent writes is a plain Markdown file on disk (see [Vault format](vault-format.md)). You can read your agent's memory in any editor, version it with git, and sync it with any tool. Nothing is locked inside a database. --- # Vault Format A Nekko vault is a plain folder. Every user-facing object is a real file in a portable format, so the vault opens, syncs, greps, and versions with any tool. This is the "file over app" guarantee: your notes outlive Nekko. ## Folder layout ```text my-vault/ notes/ one Markdown file per note (.md with YAML front-matter) tasks/ one JSON file per standalone task list / kanban board html/ HTML wiki pages as real .html files media/ images and audio .nekko/ vault.json app-layer state: lenses, canvas layout, edges, comments, versions, trash, checkpoints connections.json external-connection registry (used by the CLI/MCP hub) ``` ## Note files: Markdown + front-matter Each note is a clean `.md` that renders anywhere. Features Markdown cannot express (canvas position, kind, shape, sharing) live in YAML front-matter, so the file stays fully portable and just renders richer inside Nekko. ```markdown --- id: n-7f3a title: Kyoto trip ideas kind: doc type: note tags: [travel, japan] group: g-travel status: none priority: none assignee: '' homeX: 480 homeY: 220 width: 320 height: 240 color: '' shape: '' sketch: true source: manual links: [] pinned: false dueDate: '' createdAt: 2026-06-20T09:12:00.000Z updatedAt: 2026-07-01T18:40:00.000Z --- Ryokan in Gion, arashiyama bamboo walk, [[Packing list]]. ``` Field notes: - `kind`: `sticky`, `doc`, `list`, or `kanban` (fixed at creation) - `type`: `note`, `todo`, `idea`, `image`, `voice`, `link`, or `html` - `status`: `none`, `todo`, `in_progress`, `done`, `archived` - `priority`: `none`, `low`, `medium`, `high`, `urgent` - `homeX`/`homeY`: the sacred home position on the canvas (lenses never touch it) - `[[wiki links]]` in the body create graph edges and canvas link lines ## Task lists and boards: JSON A standalone checklist or kanban board serializes losslessly to `tasks/.json`: columns, per-card fields (priority, assignee, due, labels, estimate, checklist, blocked-by), custom field definitions, and ordering all round-trip. ## HTML pages: real .html An HTML wiki page is exactly the file you gave it (or the AI generated), no wrapper format. It opens in any browser and serves from any host. ## Syncing the folder Because everything is plain files, any sync works: iCloud/Dropbox/Syncthing on the folder, your own git repo (the app has GitHub/GitLab/Bitbucket sync built in), or the optional Lightwrite Cloud. A phone or second computer sees your docs as ordinary Markdown. --- # Self-Hosting The core app never needs a server. The optional sync server adds cross-device sync, public share links, and real-time collaboration. It is MIT-licensed like everything else, and a self-hosted server is never billing-gated. ## Run the server with Docker The repo ships a compose file that builds and runs the server with a persistent data volume: ```bash git clone https://github.com/nekko-labs/lightwrite.git cd lightwrite docker compose up -d ``` The server listens on port 8787 by default. ## Run it with Node or Bun No framework, no database required (file-backed storage under `DATA_DIR`): ```bash cd apps/server npm run dev # Node with type stripping npm run dev:bun # or Bun ``` ## Point the app at your server In the app: Settings, then "Hosted server URL", enter your server's URL (for example `https://nekko.example.com`). Then connect an account (email only, no verification email needed in the MVP flow) and choose "Hosted" sync mode. The app auto-pushes your vault on change and you can pull it from any other device. ## Environment variables | Variable | Purpose | | --- | --- | | `PORT` | Listen port (default 8787) | | `DATA_DIR` | Where accounts, vaults, and shares persist | | `APP_URL` | Your web app origin (used in billing redirects) | | `STRIPE_SECRET_KEY`, `STRIPE_PRICE_ID`, `STRIPE_WEBHOOK_SECRET` | Optional billing (enables tier enforcement). The webhook endpoint refuses to process events until `STRIPE_WEBHOOK_SECRET` is set and signatures verify. | | `AUTH_REQUIRE_VERIFY` | Set to `1` to require magic-link email verification on sign-in (register never returns a token directly). Set this on any instance where the email addresses are not all yours; without it, knowing an email is enough to mint a token for that account. | | `RESEND_API_KEY`, `AUTH_EMAIL_FROM` | Email delivery for the sign-in links (Resend). Without a key the link is printed to the server log, which is fine for a personal self-host. | | `TOKEN_TTL_DAYS` | Optional sliding token expiry in days (a token unused that long stops working). Unset or `0` = tokens do not expire. | | `CORS_ORIGINS` | Optional comma-separated origin allowlist for API responses. Unset = any origin (self-host default). Set it on a public hosted instance. | | `NEKKO_WS_AUTH` | Set to `1` to require a signed-in account token to join collaboration rooms (automatic when tier enforcement is on). Self-host default: rooms are open. | | `TRUST_PROXY` | Set to `1` only when behind a reverse proxy / load balancer you control, so `X-Forwarded-For` is trusted for client-IP rate limiting. On bare Node leave it unset (the header is client-controlled and would let callers evade limits). | | `SHARE_TTL_DAYS`, `SHARE_MAX` | Optional lifetime (days; 0 = keep forever) and hard cap (default 10000, oldest evicted) for published share links, so a public instance's share store stays bounded. | | `MAX_ROOM_DOCS` | Cap on cached collaborative documents in memory (default 5000, oldest evicted). | | `NODE_ENV` | Set to `production` on the hosted instance. Disables the `AUTH_DEV_ECHO` test hook regardless of its value. | | `NEKKO_ENFORCE_TIERS` | Force tier gates on (auto-on when Stripe is configured) | | `MODERATION_URL`, `MODERATION_KEY` | Optional content moderation for public shares | ## What tier enforcement means Only the hosted instance that actually sells subscriptions gates anything. On your own server: - Publishing public share links: not gated - Vault sync push/pull: not gated - Multiple editors: not gated And even on the managed cloud, pulling your data out is never gated. Notes are never held hostage. ## Desktop one-click server The desktop app can launch a bundled local server (Settings, sync chooser, "Self-host"), which is handy for LAN-only collaboration without touching Docker. --- # Views and Lenses The lens is Nekko's signature feature: gather notes from everywhere without disturbing where you put them. ## What a lens does Ask for "everything due today" or "gather my travel ideas". Nekko runs the query across all notes, regardless of which section they live in, and renders a temporary arrangement (cluster, board, grid, or list) layered over your canvas. Close the lens and your layout is exactly as you left it, always. Two rules make this trustworthy: 1. Edits through a lens write through to the real note. 2. Positions inside a lens never write back to your home layout. ## Open a lens - Type a gathering query in the top search bar: "show me todos for this week", "gather everything tagged kyoto" - Ask the assistant: "focus on what's due today" - Press `/` to focus the bar from anywhere - The reminder bell opens the built-in Due lens ## Save and reopen views Every lens persists as a saved view. Reopen or delete them from the assistant panel. --- # The Canvas The canvas is your spatial home: every note has a place you chose, and that layout is sacred. AI features gather and arrange *copies of the view*, never your actual layout (see [Views and lenses](lenses.md)). ## Create things - Double-click empty canvas for a quick note - Use the bottom dock: Select, Pen, Sticky, Doc, Tasks, Shape, Section, Connector - Click a tool to drop at center, or drag it off the dock onto the canvas - The Task tool picks a style on hover: checklist, board, or timeline - The Shape tool picks a flowchart shape: box, circle, diamond, triangle, database, input/output, preparation ## Navigate - Pan: middle-drag, two-finger scroll, or the mouse wheel - Zoom: Ctrl/Cmd + scroll - Marquee select: left-drag on empty canvas (Shift adds to the selection) - Select all: Ctrl/Cmd+A; nudge with arrow keys (Shift for 1px) ## Sections (frames) Sections group notes spatially. Drop a card in and it snaps fully inside by majority area; drop it across two sections and a split-color chooser asks which one you meant. Moving a section frame moves only the frame. Sections carry their own sharing (see [Collaboration](collaboration-sharing.md)). ## Connectors and diagrams Drag from any card's side handle to another card to draw a typed arrow. Connectors are curved and hand-drawn by default; per connector you can switch routing (curved, straight, right-angle), arrowheads, line style, color, and label. Endpoints pin to the side you drag from. Shapes plus connectors make real flowcharts, and the AI can generate one from text ("diagram of our deploy pipeline"). ## Freehand drawing Press `P` or pick the Pen. Pressure-sensitive ink (stylus and Apple Pencil supported), four brushes (pen, marker, highlighter, paint), eight colors, line-straightening, and an eraser. Strokes are selectable with the Select tool: move, delete, or duplicate them like anything else. ## Undo everything Ctrl/Cmd+Z undoes any canvas mutation (create, move, delete, restyle, sharing, strokes); Ctrl/Cmd+Shift+Z or Ctrl/Cmd+Y redoes. Durable, cross-session checkpoints live in Settings, "Workspace history". --- # Tasks and Kanban Checklists, kanban boards, and timelines are one underlying task object with three faces. Drop one from the dock's Task tool and switch styles any time. ## Cards Cards carry PM-grade fields: priority, assignee, due date, labels, a story-point estimate, an inline checklist (subtasks), blocked-by dependencies, a cover color, and a stable card key like `T-3`. Click a card to open its detail popover; the card face shows labels on top, the title, then a meta row (key, estimate, due, avatars). ## Columns Add, rename, reorder, recolor, and delete columns; set per-column WIP limits (the count chip turns red over the limit); drag cards within and across columns. ## View settings (the display options) The gear opens a Linear-style panel: - Layout: Board, List, or Timeline - Grouping: status columns, priority, assignee, tags, or any custom select field - Swimlanes: split the board into horizontal lanes by a second field - Ordering: up to four sort rules, each ascending or descending - Display properties: toggle which fields show on card faces - Custom fields: text, number, currency, date, select, multi-select, boolean, url ## Bulk actions and reporting Ctrl/Cmd-click cards to multi-select, then set priority, move, or delete the whole selection. The report button rolls up totals, points, blocked counts, and per-column bars. ## Boards are files A standalone board serializes to `tasks/.json` in your vault, lossless: columns, fields, ordering, everything (see [Vault format](../vault-format.md)). The Board space also offers many lightweight boards as saved filters over your notes, and the List space renders the same notes as a sortable, filterable issue table. --- # HTML Wiki: Publish AI Artifacts AI tools hand you finished HTML pages (Claude artifacts, ChatGPT canvases, generated dashboards) that are painful to keep and share. Nekko's HTML space fixes that: the page lives beside your notes as a real `.html` file, versioned with your workspace, and publishes as a live link in one click. ## Add a page - Paste or write HTML in the built-in CodeMirror editor (syntax highlighting, dark mode) - Ask the AI: "make a page for my reading list" creates an editable page (Make Real) - Every page is a real `.html` file in your vault's `html/` folder ## View safely Pages render in a sandboxed iframe. Open any page in its own browser tab, duplicate it, or download the file. ## Edit any element with AI Toggle AI-edit mode, then hover or tap any element on the page and tell the model what to change ("make this heading bigger", "reword this paragraph"). Each edit checkpoints your workspace first, so it is always revertible. ## Share and publish - Share among your collaborators: free, always - Copy a local share reference or open in a tab: free - **Publish to a public link** (anyone with the link, no account): one click when a server is configured. On the managed cloud this is part of the paid plan; on a self-hosted server it is never gated. ## Why this beats artifact links Chat-tool share links expire, break when conversations are deleted, and live outside your notes. A published Nekko page is a file you own, in your vault, with your version history, at a stable link. --- # Collaboration and Sharing Nekko's people model is the collaborator: family, friends, or teammates. You control what each person can see and do, per note, per section, and per page, visible right on the canvas. ## Collaborators and roles Add people in Settings, "Collaborators": name, email, and a role. Roles are owner, editor, and viewer. On the free plan one collaborator per team can be an editor (everyone can view); the paid plan unlocks unlimited editors. ## The share dialog Click the share control on any card, section badge, or the doc editor's Share button. The dialog works like Google Docs: - **Add people**: search your collaborators by name or email, or type a new email to add someone on the spot, each with a viewer or editor role - **People with access**: per-person role dropdowns and remove - **General access**: Restricted, Friends, Team, Company, or Anyone with the link, with a viewer/editor link role - **Copy link**: notes get a free shareable bookmark deep-link that opens that exact doc A card's audience shows as a glyph on its face, so who-can-see-what is always visible on the canvas. ## Live collaboration Go live (top bar) with a room name and a server (managed or self-hosted). You get: - Conflict-free co-editing of docs (Yjs CRDT), with live cursors and selections - Live collaborator cursors on the canvas and presence avatars - A per-doc facepile of who is here now - FigJam-style sessions: sticky brainstorming, dot voting, a session timer Offline and serverless, everything still works; collaboration is an enhancement, never a requirement. ## Version safety Deleting moves notes to Trash (restorable, one-click undo). Docs snapshot versions on collapse. The whole workspace checkpoints automatically and restores from Settings, "Workspace history". --- # Voice and AI Every AI surface works offline in mock mode with no key, degrades gracefully, and never touches your notes without you asking. Bring your own model: Claude, OpenAI, a local model (Ollama or LM Studio), Apple Intelligence on-device, or any OpenAI-compatible endpoint. ## Voice capture Record, speak, done: the transcription becomes a note and the AI titles, tags, and suggests a home for it. The voice language is configurable (any BCP-47 tag). ## The assistant One bar at the top does both search and asking. Gathering phrases ("show me", "gather", "focus on") build a [lens](lenses.md); anything else is answered over your notes with citations. Ctrl/Cmd+J expands the panel with chat history and saved views. The assistant acts, not just answers: - "create a todo to call the plumber" makes a real note - "mark the launch done" updates status - "tag Kyoto with travel" edits tags - "brainstorm marketing ideas" builds a connected mind-map on the canvas - "diagram our signup flow" generates an editable flowchart - "make a page for my reading list" creates an HTML page - "read me my updates" speaks a briefing aloud ## In the editor Select text and Ask AI rewrites in place (improve, fix grammar, shorten, translate, and more). Buttons draft content, summarize with read-aloud, extract action items from meeting notes, and suggest tags and related notes. ## The canvas agent Toggle Agent mode and describe what to build: the model sees a compact serialization of your notes and returns a validated plan of canvas actions (create, connect, update, move) applied to a fresh section. Invalid references are dropped before they touch your data. ## Local and on-device AI Choose "Local model" and point at Ollama (`http://localhost:11434/v1`) or LM Studio: nothing leaves your machine. On the macOS/iOS apps, choose Apple Intelligence and every surface, including the agent, runs on-device with no key at all.