An app for building typed knowledge graphs for active learning.
Nesso is an interactive concept map where nodes are ideas and edges are typed semantic relations (52 types across 8 categories, e.g. causes, requires, subtype-of). Each concept carries spaced-repetition state scheduled by FSRS. Available as a web app at app.nesso.how and as a native macOS desktop build.
Note
An experimental AI mentor (Socrates) is also available: opt-in under Settings → AI, requires an OpenAI-compatible endpoint (local Ollama or a cloud provider).
Prerequisites: Node 20+, pnpm 10+ (via corepack enable), and a Rust toolchain for the desktop build.
pnpm install
pnpm dev # web app at http://localhost:5173
pnpm dev:desktop # Tauri v2 desktop shellpnpm install builds the workspace packages automatically (via prepare). To build for production:
pnpm build # web bundle
pnpm build:desktop # desktop binarysrc/
components/ UI components (read state via useGraphStore)
store/ Zustand store (index.ts + slices/: graph-editing, graph-management, settings, ui)
llm/ mentor transport (OpenAI-compatible fetch)
data/ relation type registry, seed graphs
types/graph.ts facade re-exporting vocab-learning + graph display + app settings
src-tauri/ Tauri v2 Rust shell (conf, capabilities, icons)
packages/
schema/ @nesso-how/schema: vocabulary-agnostic graph JSON serialize/deserialize
vocab-learning/ @nesso-how/vocab-learning: graph vocabulary (relations, node params, palettes)
theme/ @nesso-how/theme: design tokens (colours, fonts, spacing, radii)
graph/ @nesso-how/graph: embeddable graph React component (read-only by default)
mcp/ @nesso-how/mcp: MCP server for LLM clients
docs/ Starlight docs site, published at nesso.how/docs
Nesso is a React 18 + Vite + TypeScript single-page app, optionally wrapped by Tauri v2 for a native desktop shell. All state lives in a single Zustand store, with components subscribing via selectors and no prop drilling.
The canvas is built on React Flow with a custom edge renderer that encodes each relation type as a category colour and SVG glyph. Graph content persists to IndexedDB on web and is also written to a folder of .json files on desktop, with a file watcher that picks up external edits. FSRS review progress lives in a separate IndexedDB store and is never mixed into the shared graph files.
The AI mentor talks to any OpenAI-compatible chat/completions endpoint. On every send the system prompt is rebuilt from the live store, so the model always sees the current graph, the active selection, and a focal neighbourhood of related concepts.
The repo is a pnpm workspace monorepo. The graph vocabulary lives in packages/vocab-learning and is consumed by both the app and an MCP server in packages/mcp that lets LLM clients query relation types, read the bundled docs, build valid graph documents, and validate graph JSON.
Nesso uses OpenCode as its development environment, a modular, multi-provider AI coding tool that aligns with Nesso's own philosophy. We chose it over vendor-locked alternatives because it runs locally against any provider (currently OpenAI, open-weight models via a Go subscription, or local models), supporting a structured workflow built around typed agents, skills, and subagent pipelines:
The pipeline (from issue to PR) routes through specialized agents: nesso-fix forensic traces bugs, nesso-brainstorm explores design, nesso-plan produces bite-sized TDD tasks, nesso-build executes RED-GREEN-REFACTOR per task, nesso-guard-review checks semantic constraints, and nesso-quality-review catches bugs and regressions. An orchestrator agent (nesso-work) dispatches each phase and gates on user approval.
This lets us match model capability to cost per phase without locking into a single model or provider.
The harness lives in opencode.json (model/config settings), .opencode/ (agents, skills), and .rules/ (area-specific rules for graph model, store conventions, theme tokens). All tracked in the repo so every contributor sees the same guardrails.
flowchart TD
B["nesso-brainstorm"]:::plan -->|"design brief"| P["nesso-plan"]:::plan
P -->|"task list"| T["nesso-build<br>RED-GREEN-REFACTOR"]:::exec
T --> GR["nesso-guard-review"]:::quality
T --> QR["nesso-quality-review"]:::quality
GR --> S["review · synthesize"]:::review
QR --> S
S -->|"✓ approve"| DONE((" ")):::done
S -->|"issues found"| P
classDef plan fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
classDef exec fill:#dcfce7,stroke:#22c55e,color:#14532d
classDef quality fill:#fef9c3,stroke:#eab308,color:#713f12
classDef review fill:#f3e8ff,stroke:#a855f7,color:#3b0764
classDef done fill:#bbf7d0,stroke:#16a34a,color:#14532d,stroke-width:3px
The nesso-work orchestrator dispatches each phase and gates on user approval between them.
The project is managed with a kanban board tracking active issues and a roadmap for longer-term direction. We follow a continuous flow model rather than sprints or classic agile iterations: work is pulled from the backlog as capacity allows, sized so each unit maps to one agentic pipeline run. This cadence matches the tooling: agents work best on focused, sequential tasks, not time-boxed batches of unrelated work.
Nesso is built as a monorepo of focused packages so that its graph vocabulary, visual components, and tooling can be used independently of the full app. The MCP server, embeddable graph component, and schema layer are all separate entry points into the same underlying model.
| Package | Purpose |
|---|---|
@nesso-how/schema |
Vocabulary-agnostic graph document: concepts/relations, serialize/deserialize |
@nesso-how/vocab-learning |
Graph vocabulary: relation types, FSRS node params, category palettes, NessoGraphDocument |
@nesso-how/theme |
Shared design tokens for the app, graph embeds, and docs site |
@nesso-how/graph |
Embeddable <NessoGraph /> React component for docs and external apps |
@nesso-how/mcp |
MCP server: query relation types, read docs, build and validate graph documents |
Bug reports, feature ideas, and PRs are welcome on GitHub Issues. Start with CONTRIBUTING.md.
Copyright © 2026 Omar Desogus. Licensed under the MIT License. See LICENSE.