Appearance
Notes
Freev1.2.0Markdown notes, organized into collections
Overview
Notes is a Notion-style Markdown notebook. You organize your writing into collections (think of a collection as a notebook, e.g. one per book or topic), and each collection holds one or more Markdown pages. A sidebar tree lets you expand a collection to reveal its pages, and an editor with an optional live preview sits alongside. It is part of the kimtos new-tab app suite.
Everything is fully on-device. There is no backend, no account, and no network: every collection and page lives in your browser's IndexedDB and never leaves the machine.
Highlights
- Collections & pages — a sidebar tree of collections, each expanding to its pages. Create, rename, move, and delete from right-click menus.
- Markdown editor — write GitHub-flavored Markdown with headings, lists, tables, links, and fenced code blocks with syntax highlighting.
- Edit / Split / Preview — write in source, see a live preview, or split the pane and do both. Edits autosave.
- Find & replace —
⌘/Ctrl+Fopens a find bar; every match is highlighted, with match-case, previous/next, replace, and replace-all. - Internal links — link from one page to another with a plain Markdown link, within a collection (
this:page) or across collections (collection:page). - Export as Book — read a whole collection as one continuous document, with internal links navigating in the reading view.
- Export & download — download a page as
.md, a collection as a.zip, or export either to PDF through your browser's own print dialog. - Floating window — pop the app out into a small, always-on-top window so your notes stay visible while you browse other tabs.
- Home card — an optional card on the KimtOS home screen listing your collections; click one to open it, or start a new collection. Turn it off in Settings ▸ Preferences.
- Batch delete with undo — multi-select collections and pages, delete in one step, and undo for 30 seconds.
Privacy model
Notes writes only to local browser storage:
- Collections (name, last-updated time) are records in IndexedDB.
- Pages (title, Markdown content, last-updated time) are records in IndexedDB, each linked to its collection.
- Nothing is uploaded, and there are no analytics or third-party calls.
Markdown is rendered client-side purely for an instant preview and for export — all of your data and logic stays local. Because each page is plain Markdown text, your work is portable: it travels with the browser profile and is included in the suite's local backup.
Getting Started
Open Notes from the dock. On first run, if you have no collections yet, it offers New collection to get started. After that, your most recently worked-on collection opens automatically, with its first page in the editor.
Collections and pages
The left sidebar is a tree: collections at the top level, their pages nested underneath.
- New collection — the + button in the sidebar header.
- New page — expand a collection and click New page at the bottom of its page list, or pick New page from the right-click menu of any collection or page.
- Expand / collapse — click a collection to show or hide its pages.
- Open a page — click it to load it into the editor.
- Rename, move, delete — right-click a collection or page for its menu.
- Move a page — drag it onto another collection, or use Move to collection… in its right-click menu.
- Resize the sidebar — drag the divider; the ☰ button toggles it.
Every edit autosaves a moment after you stop typing. Deleting a page or a whole collection can be undone for 30 seconds via the toast that appears.
The Markdown editor
Write in GitHub-flavored Markdown: headings, lists, tables, links, and fenced code blocks (syntax-highlighted for many languages). Pages are capped at 50,000 characters; the counter in the toolbar shows how close you are.
Switch panes with the toolbar tabs:
- Edit — the source textarea only (the default).
- Split — source and live preview side by side; drag the divider to resize the two panes.
- Preview — the rendered result only.
When the window is too narrow for two panes, Split falls back to Edit automatically until there is room again. A narrow window also has no room for the three tabs, so they give way to a single toggle next to the search button that flips between writing and preview.
Lists and checklists
Lists continue themselves. Press Enter at the end of a list item and the next line starts with the same marker, indented to match:
| You are on | Enter gives you |
|---|---|
- [ ] item | - [ ] — a new box, always unticked |
- item | - |
* item | * (the marker you used is kept) |
1. item | 2. (the number goes up) |
A continued checkbox is deliberately unticked, even when you continued a ticked one — the new task is not one you have done.
To end a list, press Enter on an item you have not typed anything into. The marker is removed and you are left on a blank line. Shift + Enter skips all of this and gives you a plain newline wherever you are.
Undo treats a continuation as one step, so ⌘/Ctrl + Z takes back the whole marker rather than a character at a time.
Ticking things off
Checkboxes in the preview are real checkboxes — click one and it ticks. What you are actually clicking is the note itself: the click rewrites [ ] as [x] in your Markdown, so the change is saved with the page and comes out in every export, the book view and the print. In Split view you can watch the source change as you click.
This is specific to Notes. The assistant's replies and file previews render the same Markdown, but there is no document behind them to write to, so their checkboxes stay decorative.
Find & replace
Press ⌘/Ctrl+F (or the search icon) to open the find bar. Every match is highlighted in the source.
- Enter / Shift+Enter — jump to the next / previous match.
- Aa — toggle match case.
- Replace — change the current match; All — replace every match in one undoable step.
- Esc — close the bar.
Replacements join the editor's native undo history, so ⌘/Ctrl+Z undoes them just like typing.
Internal links
Link from one page to another using an ordinary Markdown link whose target is a page reference instead of a URL:
- Same collection:
[text](this:page_name) - Another collection:
[text](collection_name:page_name)
Names are normalized — spaces and dashes become _ and case is ignored — so a page titled "Page Title" is referenced as page_title. In the editor's preview, clicking an internal link opens the target page; in Book view it navigates within the reading view.
Export as Book
From a collection's right-click menu, choose Export as Book to read the whole collection as one continuous, rendered document (pages in oldest-first order). Internal links navigate within the book, and the ← button steps back through where you have been; the ⬇ icon exports the book to PDF.
Export and download
From the right-click menus (or the Book view):
- Download a page as a
.mdMarkdown file. - Download a collection as a
.zipcontaining one.mdfile per page, inside a folder named after the collection. - Export as PDF — for a single page or a whole collection. This opens your browser's print dialog; choose Save as PDF. Each page in a collection export starts on its own sheet. Everything stays on your device.
The floating window
If your browser supports it, a pop out button appears in the title bar (you can turn this off in settings). It moves the app into a small, always-on-top floating window — the same browser feature Google Meet uses — so your notes stay visible while you work in other tabs. Keep the original tab open; the floating window lives only as long as that tab does.
Deleting several at once
Click Select in the sidebar to enter multi-select mode. Tick pages, or pick whole collections (which selects all of their pages too), then Delete (N) removes them in one step. You can also drag across collection rows to select a range. A single confirm covers the batch, and one Undo restores everything.
Architecture
Notes follows the suite convention: all data logic lives behind the local API layer, and the app itself is UI plus client-side Markdown rendering. The code lives in extension/src/apps/notes/.
Modules
| File | Role |
|---|---|
index.ts | The app descriptor and UI — the collections/pages sidebar tree, the Markdown editor (Edit/Split/Preview), find & replace, internal links, Export as Book, PDF/.md/.zip export, and the floating-window control. |
notes.local.ts | The data layer — collections and pages CRUD over IndexedDB, registered on the local API router. Includes a one-time migration of legacy flat notes into a "My Notes" collection. |
bookSection.ts | Builds one page of the Book view / PDF / .md export. In the book and the PDF a page's name is never Markdown — a heading node, or escaped HTML — so * and # in it survive verbatim. In a .md file the name is a real heading; only its whitespace is collapsed, so it cannot split across lines. |
previewDiff.ts | The pure half of the incremental live preview — diffs the previous and next lists of top-level Markdown blocks so a one-paragraph edit re-renders one block instead of the whole page. |
listContinuation.ts | The pure half of Enter-continues-a-list — given the source and the caret, it returns the range to replace and the text to put there (a new marker, or nothing when an empty item ends the list). No DOM, so every rule is a unit test. |
taskToggle.ts | Maps the checkbox a user clicked in the preview back to the exact [ ] / [x] in the source. Uses marked's lexer to skip code blocks rather than a line regex, because a - [ ] inside a fenced block renders no checkbox and must not be counted. Nested list raw comes back de-indented, so offsets are found by scanning source lines rather than by walking child tokens. |
print.ts | The PDF export path — renders the already-rendered Markdown HTML to PDF through the browser's own print-to-PDF (offscreen iframe → print dialog → "Save as PDF"), with a light syntax theme injected into the print document. |
marked + marked-highlight + highlight.js | Client-side Markdown parsing and code syntax highlighting, used for the live preview, Book view, and export. |
lib/pip.ts | The Document Picture-in-Picture helper that pops the UI out into an always-on-top floating window. |
Data flow
The UI never touches storage directly: it calls getApi / jsonApi (the suite's local router), which dispatches to notes.local.ts. Markdown rendering is purely a view concern — marked parses the source for the preview, the Book view, and PDF export, but the source of truth is always the plain Markdown text in storage.
Data model
Two record types, linked by id:
- Collection —
{ id, name, updated }. Itsupdatedtime is bumped whenever any of its pages changes, so the "recent" ordering reflects real activity. - Page —
{ id, collectionId, title, content, updated }, wherecontentis the Markdown text (capped at 50,000 characters).
Listing a collection returns a live page count; deleting a collection cascades to remove all of its pages. Moving a page rewrites its collectionId and bumps both the old and new collections' timestamps.
Persistence
Saves are debounced (~600 ms after the last keystroke) and flushed immediately before switching pages, so a fast switch never drops an edit. Deletes (and moves) are reversible for 30 seconds through an in-app undo toast that re-creates the removed records. Reopening the app restores the most recently edited collection and opens its first page straight from storage.
Reference
A quick reference for shortcuts, settings, internal links, and storage.
Keyboard shortcuts
| Keys | Action |
|---|---|
⌘/Ctrl + F | Open find & replace |
⌘/Ctrl + Z | Undo (including Replace) |
⌘ + Shift + Z / Ctrl + Y | Redo |
Enter (in the editor, on a list) | Continue the list |
Enter (on an empty list item) | End the list |
Shift + Enter (in the editor) | A plain newline, never a marker |
Enter (in the find bar) | Next match |
Shift + Enter (in the find bar) | Previous match |
Esc | Close the find bar (or a dialog) |
The Aa button in the find bar toggles match-case; Replace changes the current match and All replaces every match in one undoable step.
List continuation
| Current line | Enter inserts |
|---|---|
- [ ] item | - [ ] (a continued box is unticked) |
- item | - |
* item | * |
+ item | + |
1. item | 2. |
3) item | 4) |
Leading indentation is carried across, so a nested list stays nested. An item with nothing in it ends the list instead. Anything that is not a list item leaves Enter alone.
Task checkboxes
| Where | Behaviour |
|---|---|
| Notes preview (Split/Preview) | Clickable; ticking rewrites [ ] / [x] in the page source |
| Book view, print, exports | Rendered as-is, not clickable |
| Other apps' Markdown previews | Not clickable — no source document behind them |
Settings
Open the app's settings to configure the floating window. These are per-app.
| Setting | Key | Options | Default |
|---|---|---|---|
| Floating window | popout | On, Off | On |
| Floating window size | pipSize | Compact, Standard, Large | Standard |
Floating window shows the "pop out" button in the title bar (it needs a browser that supports the feature; keep the original tab open). Floating window size sets how big the window first opens — you can still drag its edges to resize afterwards:
| Size | Opens at |
|---|---|
| Compact | 380 × 520 |
| Standard | 560 × 720 |
| Large | 880 × 940 |
Internal-link syntax
Write an internal link as a normal Markdown link whose target is a page reference. Names are normalized: spaces and dashes become _ and case is ignored (so "Page Title" → page_title).
| Syntax | Links to |
|---|---|
[text](this:page_name) | A page in the same collection |
[text](collection_name:page_name) | A page in another collection |
Anything that looks like a real URL (e.g. https://…, //…, #…, /…) is left as an external link and opens in a new tab; schemeless links get https:// added automatically.
Right-click actions
| Item | Actions |
|---|---|
| Collection | New page, Export as Book, Rename, Download (.zip), Export as PDF, Delete |
| Page | New page, Rename, Download (.md), Export as PDF, Move to collection…, Delete |
Data & storage
| Item | Where it lives |
|---|---|
| Collections (name, last-updated) | IndexedDB records |
| Pages (title, Markdown content, last-updated) | IndexedDB records, linked to a collection |
| Backup | Included in the suite's local Export / Import |
Pages are capped at 50,000 characters each. Deleting a collection also deletes its pages. Deletes and moves can be undone for 30 seconds. Nothing is ever uploaded.
Changelog
1.2.0 — 2026-08-13
- Enter now continues a Markdown list: a task item gives you a new unchecked box, a bullet gives you the same bullet, a numbered item gives you the next number, and the indentation comes with it. Enter on an item you have not typed into ends the list instead. Shift+Enter always gives a plain newline.
- Checkboxes in the preview can be ticked. Clicking one edits the note's own text, so the change is saved, exported and printed like anything else you typed.
1.1.0 — 2026-07-27
- Give the extension a session model, and run the apps in one tab
- Scroll a wide Markdown table inside its own block
- Unblock every open PR — admin path filter, the Semgrep rule, and a real audit gate
- Tell the browser which palette to draw its own controls in
- Give Notes' book view a measure, wrap long text, and stop parsing page names as Markdown
1.0.3 — 2026-07-25
- Export as Book now reads like a book: lines are held to a readable width instead of running the full window.
- Long unbroken text wraps in the book and the preview, the way it already did while you were writing it.
- A page name is shown exactly as you typed it in the book and in the PDF: one containing `*` or `#` is no longer reinterpreted as Markdown there.
- A page name spanning more than one line no longer splits the heading in an exported `.md` or `.zip` file. In those files the name is still a real Markdown heading, so `*` and `#` in it keep their Markdown meaning.