Krillnotes banner
Open source · MPL-2.0

Notes that swim the way you think

A local-first note-taking app built with Rust. Define your own note types with scripts, sync across devices, and share securely with your team β€” all without a cloud account.

Krillnotes main window showing a contacts folder

Sync and share without the cloud

Your data moves the way you want it to β€” peer-to-peer, no account required.

πŸ”„

Sync on any channel

Internet relay, shared folders, or via USB stick β€” all you need is file transfer.

βœ‰οΈ

Invite your peers

One-click via relay URL, or send an invite file by any means you like.

πŸ›‘οΈ

Trusted contacts

Manage your peers with an encrypted contact book and state-of-the-art cryptography.

Organise your teams

Grant peers granular access to any subtree. Permissions cascade automatically β€” the nearest grant wins.

  • Subtree-level permissions β€” grant access to any branch of your tree
  • Five roles from owner to reader β€” cascading from parent to child
  • Impact preview before demotion or revocation
  • Role-aware UI β€” controls adapt to your access level
  • Owner-only script enforcement β€” only workspace owners can modify scripts
πŸ‘‘ Owner full control
βš™οΈ Admin manage peers and permissions
✏️ Editor edit notes
πŸ‘οΈ Reader view only

The schema is the application

Define custom note types with Rhai scripts. Add fields, hooks, validation, views, and context-menu actions β€” no recompilation needed.

  • Typed fields (text, date, select, rating, note_link, file…)
  • On-save hooks with transactional API (set, validate, reject, commit)
  • Custom views and hover tooltips via register_view / register_hover
  • Context-menu actions via register_menu
  • Schema versioning with automatic data migration
  • Field groups and validation closures
  • Ready-to-use templates β€” book collection, Zettelkasten, and more
Read the Scripting Guide β†’
task.schema.rhai
schema("Task", #{
    version: 2,
    fields: [
        #{ name: "name",   type: "text",   required: true },
        #{ name: "status", type: "select",
           options: ["TODO", "WIP", "DONE"] },
        #{ name: "due_date", type: "date" },
    ],
    on_save: |tx| {
        let status = tx.get("status");
        let symbol = if status == "DONE" { "βœ“" }
            else if status == "WIP" { "β†’" }
            else { " " };
        tx.set_title("[" + symbol + "] " + tx.get("name"));
        tx.commit();
    },
    migrate: #{
        2: |note| { note.fields["due_date"] = ""; }
    }
});

And much more

Everything you need, nothing you don't.

🌊
Hierarchical notes
🏷️
Tags & tag cloud
πŸ”—
Note links
πŸ”
Fuzzy search
πŸ”’
Encrypted at rest
πŸ”‘
Identity system
πŸ“Ž
File attachments
πŸ’¬
Hover tooltips
πŸ“¦
Export & Import
🌐
7 languages
🎨
Theming
πŸ’»
Cross-platform
πŸ“
Workspace manager
↩️
Undo / Redo
πŸ“‹
Operations log
πŸ“
Templates

Solid foundations, tiny footprint

Modern tools chosen for speed, reliability, and cross-platform reach.

πŸ¦€ Rust βš›οΈ React πŸͺŸ Tauri v2 πŸ—„οΈ SQLite πŸ” SQLCipher πŸ“œ Rhai scripting

Ready to dive in?

Krillnotes is free, open source, and ready for your notes.

Download Krillnotes