[[wiki-links]] in entry bodies are extracted at save time, resolved
to entity IDs (title match first, body substring fallback), and
stored in entity_links junction table. Backlinks surface in TUI
detail view showing entries that link to the current entry.
Schema migration v5 adds entity_links with CASCADE/SET NULL
semantics. Links sync on Create, Update, and Absorb.
- nib export: dump all entities to JSON (stdout or --output file)
- nib backup: atomic SQLite backup via VACUUM INTO (WAL-safe)
- Store.Backup() method on db layer
- Tests for both commands
- Cap list API limit at 200 to prevent unbounded queries
- Sanitize markdown output with DOMPurify to prevent XSS
- Add v4 migration with indexes on deleted_at and modified_at
- Fix v2 migration swallowed ALTER TABLE errors
- Tighten ~/.nib directory permissions to 0o700
Card-by-card walkthrough of entries untouched for 30+ days.
Prevents write-mostly decay by bringing old entries back to attention.
- S from list triggers stumble, loads entries where modified_at < 30d
- Single-card view with markdown body, glyph, tags, age indicator
- Actions: n skip, d dismiss, ! pin, p promote, m absorb, esc exit
- Progress indicator: stumble [3/12]
- After promote/absorb from stumble, returns to deck (not list)
- "All caught up" screen when deck exhausted
- DB: add ModifiedBefore to ListParams, modified_at sort column
- Add 'reminder' to glyph CHECK constraint (was accepted by parser but
rejected by DB)
- Default serve bind to 127.0.0.1, add --host flag for LAN access
- Validate card_data as JSON in Store.Create/Update/Promote
- Return pagination envelope {data,total,limit,offset} from list endpoint
- Append absorb breadcrumb to source entity before soft-delete
- Add Levenshtein fuzzy match to catch command typos before routing to add
- Replace DDL string-matching migrations with versioned schema_version table
- Update web UI and API tests for envelope response format
Split EDITOR env var on whitespace so multi-word values like
"code --wait" work correctly. Add allow-list switch for sort column
and order direction at the query boundary to prevent future callers
from passing unsanitized values into SQL.
Status bar with entity count and context-sensitive key hints. Help
overlay via ? key. Tag filter via # with cursor-navigable tag list.
Todo toggle (x), pin (!), promote (p), demote (D), copy (c), edit (e)
via $EDITOR. Delete confirmation with 3s timeout. Date-grouped list
with completed todo and pinned indicators. Esc clears active tag filter.
Adds CompletedAt/ClearCompleted to EntityUpdate for todo toggling.
New card type renders body as styled markdown with no copy/fill/run
affordance. Glyph: ¶, color: --note.
Migration uses transaction to safely rebuild table constraint.
Checks both 'note' presence and modified_at column to catch
partial migration state.
- Tag rail counts now reflect cards-only when in cards view
(ListTags accepts cardsOnly filter, JS passes it per view)
- j/k navigation scoped to visible (intent/search filtered) list
- scrollSelectedIntoView works in both stream and cards view
- Entity items wrap title/desc/preview in .entity-content flex
container so tags/pills align right consistently
- Title no longer eaten by description/body (flex-shrink + min-width)
- Search bar centered in header with margin auto
- switchView awaits loadEntities+loadTags to fix stale intent counts
Kind prefixes now follow the canonical grammar: `-` for todo,
`@time` for event, `!time` for reminder. Removed `*`/`◇`/`▸`
as capture aliases (display-layer only). Added `\` escape prefix,
`?` query mode, `!pin` flag extraction, `##word` hash escape,
and tag lowercasing. Both parsers produce identical results.
Implement | prefix for titles and // separator for descriptions
across the full stack: parser, schema, API, CLI, and web frontend.
- Parser: line-aware extraction for |title, |title // desc,
// leading desc, body // inline desc. URL-safe (skips :// lines).
Modifiers (#tag, @time, ^card) extracted from all segments.
- Schema: ALTER TABLE migration adds title, description columns
- DB: Entity/EntityUpdate structs, all CRUD queries updated
- API: title/description on create/update/response, body validation
relaxed (title-only entries valid)
- CLI: shows title as scan label when present
- Web: parseInput mirrors Go parser, list shows title, detail pane
renders title + description with double-click inline editing
- Tests: 10 new cases (grammar, entity, API) — 71 total, all pass
- Add rows.Err() checks after all scan loops (entities, tags, resolve)
- Surface time.Parse errors instead of silently discarding
- Extract entityRow scan helper to eliminate Get/List duplication
- Cap request body at 1MB via MaxBytesReader
- Stop leaking internal errors to API clients (log server-side only)
- Block javascript: URIs in link card open button (XSS)
- Fix all go vet failures in api_test.go (unchecked http errors)
- Add tests for display package, generateCardData, absorb-source-card
- Run go mod tidy to fix direct/indirect dep markers
CLI: --month YYYY-MM, --from/--to date range, --limit override
API: from/to query params for date range filtering
Web: load more button for pagination, month nav (◂/▸) in stream view
- Fix N+1 tag query in List() with batched IN clause
- Add inline body editing in web detail pane (dblclick or e key)
- Delete API returns {result: "soft"|"hard"} with 200 instead of 204
- SPA handler serves index.html for all extensionless paths
- Link glyph changed from emoji 🔗 to unicode ↗ for terminal alignment
- Capture bar contrast and hover glow increased
- Comment on load-bearing "--" in root.go
Foundation layer: entities table with card support, entity_tags join
table, WAL mode, busy_timeout, full CRUD operations including
promote/demote lifecycle and soft/hard delete. 33 tests passing.