A bookmark server manager written in Nim. Stores everything in plain CSV + INI files.
Copyright (C) 2026 Luciano Federico Pereira Licensed under the GNU Lesser General Public License v2.1
Compatible with linkding. Linknim reimplements the linkding REST API and UI concepts in Nim with a CSV/INI backend. No linkding source code was copied or derived.
Features
- 1:1 linkding API — existing browser extensions (Firefox, Chrome) work without modification
- CSV + INI storage — human-readable, version-controllable, trivially backed up
- Web UI — search, add, edit, archive, bulk actions, tag tree, bundle saved searches
- TUI — full terminal interface, no browser needed
- CLI — add/list/edit/delete/archive from the shell, scriptable with
--format json - Import — Netscape bookmark HTML (exported by every browser)
- Export — Netscape HTML and JSON
- RSS feed — shared bookmarks at
/feed.xml - Bookmarklet — save any page with one click, no extension required
- Keyboard-driven — configurable shortcuts in
bookmarks.ini - Favicons — fetched async, cached locally in
data/favicons/ - Dark / light / auto theme — set in ini or toggled per-session
Install
# Install Nim >= 2.0: https://nim-lang.org/install.html # Install Nimble (comes with Nim) git clone <this-repo> linknim cd linknim nimble install illwill # TUI dependency nim c -d:release linknim.nim
Quick start
# Create default config with a random token ./linknim init # Start the server ./linknim serve # Open http://127.0.0.1:8888 in your browser
Configure the browser extension (linkding-extension for Firefox/Chrome):
- Server URL:
http://127.0.0.1:8888 - Token: from
bookmarks.ini [auth] token
Configuration
All settings live in bookmarks.ini next to the binary.
[server] host = 127.0.0.1 port = 8888 [auth] token = your-secret-token [profile] theme = auto # auto | light | dark font = # CSS font-family, empty = system default web_archive_integration = disabled # disabled | enabled [shortcuts] add = n search = / sidebar = b settings = , nav_all = ga nav_unread = gu nav_archived = gr prev_page = [ next_page = ] [tag.work] date_added = 2024-01-01T00:00:00.000000Z [tag.work/nim] date_added = 2024-01-15T00:00:00.000000Z
Tags use slash-convention for hierarchy: work/nim renders as nim under work in the UI.
Storage
| File | Contents |
|---|---|
bookmarks.ini |
Config, auth token, tag registry, shortcuts |
bookmarks.csv |
Bookmark data (named headers, RFC 4180) |
bundles.csv |
Saved searches |
data/favicons/ |
Cached favicon PNGs |
Writes are atomic (temp file + rename) — safe against crashes.
CLI
# Server linknim serve linknim serve --port 9000 --open --quiet linknim serve --config /path/to/other.ini # Setup linknim init # create bookmarks.ini with random token linknim stats # show counts linknim check # validate CSV integrity # Bookmarks linknim add https://example.com --title "Example" --tags "work,nim" --desc "useful" linknim list linknim list --tag work --limit 50 --format json linknim list --search "nim async" --format csv linknim list --archived linknim list --unread linknim get 42 linknim get 42 --format json linknim edit 42 --title "New title" --tags "work,updated" linknim delete 42 linknim archive 42 linknim unarchive 42 # Tags linknim tags linknim tags --format json linknim tag-add work/nim linknim tag-rename work/nim nim linknim tag-delete oldtag # TUI linknim tui
--format accepts table (default), json, csv.
TUI
┌─ Linknim ─── Search: █ ──────────── [N]ew [/]Search [Q]uit ┐
│ All (142) ├──────────────────────────────────────────────│
│ Unread (12) │ ID TITLE TAGS DATE │
│ Archived (8) │▶42 Nim async deep dive nim,async ... │
│ │ 41 linkding source tools ... │
│ TAGS │ 40 Tailwind v4 guide css ... │
│ nim │ │
│ work/nim ├──────────────────────────────────────────────│
│ personal │ Nim async deep dive │
│ │ https://nim-lang.org/... │
│ │ Tags: nim async │
│ J/K:move Enter:open E:edit N:new A:archive D:del T:tag│
└─────────────────────────────────────────────────────────────┘
| Key | Action |
|---|---|
J / K |
Navigate list |
Enter |
Open URL in browser |
N |
New bookmark |
E |
Edit focused bookmark |
A |
Archive / unarchive |
D |
Delete (with confirm) |
T |
Tag filter picker |
/ |
Search (live) |
1 / 2 / 3 |
All / Unread / Archived view |
G |
Jump to top |
Q / Esc |
Clear filter → quit |
Web UI
Available at http://127.0.0.1:8888 when the server is running.
Bookmarklet — drag from the 🔖 button to your bookmarks bar. Click it on any page to save instantly without the browser extension.
API
Full linkding REST API — see linkding API docs.
Linknim-specific extras:
| Endpoint | Description |
|---|---|
GET /feed.xml |
RSS feed of shared bookmarks |
GET /api/export.json |
Download all bookmarks as JSON |
GET /api/export.html |
Download as Netscape bookmark HTML |
PATCH /api/tags/<id>/ |
Rename a tag (updates all bookmarks) |
DELETE /api/tags/<id>/ |
Delete a tag (removes from all bookmarks) |
Compatibility
Tested against the linkding-extension for Firefox and Chrome.
The extension calls: /api/bookmarks/check/, POST /api/bookmarks/, GET /api/tags/, GET /api/user/profile/.
All return the exact linkding response shapes.
