Releases: 2pisoftware/krillnotes
Krillnotes v1.1.1
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
ScriptManagerDialogalready 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
UpdateWorkspaceMetadataoperation, so they propagate to peers via delta bundles. Snapshots also include workspace metadata for initial peer sync (#199). - Read-only workspace properties for non-owners —
WorkspacePropertiesDialognow 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 improvements —
Cmd+Nnow creates a sibling note (previously created a child).Cmd+Shift+Ncreates a child note. Menu labels updated accordingly. Edit focus improvements for smoother note creation flow (#198).
Fixed
- Relay polling resilience — Parse
Retry-Afterheader from relay 429 responses into structuredRelayRateLimitederror withretry_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 fromi32tof64inhooks.rsto match float positions introduced in v1.0.
v1.1.0 — Security Hardening
⚠️ 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:
- Ensure all peers are online and synced
- Upgrade all peers to v1.1.0 simultaneously
- 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
.swarmand.krillnotesfiles (#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
Bugfixes
is_checkedmissing from query context —get_children()/get_note()results always hadis_checkedundefined, so views filtering by checkbox state (e.g. task progress counters) got zero matches (#167)on_savehooks could not resolve linked notes —on_savehooks had no query context, soget_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_linkfield in the default Fields tab did nothing (#169)
Added
- Travel planner example script — New example demonstrating
note_linkfields, multi-schema hierarchies,show_checkbox,is_leaf,filefields withallowed_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
coverfile field to the Book schema with a thumbnail in the hover tooltip.
Krillnotes v1.0.0
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_byfield 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
.krillnotesarchive, 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: trueto render an interactive checkbox in the tree view. Checked notes display with a strikethrough title. Theis_checkedstate is a first-class field on theNotestruct (liketitle), tracked by a dedicatedSetCheckedCRDT operation with full sync, export/import, and undo support. Rhai scripts can readnote.is_checkedin views/hooks and write viaset_checked(note_id, checked)inon_savehooks (PR #134). - Built-in TodoItem schema — A new system script (
TodoItem) withshow_checkbox: trueandis_leaf: true, ideal for checklists and task lists. - Sync events audit trail — New
sync_eventsdatabase 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. Includeslist_sync_eventsTauri 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_pubkeyis omitted fromworkspace.jsonandcreated_by/modified_byare 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_atcolumns where the frontend expects Unix seconds. Introduced aUnixSecs(i64)newtype that makes this mismatch a compile error (PR #160). - lock_identity stale state —
lock_identitynow inserts labels intoclosing_windowsand callsdestroy(), eagerly removing workspace entries to prevent stale state (PR #154). - Rapid file-open clobber — Split shared
pending_file_openintopending_krillnotes_openandpending_swarm_openso rapid.krillnotes+.swarmopens no longer overwrite each other (PR #154). - Duplicate-while-open guard —
duplicate_workspacenow checksfind_window_for_pathat 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 allalert()calls with inline error state (PR #143/#156). - Async forEach race —
HoverTooltipasyncforEachreplaced withPromise.allto 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
PeerInfoTypeScript type at the IPC boundary to replace untyped objects (PR #143/#156). - Pending sync false positives —
has_pending_ops_for_any_peer()now excludes operations authored by the peer and operations received from the peer (echo prevention), matching the filters used bygenerate_delta()(PR #135). - Stale view tab on note switch — Switching between note types with different view names no longer produces
render_viewerrors.
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 drop —
RelayAccount.passwordandsession_tokenare zeroized from memory when the struct is dropped via thezeroizecrate.Debugoutput 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 —
.swarmidrelay filename and attachment temp filename sanitized withPath::file_name()(PR #148). - SQLCipher key encoding — PRAGMA key switched from string interpolation to hex-encoded form (PR #148).
read_file_contentpath confinement — File reads confined to Krillnotes home directory and.themes/subdirectory (PR #148).- Note titles removed from production logs —
ghost_opsWARN-level log lines that leaked note content removed (PR #148). - Atomic note deletion —
delete_note_recursivenow runs deletion and operation log entry in a single transaction (PR #147). - Transactional migrations —
run_migrationswrapped inBEGIN IMMEDIATE/COMMITto prevent partial migration on crash (PR #147). - HLC panic guard —
wall_clock_ms()uses.unwrap_or_default()instead of.unwrap()(PR #147).
Data integrity
- Script undo restores original category —
ScriptRestoreundo variant now captures and restores the originalcategoryfield (PR #147). - Op purge limit increased — Default purge limit raised from 100 → 1000, configurable via
workspace_metakeypurge_limit(PR #147). - Checkbox timestamp fix —
set_note_checkednow storesmodified_atin seconds (PR #147). - Import preserves owner —
import_workspacenow preserves the originalowner_pubkeyfrom 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
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_idandrecipient_device_idsheaders. - 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-utilspackage.
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.appThen launch normally.
Windows — If SmartScreen blocks the installer, click More info → Run anyway.
Krillnotes v0.9.1
See the assets below to download this version and install it on your platform.
Krillnotes v0.9.0
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-rbaccrate — A new optional crate with a pluggablePermissionGatetrait. All note and script mutations go throughauthorize()- Protocol versioning —
.swarmbundles 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
.swarmfile, 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_permissionensures a full resend of newly-visible operations granted_by/revoked_bycorrectly populated inSetPermissionandRevokePermissionops- Various dialog z-index and theming fixes across invite and onboarding flows
Migration
Two breaking changes affect existing sync setups:
-
Protocol version in
.swarmbundles — All.swarmfiles (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. -
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:
- Have all peers upgrade to v0.9.0
- The workspace owner opens the workspace and grants permissions to each peer via ShareDialog
- The owner sends a fresh snapshot to each peer (Workspace Peers → Send Snapshot, or via relay)
- Peers import the snapshot — bidirectional sync resumes normally
Krillnotes v0.4.1
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 prevention —
received_from_peertracking 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
[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
.swarmfile 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
.swarmdelta 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
.swarmdelta 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
CreateDeltaDialoglisting accepted peers with their last-sync operation ID. One.swarmfile 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 watermarks —
last_sent_oponly 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 ownlast_sent_op, it rewinds its watermark automatically — peers self-heal from missed deltas without manual intervention. - Sync event streaming —
SyncEventenum (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:ContactBookDialogwith search, trust-level badges,AddContactDialog(live fingerprint preview, in-person verification gate), andEditContactDialog(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 flow —
InviteManagerwithInviteRecord,InviteFile,InviteResponseFilestructs. 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
.swarmfile.WorkspaceSnapshotstruct withto_snapshot_json/import_snapshot_jsonfor complete workspace serialisation. Snapshot baseline sets both watermarks so bidirectional delta sync works immediately. .swarmfile association — OS registers.swarmfiles 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 scripts —
owner_pubkeystored inworkspace_metaat creation. All six script mutation methods (create,update,delete,toggle,reorder,reorder_all) returnNotOwnererror for non-owners. Non-owner script ops are skipped during sync ingest (logged but not applied)..swarmbundle headers embed and validateowner_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 anon_hoverhook orshowOnHoverfields 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_nameTauri command — Resolves a public key to a display name; used by both the info panel and the operations log.is_leafschema option — Whenis_leaf: trueis 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
.swarmfile payloads are signed with Ed25519 and verified on open. - Hybrid encryption for
.swarmpayloads — X25519 key exchange + AES-256-GCM payload encryption. ack_operation_idfield in SwarmHeader — Threaded through delta codec for watermark self-correction.owner_pubkeyfield in SwarmHeader — Embedded in all bundle types; validated on receive.SetPermission,RevokePermission,JoinWorkspaceoperation variants — CRDT operations for future RBAC sync.peer_registrytable — Tracks known peers and their sync state per workspace (device ID, identity ID, channel type, channel params, watermarks, sync status).- Structured logging —
logcrate macros throughout sync engine, relay client, folder channel, and Tauri commands (replaceseprintln).
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 encoding —
RelayChannelnow 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 poll —
receive_bundlesnow callsensure_mailbox()so the relay routes incoming bundles to this account (was silently dropping them). - Tokio runtime drop panic —
poll_syncrestructured to run the sync engine insidespawn_blocking, releasing allMutexGuards 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 ofexpect(), preventing a secondary panic from a poisoned mutex during cleanup. generate_deltawith no watermark — Force Resync clearslast_sent_optoNone. Previouslygenerate_deltarejected this with "snapshot must precede delta"; now it returns all ops and the recipient'sINSERT OR IGNOREhandles duplicates.- Workspace Properties dialog crash —
meta.tagsis now guarded with?? []before calling.join()(wasTypeError: undefined is not an object). - Script category preserved on export/import —
ScriptManifestEntrynow includes thecategoryfield so schema vs. presentation classification survives a.krillnotesarchive 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_viewandregister_menuno 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_diringet_identity_public_key. source_display_namecorrectly 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_hoverhook and noshowOnHoverfields. - 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/ddgrid layout as the fields view and is hidden on custom view tabs.
Changed
- Breaking (Rhai scripts):
note.node_typerenamed tonote.schemain all Rhai script contexts.
Update any user...
Krillnotes v0.3.0
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:
- Open your workspace in v0.2.x
- Go to File → Export Workspace and save the .krillnotes archive
- Install v0.3.0
- Create a new identity in Settings → Identity Manager
- Use File → Import Workspace to restore from the archive
- 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