You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
v0.2.0 — quick capture, professional markdown editing & vault protection
global quick capture from the tray icon, command palette, a local shortcut and the remappable ctrl+alt+space system-wide shortcut: it opens an independent mini-window, preserves the draft when cancelled and writes directly to an Inbox/ note or the selected Kanban column without bringing the main window forward.
native global-shortcut backends for Windows (RegisterHotKey), Linux X11 (XGrabKey) and macOS (RegisterEventHotKey), with explicit fallback for Wayland, conflicts and unsupported platforms; plus an opt-in setting to keep Enki in the tray when the main window closes.
professional markdown editing through MarkdownEditing: toggle inline formatting and block markers, apply actions to multiline selections, indent and renumber lists, continue lists and quotes with enter, smart home, marker deletion, configurable automatic pairs, url-to-link pasting, and line move, duplicate, delete and expand operations, all connected to remappable shortcuts and complete undo actions.
syntax highlighting for fenced code blocks with a declared language using the textmate grammars and light/dark themes already shared by the file viewer, loaded in the background, cached per block and bounded by time and line count so typing never blocks.
obsidian-compatible callouts (> [!note], tip, warning, danger and their aliases) with theme-aware icons, titles, tones and backgrounds, plus the /aviso command so they can be inserted without memorising the syntax.
settings under settings > editor to choose justified or ragged text and enable or disable automatic bracket and quote closing, persisted per vault and translated into all seven supported languages.
reusable note templates in <vault>/.enki/templates/: each template is a markdown file with optional front matter (name, description, title) and a body with {{title}}, {{date}}, {{time}}, {{datetime}}, {{weekday}}, {{month}}, {{year}}, {{uuid}} and {{cursor}} variables, with optional format ({{date:dd/MM/yyyy}}) and offset ({{date+1d}}); anything unrecognised is left untouched in the note.
a "from template" flow in documents — full-view button, simplified-view action row, note grid context menu and command palette — with a picker to create the note, edit the template in an editor tab, create a new template pre-filled with the syntax, open its folder and delete it honouring "ask before deleting".
a "daily note template" setting under settings > editor > templates, stored per vault in <vault>/.enki/settings.json: the template decides the content and, when it declares title, the note's name too; it only applies on creation, never over the day's existing note.
two translated example templates (daily note and meeting) seeded the first time each vault is opened, never restored again if the user deletes them.
previous-day / next-day navigation in the editor header whenever the open note is a daily note, with the date spelled out to be read, a jump back to today and remappable ctrl+alt+left / ctrl+alt+right shortcuts; the target day's note is created from its template when it doesn't exist yet.
daily notes recognised by their file name in both directions (date to name and name to date), honouring the configured template's title while still recognising the yyyy-MM-dd notes that predate it, so a day never ends up with two daily notes.
a "merge with template" action in the editor header that appends only the sections the daily note is missing, at the end and without touching anything already written, listing what it will add in the tooltip beforehand and leaving a restore point in the version history.
a daily note consistency calendar in documents (full view, simplified view and command palette): ten calendar-aligned weeks, one cell per day, clicking a cell opens or creates that day's note, and a single descriptive figure of how many days have one.
a habits row inside that same calendar, read from the vault's real habits and with jumps to habits and statistics, with no streaks, points or goals of any kind.
local per-note version history, stored inside the vault itself (<vault>/.enki/history/, or .history/ alongside a session note, inheriting its encryption when the session is protected): automatic snapshots during autosave (throttled to one every 5 minutes, and only when the content actually changed), a "History" tab in the editor to diff line-by-line against the current version and restore, and an automatic safety snapshot before restoring or before a rename rewrites wikilinks in other notes.
add a "Tags" sidebar section to browse and search active tags from notes, kanban cards and polar tasks in one view, with per-module counts and multi-selection for merging.
allow tags to be renamed, merged and removed across all three modules without a separate store: preserve note front matter and version history, remove duplicates within each item, sync polar changes and refresh open note tabs.
extend the global vault graph with combined session and tag filters to explore accessible notes without creating another store or replacing the existing renderer.
add modes to discover orphan notes, cross-session connections and connected note groups, computed over the entire accessible vault to prevent misleading results when filtering.
detection of changes made to the vault outside enki (syncthing, dropbox, another editor): VaultChangeWatcher watches the folder with a FileSystemWatcher filtered to *.md, with per-path debouncing, filtering of temporary and sync-conflict files, and degradation to polling when the watcher fails or the file system does not support it.
a per-note on-disk stamp (NoteDiskStamp: timestamp, size and file hash) used to tell an own write from a foreign one by exact comparison rather than time windows, so autosave never produces a false conflict.
a pre-save check in VaultService.WriteContentChecked, independent of the watcher: if the file on disk is no longer the one that was read, the write is aborted without touching anything instead of overwriting the foreign change.
conflict policy in the editor: silent reload preserving caret and scroll position when there are no local changes, and a conflict dialog offering "keep mine", "load from disk" and "show differences" when there are; the discarded version is saved to the local history first under the "external conflict" trigger, so neither option destroys anything.
per-note autosave pause while the decision is still pending, with a header badge that reopens the dialog, and preservation of the unsaved text in the history if the tab is closed without deciding.
handling of external deletes and renames: a deleted note keeps its content on screen and offers to be saved as a new note; a renamed or moved one makes the tab follow its file to the new path.
settings > editor toggles "watch for external changes in the vault" and "reload automatically when there are no local changes", both on by default and translated into the seven supported languages; with watching off, the pre-save check still applies.
snooze reminders from the reminder inbox and from the notification centre, with two configurable quick durations (10 min and 1 h out of the box), "this evening", "tomorrow" and a custom value of up to seven days; a snoozed item leaves the overdue count, stays at the end of the list showing "snoozed until HH:MM" and its snooze counter, and fires again at the chosen time.
a dedicated snooze store in <vault>/.tasks/snoozed-reminders.json, the twin of the dismissal one: snoozing never rewrites a card's due date, a reminder's NotifyAtUtc, or a recurring reminder's series; it respects do-not-disturb by deferring the alert to the end of the window and keeps wall-clock time across daylight-saving transitions.
settings > notifications for the four quick snooze values (both durations and the "this evening" / "tomorrow" hours), with the menu labels following what is configured instead of fixed text.
export the calendar, the kanban board and a note to png and pdf, from each view's menu and from the command palette: the board comes out whole even when its columns do not fit on screen, the calendar comes out with the weekday header and without the navigation toolbar, and a long note is paginated into a4 pages.
an in-house pdf writer with no new dependencies (PdfImageWriter): one page per image, flate-compressed /DeviceRGB, and proportional page shrinking when the sheet exceeds the format's maximum side; writes are atomic, so a mid-way failure never leaves truncated files.
new-version notice: an optional check on startup (off by default, at most once every 24 h) and a manual one from settings > general, showing the version found, its release notes, "download" and "skip this version"; it only opens the release page in the browser, never downloads or runs anything, and with the setting off enki makes no network requests of its own.
store per-vault appearance, language, editor, calendar, statistics, navigation, shortcut and layout preferences in <vault>/.enki/settings.json, migrating the logo and custom themes from the global file when the first vault is chosen without overwriting anything already there, and keeping a settings.json.corrupt-* copy if the json arrives damaged.
color each calendar task by its source: red/amber/green for the base kanban columns (a color of its own for every new column) and a palette of blues, cyans, violets and magentas for polar lists, customisable from the layers panel with a color picker, hex input or a reset to automatic.
a settings > editor > code font setting to pick any font installed on the system for code blocks and inline code in notes and skills, the code file viewer and a skill's raw content, independent of the interface font and stored per vault, with jetbrains mono nf as the default.
a settings > appearance > sidebar logo setting to replace enki's icon with a custom image, in square or circular shape, with a preview, the original file kept without re-encoding and quality resampling when it is drawn.
archive completed kanban cards, one at a time or the whole column at once, to remove them from the board without deleting them: they still count in the calendar, statistics, global search and linked notes, with a dedicated archived-cards window to search, filter, sort, unarchive or delete.
organise the ai skills library into folders and subfolders inside <vault>/.enki/skills/, with two ways to browse it (a breadcrumb explorer with a card grid, or a hierarchical tree with its own search), global search that still covers the whole library, and import/export that preserves the folder structure.
a button to copy a code block's full content to the clipboard without the fence markers, with a visual confirmation after copying.
render a note's markdown tables in the editor (github flavored markdown syntax, per-column alignment and inline formatting inside cells) as well as in html export, with a table button in the formatting toolbar next to the existing /tabla command and tab/enter navigation between cells and rows.
insert images into a note by pasting from the clipboard, dragging files, or through the file dialog with multi-select; they are saved to <note>.attachments/, linking in place a file that already lives in the vault, encrypted when the note belongs to a protected session, and rendered in the editor at their natural size with , ![[file.png]] and explicit-size syntax.
a new settings > editor > editor view setting (full / simplified) with a minimal, obsidian-style layout: a sidebar with a folder/note tree for the active session, recursive search, a daily note shortcut and one-click new note/folder, with the same tabs and editor as always on the right.
interpret a fixed subset of html in the editor to align a note block (<div>/<p>/<center> with align or text-align) and apply inline formatting with <b>, <i>, <u>, <s>, <mark>, <code>, <span> and <br>, exported to html/pdf with the same sanitised containers.
a unified command palette (ctrl+shift+k) to search any app action by text (jump to a section, open settings/reminders/notifications, toggle the sidebar or theme, interface zoom, new/daily note, import notes, focus mode, new kanban column, open the vault folder, community ai skills or sync polar), rebuilt every time it opens to reflect the app's live state.
a focus mode in the editor (a header button and the ctrl+shift+enter shortcut) that hides the header, formatting toolbar, sidebar, tabs and app sidebar, leaving only the centred note body, shared across tabs and always off after restarting the app or switching vaults.
export a note to a standalone html file or to pdf from a full-screen print view with a real preview, an option to include tags, and printing or saving through the system dialog, reusing the editor's own markdown-to-html renderer.
local reminder recurrence independent of polar: a recurring reminder reschedules itself to its next occurrence instead of having to be recreated by hand.
an undo button when dismissing a reminder from the shell tray, with a few seconds' window before the dismissal becomes permanent.
dedicated controls in settings > general for the automatic backup's interval and retention, previously visible only as an on/off toggle.
a real application icon (.ico/.icns/png at several resolutions), with light and dark variants following the active theme, replacing the operating system's generic icon.
add README.en.md, an english version of the readme, since the app supports six interface languages.
warn the user when a local edit loses a synchronisation conflict (last-write-wins) against a newer remote version.
CHANGED
rebuild paragraph, list, task and quote justification to distribute word spacing before limited character tracking, preserve caret and selection geometry, respect final rows and code, and keep wrapping stable across redraws.
route formatting-toolbar buttons and shortcuts through the same editing operations so headings, lists, tasks, quotes and inline formatting toggle or replace existing markers instead of stacking syntax.
document editor behaviour and limits in .docs/project-info/editor-markdown.md and expand MarkdownEditingTests, MarkdownCalloutsTests, EditorEditingUiTests, MarkdownCodeHighlightUiTests and MarkdownJustificationUiTests with regressions for selections, undo, lf/crlf line endings, code fences, callouts, highlighting and text geometry.
establish .docs/project-info/ as the versioned project documentation path and clarify in README.md, README.en.md, AGENTS.md, and .gitignore that docs/ is not part of the checkout.
add .docs/project-info/qa-manual-release-candidate.md, the release-candidate manual qa checklist covering screen reader, wikilink/broken-link rendering, polar realtime reconnection and recurrence selector checks that automated tests don't cover.
add real per-platform packaging under enki/packaging/: a .deb and .tar.gz with .desktop/hicolor icon integration on Linux, an Inno Setup installer on Windows, and an ad-hoc signed .app/.dmg bundle on macOS, all built from the same self-contained publish and never carrying local.properties into the final package.
add .github/workflows/release.yml: pushing a v*.*.* tag builds, packages and publishes all five packages across the three platforms as a GitHub Release with no manual steps; also available as a workflow_dispatch to test packaging without cutting a real release.
add a lint-packaging job to .github/workflows/ci.yml that validates enki/packaging/ scripts on every push/pr (bash -n, shellcheck), the linux enki.desktop file and release.yml's yaml, to catch packaging errors before cutting a real release.
expand the graph panel with connected group selection, tags on hover, visible and global counts, empty states and filter reset; preserve available selections when reloading and the exploration mode when switching languages.
document daily notes in .docs/project-info/notas-diarias.md (two-way naming, day navigation, template merging and the consistency calendar), link it from AGENTS.md, plantillas-de-notas.md and the feature inventory, and add its section to the manual qa checklist.
cover daily notes with DailyNoteNamingTests, DailyNoteTemplateMergeTests, DailyNoteServiceTests and NotesViewModelDailyNoteTests in enki.Tests, plus DailyNoteUiTests in enki.UITests, which mounts the real xaml of the consistency calendar and the editor header.
cover image pasting end to end in enki.UITests/EditorViewImagesUiTests.cs against the TopLevel's real clipboard (saved attachment and inserted reference, several images, an image already living in the vault, selection replacement and text pasting without attachments), and document the new behaviour in .docs/project-info/imagenes-en-notas.md.
hide the kanban board's task-management button when polar isn't configured or no account is signed in, showing it again once an account is linked.
move kanban, polar tasks, reminders and their dismissals to .tasks/ inside the active vault and notifications to .enki/, copying data from earlier installs to the first vault once without overwriting anything.
thoroughly polish the files section in both views: breadcrumb and folder cards in the explorer, keyboard navigation in the tree, previous/next file and a metadata bar in the preview, stepped zoom and fit-to-width in the pdf viewer, downsized image thumbnails and a preview that never upscales small images, a code/text viewer that no longer draws the whole file at once, a fallback card with open-with for audio/video and other unsupported types, and disk-error notifications and confirmations when creating, renaming, moving or deleting folders and files.
rebuild the kanban board from the ground up: a live status line in the header instead of manual copy, quick-filter chips for high priority and overdue, a search field with tags on their own row, sorting through a dropdown, card actions revealed on hover or focus, columns sharing the available width equally (a fixed width from the sixth column on) and column names always shown uppercase throughout the app.
rebuild the trash with a single shared card size across all seven categories, a section header with an item count and a compact clear button, a total count next to "empty trash" and a dedicated box for each empty category.
search each note's full content instead of only its first 160 characters, across global search, the quick switcher and both note-grid search boxes, showing the text fragment where the match occurred and jumping to that line; global search and the quick switcher now also cover notes inside sessions.
lower a protected session's minimum password from 8 to 4 characters, with no composition rule at all, since enki is a single-user local app.
redesign the custom themes system: a color picker next to the hex field, theme duplication, a hex normaliser tolerant of variants without #, search highlighting and the editor's current-line background and session graph following the active theme, and the window no longer forcibly starting in dark mode.
turn the dashboard's custom layout into a grid editor of up to 12 rows and columns with drag, resize and keyboard-driven move, always starting from the active template's geometry and sanitising a saved layout when a new section or a smaller grid would leave it inconsistent.
document the supabase configuration used to link polar in a development environment via local.properties/enki/.env (both git-ignored), without the secret key ever reaching the application.
FIXED
preserve selected text, caret position and lf/crlf line endings while inserting code blocks or editing lines, and group each compound transformation and list renumbering into one undo step.
prevent indentation, renumbering, smart home and backspace from treating examples inside a code fence as lists, and allow three consecutive backticks to be typed without automatic pairing interrupting the opening fence.
interpret an undefined textmate font style correctly instead of applying italic, bold and underline together, and enforce the tokenisation budget across the complete block instead of resetting it for every line.
turn a url pasted over selected text into a markdown link while retaining normal paste behaviour when the clipboard does not contain a valid url.
fix documentation links and icons in both README files, along with references and relative links in AGENTS.md and .docs/project-info/, so they point to existing files.
show the graph when the vault contains notes without any sessions and avoid temporarily hiding it during a reload.
clear the pending endpoint of a manual link when filters change to prevent accidental connections to hidden notes.
prevent graph counts from overlapping controls in narrow windows and keep the reset button accessible while scrolling the filter panel.
replace the selected text when pasting an image into the editor, like any other paste does, as a single operation that one ctrl+z undoes.
discard a clipboard image that yields no bytes, with a notification, instead of saving an empty attachment and inserting a  pointing at a broken image.
export a note containing a link to a missing image instead of failing outright: NoteExportRenderer's symbolic-link check threw while reading the attributes of a path that does not exist, so a single  brought down html and pdf export for the whole note.
fix duplicate theme export, which did not reload after being saved and could not be exported again until the app restarted.
fix the calendar's quick-creation date picker, which failed to draw the days of the month; while at it, give its footer buttons proper hierarchy, allow creating with enter and closing step by step with escape, and stop the view behind the popover from reacting to its shortcuts.
fix aliasing in the files section's thumbnails, large preview and pdf page rail, which downscaled images without filtering the discarded pixels.
fix an unexpected app crash when deleting a session (or its folder disappearing another way) while the session graph's background walk was visiting it.
apply the chosen interface font to subtitles, relative dates, spaced-out headers, counters, chart axes, calendar numbers, keyboard shortcuts, vault paths and placeholder text fields, which previously stayed on the framework's default font.
fix four silent bugs in password-protected sessions: moving a note or attachment across the encryption boundary without (de)encrypting its bytes, a corrupt .session.json causing the next note saved to be written unencrypted, sessionlockedexception thrown from inside a linq select instead of excluding a locked session's notes, and a deleted session leaving its unlocked key hanging for a new folder reusing the same name.
fix three bugs in the custom dashboard settings screen: the preview not reading the vault's active template on open, "reset" not refreshing the page after reverting to the classic layout, and custom mode leaving half the page empty where the template preview used to be.
automatically reconnect polarrealtimeservice after a socket drop by reusing the sync timer's backoff, tell a completed sync apart from one skipped because another was already running in all three "sync now" buttons, and retry the sync-failure notice hourly while the problem persists.
purge orphaned reminder dismissals when their card is permanently deleted, dispose of the session graph's webview on leaving the tab, and cancel an in-flight global search when the user keeps typing so stale results can't overwrite newer ones.
SECURITY
protect polar session tokens with dpapi on windows, secret service through libsecret on linux, and keychain on macos, outside settings.json.
migrate legacy tokens only after secure storage succeeds and report failures without saving new sessions in plain text.
keep tokens redacted in settings exports and backups of global and vault settings.json, including legacy files.
write every temporary file the app creates into a per-user directory with mode 0700, checked on each use (PrivateTempFile), instead of a fixed name in the shared root of the system temp directory, where another local account could claim that name with a symlink and make the app truncate someone else's file.
create the decrypted temporary copy of VaultService.ResolveReadablePath with mode 0600 in the very call that creates it (FileMode.CreateNew plus FileStreamOptions.UnixCreateMode) and delete it if the write fails halfway, closing the window in which it existed with the inherited umask; the startup and shutdown sweep now also cleans up temporary files left loose in the temp root by earlier versions.
validate a protected session's encryption manifest before deriving anything in SessionEncryptionService: decodable base64, coherent salt and wrapped key lengths, Iterations within range and a known FormatVersion.
tell "wrong password" apart from "unreadable manifest" with SessionManifestCorruptException and a message of its own in the unlock dialog, so a damaged session is not presented as a typing mistake.
restrict the editor's remote images to public addresses by checking the ip actually connected to in SocketsHttpHandler.ConnectCallback (RemoteImagePolicy), covering loopback, private ranges, link-local, cgnat, multicast and reserved ranges in ipv4 and ipv6, including ipv4 addresses disguised inside an ipv6 one.
limit a remote image to three redirects, validate every hop like the first one and refuse a downgrade from https to http.
cut a remote image download while streaming once it reaches MaxRemoteBytes, instead of pulling the whole body into memory before measuring it, and bound the whole download with a single time budget.
state in the protected-session dialog that encryption covers the content of the notes and their attachments, and that file names, structure and dates stay readable on disk.
treat a protected session's damaged encryption manifest as locked rather than as plain text, so no later write saves unencrypted content until the manifest is repaired.
correctly re-encrypt or decrypt content when moving a note or attachment across a protected session's boundary (including a direct move between two sessions), writing the destination before deleting the source so a mid-way failure leaves a duplicate rather than a gap.