Repository navigation
Releases
LinkMarks v2.1.2 — public-surface scrub + sync --dry-run preview
What's new
linkmarks sync --dry-run— preview the yrs-encoded payload that would be sent to the relay, per collection. No network, no commit, no risk. Useful for inspecting wire shape before deploying the relay.linkmarks-bench-crdtworkspace member — the benchmark suite that backs the CRDT choice is now a first-class workspace member (waspoc/crdt-spike/). Numbers stay the same; the path is honest.deploy/+docs/relay-deployment.md— operator template for self-hosting the relay (systemd unit + nginx config + healthcheck). The relay itself is not in this release; the deployment surface is.
Cleanup
- Internal docs (ARCHITECTURE, CONCERNS, ROADMAP, SPEC, decisions/) move out of the public repo. The maintainer-only context lives elsewhere; the public repo carries only consumer-facing docs.
- All references to internal phase labels (Fase N / ADR NNNN / Day N / poc/) scrubbed from source, tests, templates, systemd unit, and manpage.
Install
```bash
cargo install --git https://github.com/LOUST-PRO/LinkMarks \
--tag v2.1.2 \
--path crates/linkmarks-cli \
--bin linkmarks \
--locked
```
See docs/relay-deployment.md for the relay self-host walkthrough.
v2.1.1 — TUI wiring + packaging + README drift
v2.1.1 — TUI wiring + packaging + README drift
Fixed
- TUI:
FilterMode::Fuzzynow reachable viaCtrl+Finside the filter (cycles Substring → Tag → Fuzzy).SortModegains a 4th variantCanonicalUrland a globalskeybinding to cycle the four modes (updated / title / url / created). Status bar surfacessort: <label>and help overlay lists both bindings. debian/rules: replaced deprecateddh $@ --with cargowithdh $@ --buildsystem cargo.override_dh_auto_testnow honorsDEB_BUILD_OPTIONS=nocheck.arch/PKGBUILD: install hook switched from a hand-copied/usr/share/libalpm/scripts/copy to the canonicalinstall=linkmarks.installdirective..SRCINFOregenerated.rpm/linkmarks.spec:License: AGPL-3.0-or-later AND LicenseRef-Commercial→AGPL-3.0-or-later OR LicenseRef-Commercial(dual-license SPDX semantics).README.md:cargo install --git … --bin linkmarks→… --path crates/linkmarks-cli --bin linkmarks --locked(workspace path resolution).[CONTRIBUTING](./.github/PULL_REQUEST_TEMPLATE.md)label mismatch corrected.textlanguage hint added to project-layout fenced block (MD040).
Added
- 9 state-wiring integration tests in
crates/linkmarks-tui/src/app_test.rscovering everySortModeandFilterModevariant via emulatedKeyEvents + downstreamapp.visible()assertions. - 6 sort tests + 4 input-handler tests (
scycles sort,Ctrl+Fcycles filter,Ctrl+Foutside filter is no-op,Ctrl+Fpreserves query). - 13 new
~/.claude/rules/*.mdcodified from this review (10 from CodeRabbit + 3 from mid-turn hardening dialogue).
Test surface
- 302/302 tests green (was 286 in v2.1.0).
cargo clippy --workspace --all-targets -- -D warningsclean.cargo build --releaseclean.- Manual sanity checks for packaging (linter gap acknowledged: namcap/lintian/rpmlint not installed; dpkg lock from
unattended-upgrade).
v2.1.0 — F2.5 batch
What's new
Minor release — F2.5 batch. Three real concerns under one minor bump because they share the same release-cycle intent:
-
TUI fuzzy filter + sort modes — fuzzy match via
nucleo = "0.5"(case-insensitiveCaseMatching::Ignore: users typingHELLOalmost always meanhello), plus four sort modes (CanonicalUrl,Title,CreatedDesc,UpdatedDesc). Toggle in the TUI status bar. 18 tests cover empty/whitespace pass-through, exact-title-outscores-partial, case-insensitive, unicode accents, tag scoring, score-DESC ordering, stable tie ordering, and a 1000-bookmark performance smoke (< 2 s). -
completions <shell>subcommand — emits fresh bash/zsh/fish/powershell/elvish completion scripts at install time. Always regenerated from the liveCliparser, so a renamed flag never goes stale. Install recipes inREADME.md. 6 tests cover structural signatures (one per shell + one that confirms every shell surfaces in--help). -
Packaging templates — declarative stubs under
debian/,rpm/,arch/,homebrew/for downstream maintainers. Each directory has its ownREADME.mddocumenting the maintenance contract and the anti-feature conformance check. Upstream does NOT build packages — the templates are starting points that downstream maintainers adapt.
Plus: README refresh (Install / Subcommands / CI / Exit codes / Project layout / Packaging / Environment) sync to v2.1.0, and [2.1.0] CHANGELOG entry.
Why CaseMatching::Ignore (semantics over convention)
nucleo's default is Smart (case-sensitive if the query has any uppercase ASCII). That's the wrong default for bookmark search: a bookmark titled "Rust by Example" would silently fail to match a query of RUST. Documented inline in crates/linkmarks-tui/src/filter.rs:
Ignore(case-insensitive) for bookmark search is the right default: users typing "HELLO" almost always mean "hello".Smart(lowercase-only = lenient, any-uppercase = strict) is a worse UX for this domain — a bookmark titled "Rust by Example" would silently not match a query of "RUST".
Scope boundary (what this release is NOT)
- No GUI. Dioxus integration is the natural choice for Fase 4, deferred per operator direction in the F2.5 planning turn.
- No CRDT sync. Spike deferred (
yrsvsautomerge-rs); Fase 3 remains indocs/ROADMAP.md. - No actual built packages. The packaging templates are declarative starting points; downstream maintainers adapt them per distro policy.
- No packaging-time shell-completion install. Completions are generated on demand by the binary the operator just installed, not baked into a package.
Quality gates
cargo fmt --all -- --check✅cargo build --workspace --all-targets✅cargo clippy --workspace --all-targets -- -D warnings✅cargo test --workspace --no-fail-fast✅ 286 / 286 green.
Compatibility / migration
clap_complete = "4"is the only new workspace dep. No MSRV bump (still 1.78).- Behaviour change: filter
/<query>in the TUI now routes throughnucleo::Matcherinstead of substring equality. Observable only inside the TUI. - Workspace version 2.0.1 → 2.1.0; all 6 crates inherit via
[workspace.package] version.
Anti-features (locked, unchanged from v2.0.0)
- No telemetry, no phoning home, no automatic update notifier.
- No server-authoritative mode.
- No AI-without-cost-gate.
- No Docker-only deploy.
- No closed-source build.
- No packaging-time shell-completion install.
gpg-signed tag v2.1.0 cut from fc39930. Full diff: PR #11 (30 files, +1607 / −54).
v2.0.1 — Dependabot rust-security group + compat fixes
Patch release — Dependabot `rust-security` group + compat fixes
Changed (dependency upgrades)
| Package | From | To |
|---|---|---|
| `thiserror` | 1.0.69 | 2.0.20 |
| `ulid` | 1.2.1 | 3.0.0 |
| `rusqlite` | 0.31.0 | 0.40.2 |
| `clap` | 4.6.4 | 4.6.6 |
| `quick-xml` | 0.36.2 | 0.41.0 |
| `lz4_flex` | 0.11.6 | 0.14.0 |
| `dirs` | 5.0.1 | 6.0.0 |
| `toml` | 0.8.23 | 1.1.4+spec-1.1.0 |
| `ratatui` | 0.28.1 | 0.30.2 |
| `crossterm` | 0.28.1 | 0.29.0 |
Fixed
- ulid 1.x → 3.x: `Ulid::new()` removed; updated to `Ulid::generate()` in `crates/linkmarks-core/src/model.rs:23`.
- quick-xml 0.36 → 0.41: `Event::GeneralRef` is now emitted as a separate event for character references (`&`, ` `, `á` …). Added exhaustive-match arm in `crates/bridges/linkmarks-bridge-netscape/src/parser.rs`. Bonus fix: removed spurious ASCII-space separator between text chunks so `AT&T` round-trips correctly.
- clippy `explicit-auto-deref` under Rust 1.97: `&**text` → `let raw_bytes: &[u8] = text;`.
Validation
- 250/250 tests green (`cargo test --workspace --no-fail-fast`)
- `cargo clippy --workspace --all-targets -- -D warnings` clean
- `cargo build --workspace --all-targets` clean
- `cargo fmt --all -- --check` clean
- CI smoke (`fmt + build + test + clippy + release binary + groff manpage`) green on PR #10
Refs: #10
LinkMarks v2.0.0 — Fase 2 batch (TUI + Firefox + SQLite store)
LinkMarks v2.0.0 — Fase 2 batch
Major version bump (1.0.1 → 2.0.0) because Fase 2 introduces a new
persistence surface (SQLite store) and the new tui subcommand changes
the CLI surface.
What's in this release
F1 — SQLite store (linkmarks-core): rusqlite with WAL mode,
busy_timeout=5000ms, foreign_keys=ON, soft-archive via
archived_at. XDG path resolution, TOML config loader, schema
migration runner.
F2 — Netscape bookmark HTML bridge: full parser + sink with
custom HTML5 named-entity decoder (~40 entities) + numeric
character reference handling. Atomic write via tempfile + persist.
F3 — Firefox bridge (linkmarks-bridge-firefox): read-only
places.sqlite reader (moz_bookmarks / moz_places / moz_tags)
plus raw LZ4 block decompressor for bookmarks-backups/*.jsonlz4
using lz4_flex after stripping the mozLz40\0 prefix.
F4 — Interactive TUI (linkmarks-tui, new crate, ~2159 LOC):
ratatui + crossterm-based terminal browser. Browse collections,
filter by substring / tag, view metadata, open URLs. 71 tests across
4 integration suites.
F5 — Install + docs + CI:
scripts/install.sh— bash,set -euo pipefail. Auto-detects host.
Options:--prefix,--binary-from,--force,--dry-run,--help.docs/man/linkmarks.1— 358-line roff-manpage. Renders cleanly
withgroff -man..github/workflows/ci-smoke.yml— fmt + build + test + clippy +
release binary smoke + groff render, all onubuntu-latest.tests/install_test.sh,tests/manpage_test.sh— bash smoke scripts.
Validation
cargo build --workspace --all-targets— cleancargo test --workspace --no-fail-fast— 250/250 greencargo clippy --workspace --all-targets -- -D warnings— cleanbash tests/install_test.sh— all checks passedbash tests/manpage_test.sh— all checks passed
Anti-features (locked — unchanged from v1.0.0)
- No telemetry, no phoning home, no automatic update notifier.
- No server-authoritative mode.
- No AI-without-cost-gate.
- No Docker-only deploy.
- No closed-source build.
Deferred to F2.5 (next batch)
- Fuzzy filter via
nucleo— implementation present in working
tree on branchchore/snapshot-2026-08-15-fuzz-foreign-wt
(crates/linkmarks-tui/src/filter.rs). - Sort modes —
crates/linkmarks-tui/src/sort.rspreserved on the
same snapshot branch. - Shell completions (
clap_complete+ build script). - README Install / Subcommands / CI sections refresh — separate
docs pass. - Packaging: Debian / RPM / Arch / Homebrew — future maintenance
release once install.sh stabilizes. cargo fmt --check— 56 hunks of pre-existing drift to batch
with F2.5.
What's next (see ROADMAP.md)
- Fase 3 — CRDT sync server. Spike first comparing
yrs
(Y-CRCT) vsautomerge-rs, decision documented in
docs/decisions/03-crdt-choice.md.linkmarks-servercrate
(axum HTTP + WebSocket, sqlx). Opt-in only — local mode unchanged. - Fase 4 — Dioxus desktop GUI.
- Fase 5 — Plugin market with stable ABI + signed binaries.
Full CHANGELOG entry: https://github.com/LOUST-PRO/LinkMarks/blob/v2.0.0/CHANGELOG.md
LinkMarks v1.0.1: hardening round 1
LinkMarks v1.0.1 — hardening round 1
Additive release. No breaking changes vs v1.0.0.
Highlights
- Tracking-param blocklist: 6 → 21 entries with documented sources
(fbclid,gclid,gbraid,wbraid,msclkid,dclid,yclid,
twclid,li_fat_id,igshid,ttclid,ref,ref_src,ref_url,
source,spm,scm,_hsenc,_hsmi,mkt_tok;utm_*and
mc_*as prefix match). - Per-domain preservation: new
canonical_configmodule with
ALWAYS_FUNCTIONALlist andCanonicalConfig::is_preserved. Operators
can override the blocklist per domain via~/.config/linkmarks/config.toml.
Seeconfig.toml.examplefor the YouTube / Vimeo / GitHub / Twitter-X /
Amazon recipes. - SQLite hardening: new
storagemodule applies 5 pragmas at every
open():journal_mode=WAL,busy_timeout=5000,synchronous=NORMAL,
foreign_keys=ON,temp_store=MEMORY. Concurrent-reader + single-writer
pattern with bounded lock contention.
Documentation
3 ADRs in MADR format document the design rationale:
- ADR 0002 — URL Canonicalization — the ruleset, the blocklist sources, the per-domain config schema, and 4 considered options.
- ADR 0003 — SQLite Hardening — per-pragma rationale, crash-safety tradeoff with
synchronous=NORMAL, and 4 considered options. - ADR 0004 — CRDT Tombstone Compaction — server-side per-client ack protocol for Fase 3, with grace period + snapshot retention + audit log. Proposed; implementation is Fase 3 work.
Validation
- 65/65 tests pass (was 58 in v1.0.0; +4 canonical + +3 storage).
cargo clippy --all-targets -- -D warnings→ 0 warnings.cargo fmt --check→ clean.cargo build --release→ OK, binary ≈ 2.5 MB.
Commits (4 ahead of main at v1.0.0)
98d0d19 docs: config.toml.example with per-domain preservation rules
a460b36 docs(decisions): ADR 0002/0003/0004 — canonical, sqlite, crdt tombstones
4757e8c feat(core): SQLite WAL + busy_timeout storage helper
fab59d0 feat(core): expand tracking-param blocklist + per-domain preservation rules
Compatibility
All new APIs are additive. Existing v1.0.0 callers of canonicalize(),
is_tracking(), and the bridge crates continue to work unchanged. The
storage module is opt-in: callers that don't yet use it are unaffected.
Full Changelog
See CHANGELOG.md and the v1.0.0...v1.0.1 comparison.