notes

package
v0.0.0-beta.31 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package notes implements the disk-backed notes subsystem ported from kgraph. Notes are Markdown files on disk (source of truth) with an optional YAML frontmatter block. An FTS5 index in the per-project SQLite database is maintained as a derived, rebuildable view.

Index

Constants

View Source
const MaxKeyLen = 512

MaxKeyLen caps note keys. Keeps paths well under filesystem limits even with the `.md` suffix and nested dirs. Phase-2 decision.

Variables

View Source
var ErrInvalidKey = errors.New("invalid note key")

ErrInvalidKey is returned when a key contains path-traversal components, absolute path prefixes, null bytes, or exceeds MaxKeyLen.

View Source
var ErrNotFound = errors.New("note not found")

ErrNotFound is returned when a note key does not exist on disk.

Functions

func Delete

func Delete(notesDir, key string) error

Delete removes the note file. Returns ErrNotFound if missing.

func EncodeFrontmatter

func EncodeFrontmatter(data map[string]any, body []byte) ([]byte, error)

EncodeFrontmatter emits `---\n<yaml>\n---\n<body>`. An empty map emits the body verbatim (no leading delimiter). Keys are sorted by yaml.v3's default encoder (alphabetical); kgraph's gray-matter also sorts, so round-trips are stable.

func ExtractWikilinks(body []byte) []string

ExtractWikilinks returns the de-duplicated list of note keys referenced by `[[wikilink]]` or `[[wikilink|alias]]` occurrences in body, in the order of first appearance. Whitespace inside a target is preserved verbatim (Obsidian-style keys can contain spaces, though we normalize them to paths at the call site).

func ListKeys

func ListKeys(notesDir string) ([]string, error)

ListKeys is the cheap variant of List: it walks the tree once and returns keys only. Useful for the lean `GET /api/projects/.../notes` endpoint where frontmatter isn't needed.

func ParseFrontmatter

func ParseFrontmatter(raw []byte) (map[string]any, []byte, error)

ParseFrontmatter splits raw note bytes into a frontmatter map and a body. If the input does not begin with a `---` delimiter line the whole input is returned as the body with an empty map — this matches the kgraph gray-matter behavior (no frontmatter is not an error).

A body that happens to contain `---` on its own line elsewhere is preserved verbatim; only the FIRST delimiter pair is consumed.

func Related(g *Graph, key string) []string

Related returns the set of note keys directly connected to `key`, in either direction (outlinks + backlinks). Self-links are deduped. The result is sorted for deterministic API output.

func ValidateKey

func ValidateKey(key string) error

ValidateKey enforces the invariants documented on ErrInvalidKey. Public so handlers can short-circuit on bad input before touching the filesystem.

func Watch

func Watch(notesDir string, onChange func(key string)) (func(), error)

Watch scans notesDir every second and fires onChange(key) whenever a `.md` file's mtime changes, a new `.md` file appears, or an existing one is removed. The returned `stop` func halts the background goroutine.

This is a polling watcher — chosen over fsnotify to keep the watcher dependency-free and cross-platform. kgraph uses fs.watch (Node), which is similarly coarse in practice; the 1-second cadence is adequate for the "re-index after a user edits a note in their IDE" use case.

func Write

func Write(notesDir string, n *Note) error

Write persists n to disk atomically (temp file + rename). Parent directories are created as needed. The frontmatter embedded in the file is built from n.Frontmatter, then overlaid with Author, Tags, CreatedAt, UpdatedAt so the struct fields win over stale map entries.

Types

type Edge

type Edge struct {
	Source string `json:"source"`
	Target string `json:"target"`
}

Edge represents a directed `[[wikilink]]` reference from Source → Target.

type Graph

type Graph struct {
	Nodes []NoteNode `json:"nodes"`
	Edges []Edge     `json:"edges"`
}

Graph is the wikilink-derived relation between notes in a project.

func BuildGraph

func BuildGraph(notesDir string) (*Graph, error)

BuildGraph walks every note in notesDir, extracts wikilinks from the body, and returns the resulting node+edge graph. Edges may point to nonexistent targets (dangling wikilinks) — that is intentional, and matches kgraph's behavior.

type Note

type Note struct {
	Key         string         `json:"key"`
	Content     string         `json:"content"`
	Author      string         `json:"author,omitempty"`
	Tags        []string       `json:"tags,omitempty"`
	Frontmatter map[string]any `json:"frontmatter,omitempty"`
	CreatedAt   time.Time      `json:"created_at"`
	UpdatedAt   time.Time      `json:"updated_at"`
}

Note is the in-memory representation of a Markdown note.

Frontmatter is the raw YAML map; Author/Tags are convenience copies hoisted from common keys. Timestamps are derived from filesystem mtime on Read and from time.Now() on Write.

func List

func List(notesDir string) ([]*Note, error)

List returns every note found under notesDir, sorted by key. Missing notesDir is treated as "no notes" (empty slice, nil error) — handlers should not 500 just because nobody has written a note yet.

func Read

func Read(notesDir, key string) (*Note, error)

Read loads the note at key from notesDir. Returns ErrNotFound if the `.md` file does not exist.

type NoteNode

type NoteNode struct {
	Key    string   `json:"key"`
	Title  string   `json:"title"`
	Folder string   `json:"folder"`
	Tags   []string `json:"tags,omitempty"`
}

NoteNode is a lean projection of a Note for graph rendering.

type TreeNode

type TreeNode struct {
	Name     string      `json:"name"`
	Path     string      `json:"path"`
	Type     string      `json:"type"` // "folder" | "note"
	Children []*TreeNode `json:"children,omitempty"`
}

TreeNode is the recursive folder/file tree returned by Tree().

func Tree

func Tree(notesDir string) (*TreeNode, error)

Tree returns the recursive folder/note tree rooted at notesDir. Used by the `/api/projects/{p}/tree` endpoint.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL