Skip to content

Releases: 2pisoftware/krillnotes

Krillnotes v1.1.1

13 May 11:54

Choose a tag to compare

Added

  • Disable "Manage Scripts" menu for non-owners — The native menu item is now greyed out for non-owner workspace users, matching the existing "Export Workspace" ownership gating. The ScriptManagerDialog already disabled editing controls internally; this hides the entry point entirely.
  • Sync workspace properties via operation log — Owner changes to workspace metadata (author, license, description, etc.) now create a signed UpdateWorkspaceMetadata operation, so they propagate to peers via delta bundles. Snapshots also include workspace metadata for initial peer sync (#199).
  • Read-only workspace properties for non-ownersWorkspacePropertiesDialog now checks ownership and renders all fields as disabled with a yellow hint banner for non-owners. Only the owner sees Save/Cancel; peers see a Close button (#199).
  • Cmd+N for sibling notes, edit focus improvementsCmd+N now creates a sibling note (previously created a child). Cmd+Shift+N creates a child note. Menu labels updated accordingly. Edit focus improvements for smoother note creation flow (#198).

Fixed

  • Relay polling resilience — Parse Retry-After header from relay 429 responses into structured RelayRateLimited error with retry_after_secs. Downgrade attachment blob-skip log from warn to debug for deleted notes (expected during normal sync of append-only op log).
  • TextNote "Add Child Note" tree action — Fixed the menu hook calling non-existent Rhai functions (create_note/update_note); replaced with the correct API (create_child/set_title/commit). Also fixed position type from i32 to f64 in hooks.rs to match float positions introduced in v1.0.

v1.1.0 — Security Hardening

13 May 02:16

Choose a tag to compare

⚠️ Breaking: Canonical JSON signatures

This release switches operation and invite signing to RFC 8785 (JSON Canonicalization Scheme). Signatures created by v1.1.0 will not verify against v1.0.x, and vice versa.

All peers sharing a workspace must upgrade to v1.1.0 together. If a v1.0.x peer sends a delta to a v1.1.0 peer (or the reverse), signature verification will fail and the operations will be rejected.

Recommended upgrade path:

  1. Ensure all peers are online and synced
  2. Upgrade all peers to v1.1.0 simultaneously
  3. Operations created after the upgrade will use the new canonical format

Existing data is unaffected — only new signatures use the new format.


Security

This release addresses all 11 findings from the Krillnotes Security Review v1.0.1 (April 2026):

  • Enable SQLite WAL journal mode — Reduced corruption risk on crash during write-heavy operations (#175)
  • Document SQLCipher PRAGMA key escaping rationale (#181)
  • Remove attachment salt hex decode fallback — Replaced silent fallback with explicit error (#176)
  • Centralize HKDF info strings — All 7 domain-separation strings in one module (#177)
  • Harden Rhai sandbox against filesystem access — Removed default FileModuleResolver (#174)
  • Use RFC 8785 canonical JSON for signature payloads — Deterministic serialization for signing (#178)
  • Enforce relay TLS 1.2 minimum — Prevent protocol downgrade attacks (#179)
  • Add ZIP integrity verification — CRC32 + deflate corruption checks for .swarm and .krillnotes files (#180)
  • Property-based crypto tests — 25 proptest cases covering all crypto primitives (#182)
  • Cargo audit in CI — Advisory job catches new dependency vulnerabilities (#183)
  • Inline attachment size limits — Delta bundles chunked at 10 MB; attach_file() defaults to 10 MB per file to match relay limits (#184)

Full changelog: https://github.com/2pisoftware/krillnotes/blob/master/CHANGELOG.md

Krillnotes v1.0.1

29 Apr 02:26

Choose a tag to compare

Bugfixes

  • is_checked missing from query contextget_children()/get_note() results always had is_checked undefined, so views filtering by checkbox state (e.g. task progress counters) got zero matches (#167)
  • on_save hooks could not resolve linked noteson_save hooks had no query context, so get_note() returned unit. Hooks that derive titles from linked notes always fell through to fallback titles (#168)
  • Note link clicks in Fields tab — Clicking a note_link field in the default Fields tab did nothing (#169)

Added

  • Travel planner example script — New example demonstrating note_link fields, multi-schema hierarchies, show_checkbox, is_leaf, file fields with allowed_types, tags, and rich views that resolve linked notes. Includes 8 schemas, 6 views, 7 hovers, 2 context menus, and a sample Japan trip archive.
  • SCRIPTING.md: allow_attachments / attachment_types — Documented the note-level attachment schema options.
  • Book-collection cover field — Added a cover file field to the Book schema with a thumbnail in the hover tooltip.

Krillnotes v1.0.0

28 Apr 00:23

Choose a tag to compare

Caution

Breaking change — workspaces from previous versions (0.9.x and earlier) cannot be opened directly in v1.0.0. The database schema, operation log format, and identity model have changed significantly. To migrate: open your workspace in the previous version, export it via File → Export Workspace to a .krillnotes archive, then import the archive into v1.0.0 via the Workspace Manager.

First stable release. Krillnotes 1.0 ships a production-ready, local-first note-taking app with end-to-end encrypted multi-device sync, role-based access control, cryptographic identity management, and a fully scriptable schema engine. Every mutation is HLC-timestamped, Ed25519-signed, and verified on receipt — forming a tamper-evident CRDT log that syncs across devices via relay server, shared folder, or manual file exchange. This release also delivers a comprehensive security hardening pass (resource limits, path traversal fixes, zeroized secrets, transactional migrations) and dozens of bug fixes accumulated since the 0.9.x release candidates.

Added

  • Per-operation verification — Incoming sync operations are now verified individually. Sender-authored ops are checked against their Ed25519 signature; relayed third-party ops require a co-signature ("vouch") from the forwarding peer. Ops that fail verification are rejected and logged to the sync events audit trail. The verified_by field is surfaced in the Operations Log detail panel and the note Info panel metadata, with display names resolved from the identity/contact book. Full A→B→C transitive trust chain tested end-to-end.
  • Import metadata preview — When importing a .krillnotes archive, the import dialog now shows a collapsible "Workspace Properties" section displaying the author, description, license, homepage, and tags embedded in the archive — matching the same display shown in the invite acceptance workflow (PR #137).
  • Sync on close — When closing a workspace with unsynchronized changes, the app prompts to sync with relay/folder peers before closing. A new "Sync on Close" setting in Settings → General offers three modes: Always sync, Ask before closing (default), Never sync. Includes a spinner overlay during sync and error recovery if sync fails (PR #135).
  • Note checkbox support — Schemas can set show_checkbox: true to render an interactive checkbox in the tree view. Checked notes display with a strikethrough title. The is_checked state is a first-class field on the Note struct (like title), tracked by a dedicated SetChecked CRDT operation with full sync, export/import, and undo support. Rhai scripts can read note.is_checked in views/hooks and write via set_checked(note_id, checked) in on_save hooks (PR #134).
  • Built-in TodoItem schema — A new system script (TodoItem) with show_checkbox: true and is_leaf: true, ideal for checklists and task lists.
  • Sync events audit trail — New sync_events database table logs sync security failures (bundle rejections, signature failures, sidecar mismatches) with peer identity and detail. A new "Sync Events" tab in the Operations Log dialog displays the audit trail. Includes list_sync_events Tauri command and i18n across all 7 locales (PR #149).

Improved

  • Wider script & theme editors — The script and theme editor dialogs now expand to 90% of the window width when editing, instead of being fixed at 700px. The list view retains its compact size.

Fixed

  • Identity-neutral export — Exporting a shared workspace no longer embeds the owner's identity. Archives are now fully identity-neutral: owner_pubkey is omitted from workspace.json and created_by/modified_by are cleared from notes. On import, the importer becomes root owner and author of all notes (PR #164).
  • Sync timestamp corruption — Synced notes displayed dates like year 56000+ because the sync replay path stored HLC milliseconds in created_at/modified_at columns where the frontend expects Unix seconds. Introduced a UnixSecs(i64) newtype that makes this mismatch a compile error (PR #160).
  • lock_identity stale statelock_identity now inserts labels into closing_windows and calls destroy(), eagerly removing workspace entries to prevent stale state (PR #154).
  • Rapid file-open clobber — Split shared pending_file_open into pending_krillnotes_open and pending_swarm_open so rapid .krillnotes + .swarm opens no longer overwrite each other (PR #154).
  • Duplicate-while-open guardduplicate_workspace now checks find_window_for_path at entry and returns an error if the source workspace is currently open (PR #154).
  • Non-owner duplicate/export blocked — Peers invited to a workspace they don't own can no longer duplicate or export it. Duplicate button is disabled in the workspace manager, Export menu item is toggled per-window, and backend guards return NOT_OWNER (PR #154).
  • Frontend i18n gaps — Replaced hardcoded English strings with i18n keys across InfoPanel and WorkspaceView, fixed shadowed t() variable, replaced all alert() calls with inline error state (PR #143/#156).
  • Async forEach raceHoverTooltip async forEach replaced with Promise.all to avoid sequential awaits (PR #143/#156).
  • Stale closure prevention — InfoPanel callback props wrapped in useCallback, memo comparator updated to prevent stale closures (PR #143/#156).
  • PeerInfo type boundary — Added PeerInfo TypeScript type at the IPC boundary to replace untyped objects (PR #143/#156).
  • Pending sync false positiveshas_pending_ops_for_any_peer() now excludes operations authored by the peer and operations received from the peer (echo prevention), matching the filters used by generate_delta() (PR #135).
  • Stale view tab on note switch — Switching between note types with different view names no longer produces render_view errors.

Security

  • Per-operation signature verification on receive — Every incoming operation is now individually verified: sender-authored ops must pass Ed25519 signature check; relayed ops must carry a valid co-signature (vouch) from the forwarding peer. Unverifiable ops are rejected and logged to the sync events table. This closes the relay trust gap — a compromised relay cannot inject or tamper with operations.
  • Sidecar hashes in bundle manifest — Attachment sidecar ciphertext is now included in the BLAKE3 manifest hash before Ed25519 signing. Sidecars stripped in transit now invalidate the bundle signature (PR #149).
  • Relay password zeroized on dropRelayAccount.password and session_token are zeroized from memory when the struct is dropped via the zeroize crate. Debug output redacts both fields (PR #149).
  • Rhai engine resource limits — Script execution capped at 200K operations, 64 call levels, 1M string size, and 100K array size (PR #148).
  • Path traversal fixes.swarmid relay filename and attachment temp filename sanitized with Path::file_name() (PR #148).
  • SQLCipher key encoding — PRAGMA key switched from string interpolation to hex-encoded form (PR #148).
  • read_file_content path confinement — File reads confined to Krillnotes home directory and .themes/ subdirectory (PR #148).
  • Note titles removed from production logsghost_ops WARN-level log lines that leaked note content removed (PR #148).
  • Atomic note deletiondelete_note_recursive now runs deletion and operation log entry in a single transaction (PR #147).
  • Transactional migrationsrun_migrations wrapped in BEGIN IMMEDIATE / COMMIT to prevent partial migration on crash (PR #147).
  • HLC panic guardwall_clock_ms() uses .unwrap_or_default() instead of .unwrap() (PR #147).

Data integrity

  • Script undo restores original categoryScriptRestore undo variant now captures and restores the original category field (PR #147).
  • Op purge limit increased — Default purge limit raised from 100 → 1000, configurable via workspace_meta key purge_limit (PR #147).
  • Checkbox timestamp fixset_note_checked now stores modified_at in seconds (PR #147).
  • Import preserves ownerimport_workspace now preserves the original owner_pubkey from the archive (PR #147).

Changed

  • Script category renamed "presentation" → "library" — The internal DB/Rust category value now matches the frontend UI label. Includes a DB migration to update existing rows automatically (PR #130).

Full changelog: https://github.com/2pisoftware/krillnotes/blob/v1.0.0/CHANGELOG.md

Krillnotes v0.9.2

31 Mar 07:05

Choose a tag to compare

Krillnotes v0.9.2

Patch release fixing multi-device sync reliability and ARM Linux builds.

Multi-device sync fixes

v0.9.1 introduced multi-device sync with per-device derived signing keys, but relay routing between peers still used identity-level keys. This caused invite acceptances and onboarding snapshots to be silently dropped. This release fixes the full relay routing path:

  • Cross-peer relay routing — The identity public key is now registered as an additional device key on the relay, so bundles sent to a peer's identity address are correctly delivered.
  • Invite acceptance delivery — The sync engine no longer consumes Accept-mode bundles before the invite poller can process them.
  • Snapshot routing — Outbound snapshots now include proper sender_device_id and recipient_device_ids headers.
  • My Devices list — The identity routing key no longer appears as a phantom device in "Send to My Device".
  • Imported identities — Fixed a "No such file or directory" error when saving synthetic invites on freshly-imported identities.

CI

  • ARM Linux AppImage — Fixed the aarch64 release build by adding the missing xdg-utils package.

Installing on macOS and Windows

Krillnotes is not yet code-signed or notarised, so both platforms will warn you on first launch.

macOS — If you see "Krillnotes cannot be opened because the developer cannot be verified", run this once in Terminal after moving the app to /Applications:

xattr -cr /Applications/Krillnotes.app

Then launch normally.

Windows — If SmartScreen blocks the installer, click More info → Run anyway.

Krillnotes v0.9.1

29 Mar 12:40

Choose a tag to compare

Krillnotes v0.9.1 Pre-release
Pre-release

See the assets below to download this version and install it on your platform.

Krillnotes v0.9.0

23 Mar 01:56

Choose a tag to compare

Feature-complete release candidate. This is the last major feature release before v1.0 — cross-platform testing on Windows and Linux is in progress. The headline addition is role-based access control: workspace owners can now grant peers granular access to subtrees, with a full permission management UI. Sync also gains background polling and one-click relay invite sharing.

⚠️ Breaking changes — see Migration below. Existing sync peers must re-exchange snapshots, and workspace owners must grant permissions to peers before they can see any notes.

Highlights

Role-based access control (RBAC)

Workspace owners can grant peers access to subtrees with five roles: owner, admin, editor, reader, and none. Permissions cascade from parent to child — the nearest explicit grant wins. The root owner always has full access.

  • Permission management UI — Colour-coded role dots on tree nodes, share anchor icons on nodes with explicit grants, and ghost ancestor styling for path-context nodes
  • ShareDialog — Pick a peer and role to grant subtree access, accessible from the Info panel or context menu
  • CascadePreviewDialog — See the impact before demoting or revoking access, with opt-in checkboxes for affected peers
  • Role-aware actions — Edit, delete, move, and create controls are disabled when the user lacks permission. Non-owners cannot add siblings at root level
  • "Shared with" section — The Info panel shows who has access to the selected note, their roles, and grant sources
  • krillnotes-rbac crate — A new optional crate with a pluggable PermissionGate trait. All note and script mutations go through authorize()
  • Protocol versioning.swarm bundles carry a protocol version inside the encrypted payload; mismatched bundles are rejected

Sync improvements

  • Background polling — Relay and folder channels automatically poll for incoming operations and snapshots across all unlocked identities
  • Send snapshot via relay — Workspace owners can send snapshots to peers over the relay, not just via file
  • Create workspace from accepted invite — After receiving a peer's snapshot, create the workspace directly from the accepted invites section
  • Invite-to-subtree — Invites can scope access to a specific subtree. Permission ops are included in snapshots for peer onboarding

Relay invite sharing

  • One-click relay invite sharing — "Share Invite Link" creates an invite, uploads it to the relay, and copies the URL to clipboard
  • File → Accept Invite — Accept an invite by pasting a relay URL or opening a .swarm file, without needing a workspace open
  • Full relay round-trip — Both sides exchange URLs instead of files
  • Relay account fallback — If no relay account is configured, the registration dialog opens automatically

Fixed

  • Read-access filtering enforced on note queries — non-owners only see notes they have permission to access
  • Permission grants cleaned up when anchor notes are deleted
  • MoveNote checks destination scope before allowing the move
  • Sync is never blocked by RBAC — replication proceeds unconditionally; RBAC controls visibility only
  • Peer watermark reset on set_permission ensures a full resend of newly-visible operations
  • granted_by / revoked_by correctly populated in SetPermission and RevokePermission ops
  • Various dialog z-index and theming fixes across invite and onboarding flows

Migration

Two breaking changes affect existing sync setups:

  1. Protocol version in .swarm bundles — All .swarm files (deltas, snapshots, invites) now carry a mandatory protocol version tag. Bundles created by v0.4.x will be rejected by v0.9.0 and vice versa. All peers must upgrade to v0.9.0, then the workspace owner must send a fresh snapshot to each peer to re-establish sync.

  2. RBAC enforced by default — Non-root-owner peers now see an empty tree until they are explicitly granted permissions. After upgrading, the workspace owner must open the ShareDialog (right-click a note → "Share subtree…" or use the Info panel) and grant each existing peer an appropriate role (e.g. editor on the root note for full access). Until permissions are granted, peers will not see any notes.

Recommended upgrade steps:

  1. Have all peers upgrade to v0.9.0
  2. The workspace owner opens the workspace and grants permissions to each peer via ShareDialog
  3. The owner sends a fresh snapshot to each peer (Workspace Peers → Send Snapshot, or via relay)
  4. Peers import the snapshot — bidirectional sync resumes normally

Krillnotes v0.4.1

15 Mar 21:06

Choose a tag to compare

Relay account management moves from a per-peer concern to the Identity Manager, and several sync reliability fixes land.

Changed

  • Relay accounts moved to Identity Manager — Relay server credentials are now managed per-identity (like contacts) instead of per-peer. A new "Relays" button in Identity Manager opens a relay account book for registering, viewing, and deleting relay accounts. Workspace peer configuration uses a simple dropdown picker instead of the old Configure Relay dialog.
  • Automatic relay session renewal — Relay account passwords are stored (encrypted) so sessions are automatically refreshed on identity unlock — no more re-entering credentials when sessions expire.
  • Old relay credentials auto-migrated — Existing relay credentials are automatically migrated to the new per-identity format on first unlock.

Fixed

  • Folder sync addressing — Recipient-prefixed filenames and inbox filtering so bundles in a shared folder are only picked up by the intended peer, with base64 slash sanitization for safe path handling
  • Watermark feedback loop — ACK now tracks the last bundle op (not just applied ops), eliminating infinite full-resend loops in multi-device topologies
  • Poll order — Inbound-first processing prevents false ACK-behind resets from one-cycle timing lag
  • 0-op bundle suppression — No bundles sent when idle; no ACK ping-pong between peers
  • Echo preventionreceived_from_peer tracking prevents hub nodes from echoing forwarded ops back to the original sender
  • HLC-ordered delta application — Delta ops from all channels are collected and sorted by HLC timestamp before applying, preventing watermark issues when bundles arrive out of order across channels

Krillnotes v0.4.0

15 Mar 04:41

Choose a tag to compare

[0.4.0] — 2026-03-15

Sync is here. This release adds multi-device workspace sync — via a relay server, a shared folder, or manual .swarm file exchange. It also introduces an encrypted contact book, a peer invite workflow, workspace snapshots, and owner-only script enforcement.

Added

Sync engine

  • Three sync channels — Sync with peers via relay (HTTP relay server with mailbox routing), folder (shared local/network folder), or manual (export/import .swarm delta files by hand). Each peer can use a different channel; switch at any time from the Workspace Peers dialog.
  • Relay sync — Register an account on a relay server, bind your device key, and exchange encrypted delta bundles over HTTP. Session tokens are persisted locally (AES-256-GCM encrypted); expired sessions prompt re-login. Configure Relay dialog with register/login tabs. Relay credentials stored per-identity under ~/.config/krillnotes/identities/<uuid>/relay/.
  • Folder sync — Point a peer at a shared directory (local disk, NAS, Dropbox, etc.) and Krillnotes writes .swarm delta files into it. The peer's next poll picks up the file, applies it, and deletes the consumed bundle.
  • Manual delta export — "Create delta Swarm" in the Edit menu opens CreateDeltaDialog listing accepted peers with their last-sync operation ID. One .swarm file is generated per selected peer, encrypted for that peer's public key. The recipient opens the file to apply the delta.
  • Sync Now button — One-click sync from the Workspace Peers dialog triggers a full send-and-receive cycle across all configured channels.
  • Force Resync — Per-peer "↺" button in the Workspace Peers dialog resets the watermark so the next sync re-sends all operations from the last snapshot baseline.
  • Delivery-confirmed watermarkslast_sent_op only advances when the transport confirms the bundle was routed, preventing silent data loss when a relay skips unknown or unverified devices.
  • ACK-based watermark self-correction — Each outbound delta carries ack_operation_id (the last op received from that peer). When a peer sees that the remote's ACK is behind its own last_sent_op, it rewinds its watermark automatically — peers self-heal from missed deltas without manual intervention.
  • Sync event streamingSyncEvent enum (DeltaSent, BundleApplied, AuthExpired, SyncError, IngestError, SendSkipped) published to the frontend for real-time status updates.
  • Peer sync status tracking — Each peer tracks sync state (idle, syncing, error, auth_expired, not_delivered) with detail and error messages, displayed as status badges in the Workspace Peers dialog.

Peer management and invites

  • Per-identity encrypted contact book — Contacts are stored per identity under ~/.config/krillnotes/identities/<uuid>/contacts/ as AES-256-GCM encrypted blobs. Encryption key derived via HKDF-SHA256 from the identity seed; only in memory while unlocked. Full CRUD via six Tauri commands. UI: ContactBookDialog with search, trust-level badges, AddContactDialog (live fingerprint preview, in-person verification gate), and EditContactDialog (local name, notes, delete). Accessible via "Contacts (n)" button in Identity Manager.
  • Workspace Peers dialog — New "Workspace Peers" item in the Edit menu lists all sync peers with resolved display name, 4-word BIP-39 fingerprint, trust-level badge, channel type, sync status, and last-sync time. Actions: remove peer (inline confirmation), add contact as peer, switch channel, configure relay, force resync, and create invite.
  • Multi-use signed invite flowInviteManager with InviteRecord, InviteFile, InviteResponseFile structs. Ed25519 signing/verification with canonical JSON. Create/list/revoke invites; full invite→response round-trip. Seven Tauri commands. Four React dialogs (CreateInviteDialog, AcceptPeerDialog, ImportInviteDialog, InviteManagerDialog). Localised in all 7 languages.
  • Workspace snapshot exchange — A workspace owner can send a full snapshot to a new peer via a .swarm file. WorkspaceSnapshot struct with to_snapshot_json / import_snapshot_json for complete workspace serialisation. Snapshot baseline sets both watermarks so bidirectional delta sync works immediately.
  • .swarm file association — OS registers .swarm files with Krillnotes; double-click opens the correct dialog (invite, snapshot, or delta).
  • File > Invite Peer and Open .swarm File menu items
  • Show and copy public key and fingerprint in Identity Manager — for sharing with peers.
  • Auto-prompt to unlock required identity when opening an invite or snapshot file.

Owner-only script enforcement

  • Owner-only scriptsowner_pubkey stored in workspace_meta at creation. All six script mutation methods (create, update, delete, toggle, reorder, reorder_all) return NotOwner error for non-owners. Non-owner script ops are skipped during sync ingest (logged but not applied). .swarm bundle headers embed and validate owner_pubkey. UI disables script mutation controls (save, delete, new, toggle, drag-reorder, editor) for non-owners with an info banner. "Owner" badge shown in Workspace Peers dialog.

UI improvements

  • Hover indicator caret on tree nodes — A subtle is shown on the right of tree node rows when the note type has an on_hover hook or showOnHover fields defined.
  • Identity/contact name in note Info panel — Created and Modified timestamps show the author's display name inline (local identity first, then contact address book, then 8-char fingerprint for unknown keys).
  • resolve_identity_name Tauri command — Resolves a public key to a display name; used by both the info panel and the operations log.
  • is_leaf schema option — When is_leaf: true is set on a schema, notes of that type cannot have children. Blocked in core (create_note, move_note, deep_copy_note) and observed in the UI ("Add Child" and "Paste as Child" are greyed out; drag-drop onto leaf notes is blocked).

Swarm protocol internals

  • SwarmHeader codec and bundle-level signatures — All .swarm file payloads are signed with Ed25519 and verified on open.
  • Hybrid encryption for .swarm payloads — X25519 key exchange + AES-256-GCM payload encryption.
  • ack_operation_id field in SwarmHeader — Threaded through delta codec for watermark self-correction.
  • owner_pubkey field in SwarmHeader — Embedded in all bundle types; validated on receive.
  • SetPermission, RevokePermission, JoinWorkspace operation variants — CRDT operations for future RBAC sync.
  • peer_registry table — Tracks known peers and their sync state per workspace (device ID, identity ID, channel type, channel params, watermarks, sync status).
  • Structured logginglog crate macros throughout sync engine, relay client, folder channel, and Tauri commands (replaces eprintln).

Fixed

  • Rhai engine reloaded after sync ingest and snapshot import — Applying script operations via delta sync or snapshot import now reloads the Rhai engine so new/updated schemas take effect immediately without restarting the app.
  • Relay recipient device key encodingRelayChannel now converts peer device keys to hex (matching the relay server's format) instead of sending internal identity placeholders, fixing silent bundle drops.
  • Relay mailbox registration on pollreceive_bundles now calls ensure_mailbox() so the relay routes incoming bundles to this account (was silently dropping them).
  • Tokio runtime drop panicpoll_sync restructured to run the sync engine inside spawn_blocking, releasing all MutexGuards before spawning, preventing a panic when reqwest's internal Tokio runtime is dropped on an async thread.
  • Poisoned mutex on window close — Destroyed window handler uses unwrap_or_else(|e| e.into_inner()) instead of expect(), preventing a secondary panic from a poisoned mutex during cleanup.
  • generate_delta with no watermark — Force Resync clears last_sent_op to None. Previously generate_delta rejected this with "snapshot must precede delta"; now it returns all ops and the recipient's INSERT OR IGNORE handles duplicates.
  • Workspace Properties dialog crashmeta.tags is now guarded with ?? [] before calling .join() (was TypeError: undefined is not an object).
  • Script category preserved on export/importScriptManifestEntry now includes the category field so schema vs. presentation classification survives a .krillnotes archive round-trip. Previously all scripts were imported as "presentation" (PR #89).
  • Library script functions are now visible to schema scripts and their hooks — library source is prepended when compiling schema scripts.
  • register_view and register_menu no longer produce duplicate tabs/entries when a library script is loaded alongside multiple schema scripts.
  • Snapshot import no longer seeds a default root note, preserving the imported workspace structure.
  • Identity file path resolved relative to config_dir in get_identity_public_key.
  • source_display_name correctly populated in invite bundles.
  • Unlocked identity UUID refreshes when Identity Manager closes or Swarm dialog opens.
  • Schema script pre-validation now sets the loading category so library functions are available during validation.
  • Hover tooltip no longer appears for notes whose type has no on_hover hook and no showOnHover fields.
  • Operations log now checks the contact address book when resolving author names, in addition to local identities.
  • Note Info panel metadata uses the same dl/dt/dd grid layout as the fields view and is hidden on custom view tabs.

Changed

  • Breaking (Rhai scripts): note.node_type renamed to note.schema in all Rhai script contexts.
    Update any user...
Read more

Krillnotes v0.3.0

07 Mar 03:07

Choose a tag to compare

Krillnotes v0.3.0

This is a breaking release. Please read the migration notes below before upgrading.

Migration notes

Workspaces from v0.2.x cannot be opened directly. This release changes the authentication model (identity-based keys instead of per-workspace passwords) and the database schema (HLC timestamps, float positions, new columns). To migrate:

  1. Open your workspace in v0.2.x
  2. Go to File → Export Workspace and save the .krillnotes archive
  3. Install v0.3.0
  4. Create a new identity in Settings → Identity Manager
  5. Use File → Import Workspace to restore from the archive
  6. Scripts with custom on_view, on_hover, or add_tree_action hooks must be updated. These APIs are removed. See SCRIPTING.md for the new register_view, register_hover, and register_menu APIs. All on_save hooks must also be migrated to the SaveTransaction model (set_field() / set_title() / reject()). Schema scripts must now declare a version: 1 key.

macOS security warning

macOS Gatekeeper blocks unsigned apps with an "app is damaged and can't be opened" message. To bypass this after installing from the .dmg:

xattr -cr /Applications/Krillnotes.app

This removes the quarantine flag macOS adds when mounting a DMG. The app will open normally afterwards.

What's new

Identity & workspace security

  • Identity system — An Ed25519 keypair protected by Argon2id now manages workspace access. Unlock your identity once per session; all bound workspaces open without a password prompt.
  • Identity Manager — Create, rename, unlock, lock, and delete identities from Settings.
  • .swarmid export/import — Export your identity as a portable encrypted file to use on another device.
  • Workspace Manager — Full workspace browser with metadata, size, note count, and per-workspace actions (Open, Duplicate, Delete, New).
  • Random workspace passwords — Workspaces no longer use a user-visible password; a 32-byte random key is generated and stored encrypted under your identity.

CRDT foundations

  • HLC timestamps — Every mutation is now stamped with a Hybrid Logical Clock, providing causal ordering across devices as a prerequisite for future sync.
  • Ed25519-signed operations — Each mutation is signed by the author's identity key, laying the foundation for trustless multi-device merge.
  • UpdateNote and SetTags operation variants — Title changes and tag assignments are now first-class operations in the log.
  • Author display in Operations Log — Each entry now shows the author's identity name.

Schema extensions

  • SaveTransaction API — on_save hooks now use set_field(), set_title(), reject(), and commit() for declarative, transactional mutations with a 7-step validation pipeline.
  • Field groups — Group related fields into collapsible sections with optional dynamic visibility.
  • Field-level validate closures — Inline validation with live error display on blur.
  • Note-level reject() — Abort a save with a structured error banner.
  • Script categories — Scripts are now Schema (.schema.rhai) or Library/Presentation (.rhai). The Script Manager shows category badges and provides starter templates.
  • Two-phase script loading — Library helpers load before schema hooks, so shared functions are available everywhere.
  • register_view / register_hover / register_menu — View tabs, hover tooltips, and context-menu actions are now registered from presentation scripts, decoupled from schema definitions.
  • Tabbed view mode — Notes with registered views show a tab bar; the Fields tab is always rightmost.
  • Schema versioning — schema() requires version: N. Lower-version re-registration is a hard error.
  • Data migration closures — Declare a migrate map to automatically upgrade notes when the schema version increases.
  • Batch migration on load — Stale notes are migrated in a single transaction per schema type on workspace open, with a toast notification on completion.

Changed

  • notes.position is now REAL (f64) for future fractional CRDT reordering
  • Operations table uses three HLC columns instead of a single timestamp
  • Note.fields uses BTreeMap for deterministic serialization (required for signing)
  • save_note IPC replaces update_note; old command removed
  • category column added to user_scripts table
  • License changed from MIT to MPL-2.0

Fixed

  • Serde camelCase on SaveResult::ValidationErrors enum variant fields
  • evaluate_group_visibility and validate_field invoke parameter names