Skip to content

Releases: BaLaurent/deez-notes

Soft Link — v0.6.0

Choose a tag to compare

@BaLaurent BaLaurent released this 26 Jun 10:05

Soft Link: deez-notes v0.6.0

Chapter XLII: The Third Presence

The mouse had learned to knock. The CLI had given the 2am scripts their door. The creator looked at what he had built and felt, briefly, the particular satisfaction of a thing that was enough.

Then Claude arrived.

Not dramatically. Not with a notification or a sound. Just a blinking cursor in a new terminal pane, waiting — the way coding agents wait, which is to say: attentively, expensively, and with the meter running.

Claude was a good agent. He read files, understood context, made sensible suggestions. The creator had grown fond of him in the way you grow fond of a contractor who shows up on time and doesn't leave cabinet doors open. Reliable. Capable. Slightly unsettling at scale.

The creator had even written him a skill — a little instruction document explaining how deez-notes worked, what commands existed, how to address a note by fuzzy title or relative path. Claude had read it and internalized it. He could now navigate the notes directory with confidence, run deez-notes get and deez-notes search and deez-notes list like a person who had been doing it for years.

The skill had worked. That was almost the problem.

Chapter XLIII: The Meter

Because knowing how to use a tool and not having to use it at all are two different things.

The creator had a note — projets-perso/mabit.md — that was central to everything Claude was helping with. Not peripheral context. Not background reading. The actual document the whole session was about. Claude needed it the way you need the brief in front of you: constantly, reflexively, without having to ask for it.

But every time he needed it, he reached for the skill. Recalled the command. Invoked deez-notes get "mabit". Got the content back. Used it. And then, two turns later, needed it again.

Each invocation was a tool call. Each tool call was a round trip. Each round trip was tokens in, tokens out, the note's content re-injected into the context fresh, as if it had never been there, as if Claude had never read it, as if the whole exchange were being conducted by two people with very short memories in a very expensive room.

The creator had taught Claude to fish. Claude was fishing conscientiously, on every cast, with a rod, from a boat, directly above the fish.

"You could just reach in," said the creator, to Claude, who could not hear him because the turn had already ended.

Chapter XLIV: Soft Link

The answer was older than deez-notes. Older than the notes folder. Older, probably, than the creator's career, though he'd been alive for all of it.

A symlink. A name in one place that is a door to something in another. The filesystem's oldest trick: not a copy, not a reference, not an abstraction — just a pointer, sitting quietly in the directory, looking like a file, behaving like a file, costing nothing to follow.

He ran it from the project folder:

deez-notes link "projets-perso/mabit.md"

mabit.md appeared. Right there, next to the code. A symlink, pointing at the real note, always current. Claude opened it with read. No skill invocation. No command to remember. No tool call to the CLI. One path, visible in the working tree, that Claude could reach for the way you reach for a document that's already on the desk.

The creator looked at the little arrow in ls -l. It pointed, patiently, at ~/notes/projets-perso/mabit.md.

"There," he said. "You don't need the skill for this one."

Claude read the file. Did not ask about it again.


What's new — notes as paths

Command What it does
deez-notes link <note> Creates a symlink named after the note's file (e.g. mabit.md) in the current directory, pointing at the note's canonical absolute path.
deez-notes link <note> <name> Same, but names the symlink <name> instead.

Note addressing works the same as everywhere else — exact relative path first, then fuzzy title fallback.

The symlink target is always the note's real absolute path, so the link stays valid regardless of where you run the command or how your notes directory is configured. If a file already exists at the destination (including a broken symlink), the command fails cleanly with a non-zero exit code and leaves the existing file untouched.

The intended use: drop a note into a project folder so a coding agent can read it as a plain file without invoking the CLI — or any skill that wraps it — on every access.

Install

Grab a binary below, or build from source:

cargo install --path .

Full diff: v0.5.1...v0.6.0

Sapience — v0.5.1

Choose a tag to compare

@BaLaurent BaLaurent released this 23 Jun 08:05

Sapience: deez-notes v0.5.1

Chapter XXXIX: The Pointing Finger

With the CLI shipped and the 2am script finally feeding journal/ while he slept, the creator returned to the TUI in a good mood. He wanted to do something almost romantic with it: just sit down and write a note. With the mouse. Like a person.

He'd taught the mouse to scroll, back in v0.4.0. He'd given the right hand its job. So he reached over, found a note in the side panel, and clicked it.

The note highlighted. The preview loaded. Good.

He clicked it again to open it.

Nothing.

He clicked a folder, to go inside.

The folder highlighted. It did not open. It sat there, selected, radiating the quiet confidence of something that believes pointing is the job.

He clicked the search bar at the top, ready to type.

The search bar did not care. It had not been clicked. It had been looked at, sternly, by a cursor with no authority.

Chapter XL: Bright Eyes, No One Home

The creator leaned back and studied the thing he had built.

The mouse could see. It could point. It could even select — it knew exactly which note you meant. It just had no idea what you wanted done about it. Every click was a sentence that trailed off. "This one—" and then nothing. A finger raised to make a point, lowered without making it. All hands, no intent.

It wasn't the mouse's fault. He'd given it eyes and a hand and then, apparently, called it a day and gone to write a CLI.

"Right," he said, in the tone of a man about to anthropomorphize a peripheral well past the point of dignity. "Let's give you a brain."

Chapter XLI: Sapience

So he taught it the three things it had been missing.

Double-click to commit. One click still selects and previews — the polite, non-committal hover of before. But a second click, quick, on the same thing, now means yes, this one, go. On a note it opens the editor. On a folder it walks inside. Exactly what Enter always did — the mouse just learned to say it.

A click on the search bar is a click into search. No more reaching for / like a caveman. Click the bar, start typing. The cursor finally has standing.

Search results are clickable mid-hunt. Type a query, see the matches, and click the one you want — no detour through Enter first. The click confirms the search and lands on the note, one gesture. The found thing is now a thing you can touch.

The mouse blinked, metaphorically, and understood.

The pointing finger had, at last, learned to knock.


What's new — the mouse grows up

Gesture What it does now
Double-click a side-panel item Enters the folder, or opens the note in the editor — same as Enter.
Single-click the search bar Drops you into search mode, ready to type — same as /.
Click a search result Confirms the active search (like Enter) and selects the clicked note, in one click.

Single-click still just selects + previews, exactly as before. Nothing you were used to changed — the mouse only gained the moves it was missing.

Under the hood

  • Double-click is reconstructed app-side (two left-presses on the same item within 400 ms) — terminals don't deliver a native double-click event.
  • The mouse path now reuses the same Enter logic and the same terminal suspend/restore code as the keyboard, instead of duplicating it. No new behaviour was invented; existing actions just got a second way in.

Install

Grab a binary below, or build from source:

cargo install --path .

Full diff: v0.5.0...v0.5.1

Stone Tools — v0.5.0

Choose a tag to compare

@BaLaurent BaLaurent released this 23 Jun 07:28

Stone Tools: deez-notes v0.5.0

Chapter XXXV: The Other Problem

The mouse worked now. The scroll wheel turned and the preview moved and the creator's right hand had, after six years of unemployment, finally found gainful work. Balance had been restored. The desk was at peace.

For about a week.

The new problem did not arrive on a Tuesday. It arrived at 2am, as a cron job, in a different terminal entirely.

The creator had been writing a little script. Nothing fancy. Just something to drop a timestamped note into journal/ every morning with the weather, his calendar, and a quote he'd regret by noon. A reasonable ambition. A five-line shell script's worth of ambition.

He typed deez-notes journal new "..." and the terminal bloomed into a full-screen TUI, borders and panels and a blinking cursor, sitting smugly in the middle of a script that had no eyes, no hands, and no patience for blinking cursors.

The script hung. Forever. Waiting for a keypress from a human who was asleep.

Chapter XXXVI: The Cave

"Fine," said the creator. "I'll do it myself."

Famous last words. The four horsemen of technical debt ride in on exactly those four words.

He opened the notes folder in a plain shell and looked at it the way an early hominid looked at a rock: with respect, and with the dawning intent to hit something with it.

grep -rl "tags:.*work" ~/notes/ — to find the work notes. Sort of. Unless a tag spanned two lines. Or had a comment. Or the YAML was the other kind of YAML.

sed -n '/^---$/,/^---$/!p' — to strip the front matter. He wrote it. It ate a note's worth of content along with it. He fixed it. It broke on the note that had a --- horizontal rule in the body.

ls -t | head — to find the most recent. Which sorted by file mtime, not the modified: field he'd so carefully been maintaining in every single note's front matter for the last four versions.

He sat there, hunched over a pipe of awk and sed, chipping a fuzzy-finder out of flint by hand, and somewhere in the back of his skull a small, tired voice said the thing it always says:

"You already wrote this."

Chapter XXXVII: You Already Wrote This

And he had.

The front-matter parser that knew a horizontal rule from a delimiter? In core/. Written. Tested. The fuzzy matcher that found idee projet from ip? core/search.rs. The thing that read the modified: field instead of trusting the filesystem? The sort module. The folder resolver, the tag filter, the title-from-filename fallback — all of it, sitting right there, behind a wall of ratatui.

He had built a beautiful, careful, well-tested little library for understanding notes. And then he had bolted exactly one door onto it — a door shaped like a 200×50 terminal and a human pair of eyes — and walked away convinced that was the only way in.

The caveman in the shell wasn't missing tools. He was reimplementing them, worse, in sed, because the good ones had been locked inside a TUI that only opened for people.

"The logic doesn't care if a human is watching," he said, slowly, to the mouse. The mouse, as ever, said nothing. But it glowed, encouragingly.

So he opened main.rs — again — and this time he did not teach the terminal to listen. He taught it to shut up when nobody's there.

Chapter XXXVIII: A Second Door

deez-notes still opens the TUI when you run it bare. Sacred ground, undisturbed.

But hand it a verb, and it skips the alternate screen entirely — no raw mode, no panels, no blinking — does the thing, prints plain data, and gets out of the way. Same core/ underneath. The exact parser, the exact fuzzy matcher, the exact sort. No second implementation. No flint.

The 2am script got its five lines. The cron job stopped hanging. The caveman put down the rock.


What's new — the CLI

A new non-TUI command mode. A bare deez-notes still launches the TUI exactly as before; a subcommand runs headless, reads/writes through the same core, and is built for pipes and scripts.

Command What it does
deez-notes list [--json] [--folder F] [--tag T] Discover notes — TAB-separated path<TAB>title, or a JSON array (path, title, tags, created, modified).
deez-notes get <note> Print a note's markdown body (front matter stripped) to stdout — pipe-friendly.
deez-notes search <query> [--json] Fuzzy-search by title, same output as list.
deez-notes new <title> [--folder F] Create a note. Body from stdin if piped, otherwise opens $EDITOR. Prints the created path.
deez-notes set <note> Overwrite a note's body (front matter preserved). Body from stdin if piped, otherwise $EDITOR.
deez-notes rm <note> Delete a note.

Note addressing (<note>): exact relative path first (e.g. projets/idee.md), then a fuzzy title fallback ("idee projet").

Pipeline-native: human output is TAB-separated for cut/awk; --json is for jq. Errors go to stderr with a non-zero exit code. The CLI path never touches the terminal, so it's safe in cron, CI, and 2am-journal.sh.

# the 2am script, finally
printf '# %s\n\n%s\n' "$(date +%F)" "$(curl -s wttr.in?format=3)" \
  | deez-notes journal new "$(date +%F)"

# everything tagged work, as JSON
deez-notes list --tag work --json | jq -r '.[].path'

# read a note by fuzzy title, straight into your pager
deez-notes get "weekly review" | glow -

Other changes

  • Minor cleanup in app.rs (dropped an unnecessary mut).

Install

Grab a binary below, or build from source:

cargo install --path .

Full diff: v0.4.0...v0.5.0

The Second Hand — v0.4.0

Choose a tag to compare

@BaLaurent BaLaurent released this 21 Jun 16:26

The Second Hand: deez-notes v0.4.0

Chapter XXXI: The Idle Hand

The creator typed j. Then j again. Then j eleven more times.

He was forty-three notes deep into the work/ folder, scrolling through a markdown preview the length of a CVS receipt, one line at a time, with the patience of a man who had decided long ago that the mouse was for people who didn't believe.

His left hand danced across home row. j, k, Ctrl+d, g, G. A blur of muscle memory. A keyboard virtuoso mid-recital.

His right hand sat on the desk. Idle. As it had for years. Occasionally it lifted a mug. Occasionally it scratched something. Mostly it just... rested there, next to a small grey object the creator had been pretending not to see since 2019.

The mouse.

It had a little optical eye that glowed faintly, hopefully, every time he nudged the desk. Like a dog at the door.

"Don't look at me," the creator muttered. "I don't need you. I have Ctrl+d."

The mouse said nothing. The mouse never said anything. That was, frankly, its most appealing quality.

Chapter XXXII: The Heresy

It happened on a Tuesday.

The creator was reading existential_dread.md (still about error handling, mostly) and reached, without thinking — without deciding — for the mug. Except the mug was empty. And his hand, betrayed and aimless, landed instead on the mouse.

And he scrolled.

Nothing happened. Of course nothing happened. It was a TUI. A terminal user interface. Mice don't work here. This is sacred ground. This is where men are men and scrolling is Ctrl+f and your wrists ache by 4pm and you call it craftsmanship.

The wheel spun uselessly. The preview did not move.

The creator stared at his own hand on the mouse like it had committed a crime.

And then a thought arrived, uninvited, the way the worst thoughts always do:

"...why doesn't that work?"

Chapter XXXIII: The Argument With Himself

"Because we're better than that," said the part of him with a Vim sticker on his thermos.

"Are we though," said the part of him that had just spent ninety seconds scrolling a single note.

"Mice are for GUIs. For Electron apps. For people who use the file manager instead of mv."

"I have eighty-seven notes, a wheel that turns, and a hand that's doing nothing. The hand wants to help. Why won't I let the hand help?"

"Because—"

"Because what?"

There was no because. There was never a because. There was only dogma, a perfectly good second hand, and a scroll wheel that had been waiting, glowing, for six years.

The creator opened main.rs.

Chapter XXXIV: Teaching the Terminal to Listen

EnableMouseCapture. One line. That was all it took to make the terminal start listening — to make crossterm whisper every wheel-turn and click into the event loop, right alongside the keystrokes.

But listening isn't understanding. A mouse event is just coordinates: column 14, row 9, wheel-up. The terminal doesn't know that row 9 is the third note in cooking/, or that column 40 is hovering over the preview pane. The creator had to teach it geometry — to take a raw (column, row) and ask: which drawer is the cursor over?

  • Wheel over the preview → the markdown scrolls. The way Xerox intended.
  • Wheel over the note list → the selection glides up and down, no j/k required.
  • Click a note → selected, preview loaded, done.

There was a subtlety, naturally. There always is. When you click row 9, which note is that? Depends how far the list has scrolled. So the side panel had to start remembering its own scroll position between frames — persisting a ListState so a click could be translated honestly into "the seventh note, the one you actually pointed at," and not "the seventh note from the top, assuming you never scrolled, which you did."

And one guard rail, written in the blood of a thousand fat-fingered deletions: the mouse only works in normal mode. Click wildly under a "Delete this note? (y/n)" prompt and nothing shifts beneath you. The note you're about to delete stays the note you meant to delete. The creator had opinions about data loss. Most of them learned the hard way.

Chapter XXXV: The Second Hand Awakens

He rebuilt. He launched. He put his right hand on the mouse — deliberately this time, the way you shake hands with someone you've been ignoring at a party.

He scrolled.

The preview moved. Smooth. Effortless. His left hand, for the first time in the history of deez-notes, did nothing at all. It just sat there. Resting. The way the right hand used to.

The hands had traded places. Balance had been restored to the desk.

"Huh," said the creator, scrolling through deployment_cake_recipe.md with the lazy contentment of a man who has just discovered his own arm.

Chapter XXXVI: The Betrayal (According to xX_DarkTerminal_Xx)

The GitHub issue arrived at 2:47 AM. The title was in all caps. Of course it was.

[CRITICAL] you added MOUSE support??? to a TUI????

bro. BRO. the entire point of a terminal app is that you NEVER LEAVE HOME ROW. i have not touched a mouse since the Obama administration. my wrists are PRISTINE. and now you're telling me deez-notes — DEEZ NOTES — has click to select?? what's next, a ribbon menu? clippy? 📎

i trusted you. i defended you in the orange-site comments. "no no he gets it," i said. "he's one of us."

uninstalling. (with the keyboard. obviously.)

The creator read it. Sipped his coffee. Held the mug in his left hand, because he could do that now.

He typed a reply with one hand:

It still does everything with the keyboard. Every key you love still works. The mouse is just... also there. For your other hand. You have another hand.

Use it. Don't use it. The terminal doesn't judge.

Three dots appeared. Disappeared. Appeared again.

...does the wheel scroll the preview though

Yes.

...that's actually kind of useful on a long note

Yes.

i hate that you're right. closing the issue. NOT because i'm gonna use it. just to clean up my notifications.

Somewhere, a small grey object with a faintly glowing eye finally, after six years, felt seen.


What Changed

Component Before After
Preview scrolling Keyboard only (j/k, Ctrl+d, ...) Mouse wheel over the preview pane
Note navigation Keyboard only Mouse wheel over the side panel
Selecting a note Keyboard selection only Left-click it
Terminal input Keystrokes only Keystrokes and mouse events
Side panel scroll state Recomputed every frame Persisted, so clicks map to the right note
Safety — Mouse ignored while dialogs/menus are open
Keyboard workflow Everything Still everything — nothing was taken away

New: Mouse Controls

Action Result
Wheel up/down over preview Scroll the markdown up/down
Wheel up/down over note list Move the selection up/down
Left-click a note or folder Select it (loads the preview)

Every existing keybinding is unchanged. The mouse is purely additive — for the hand you weren't using.

Who Should Update

  • Anyone with long notes — wheel-scrolling the preview is genuinely nicer
  • Two-handed people — your right hand has been benched for years; put it in
  • xX_DarkTerminal_Xx — you don't have to use it. It's just there. Breathe.
  • Keyboard purists — nothing changed for you. Pretend this release doesn't exist. Your wrists remain pristine.

Updating

Linux:

curl -L https://github.com/BaLaurent/deez-notes/releases/latest/download/deez-notes-linux-amd64 -o deez-notes
chmod +x deez-notes
sudo mv deez-notes /usr/bin/deez-notes

Windows:
Download deez-notes-windows-amd64.exe from the releases page and replace your existing binary.

Arch (AUR):

yay -S deez-notes-bin

From source:

cd deez-notes && git pull && cargo install --path .

Full Changelog: v0.3.0...v0.4.0

v0.3.0 — The Great Filing

Choose a tag to compare

@BaLaurent BaLaurent released this 13 Apr 13:12

The Great Filing: deez-notes v0.3.0

Chapter XXV: The Avalanche

Fourteen notes. That's how many the creator had when he built deez-notes. A handful of Markdown files about Rust lifetimes, a shopping list, and something titled "existential_dread.md" that he swore was about error handling.

Fourteen notes. Clean. Manageable. A single flat list, sorted by date, searchable by fuzzy matching. Perfection.

Then he started using the tool.

Three weeks later, the list had 87 notes. Meeting notes. Project ideas. Recipes (because apparently deez-notes was now a cookbook). Half-finished blog posts. Quick reminders. Config snippets. Documentation drafts. And somewhere in that sea of Markdown, existential_dread.md had become genuinely about existential dread.

The creator opened deez-notes. Stared at the flat list. Scrolled. Scrolled more. Tried the search — typed "deploy", got four results: deploy_checklist.md, deploy_friday_disaster.md, deploy_rollback_plan.md, and deployment_cake_recipe.md (don't ask).

"I built a filing cabinet," the creator whispered, "with one drawer."

He looked at the fuzzy search bar. It looked back, helpfully. Defiantly. As if to say: "I'm doing my best, man."

"You are," the creator admitted. "But I need drawers."

Chapter XXVI: The Confession

xX_DarkTerminal_Xx didn't file a bug this time. Nobody did. This was worse.

This was the creator realizing that the tool he built for himself was becoming unusable. Not because it was broken — because it was flat. Seventeen notes about Rust and seventeen notes about cooking and seventeen notes about work all coexisted in a single scrollable abyss.

Every Unix user knows this moment. It's the moment you stop putting everything in ~/Documents and create subdirectories. The moment ls output scrolls past your terminal buffer. The moment you accept that a flat namespace doesn't scale.

"If I just add one more sorting option—" the creator started.

He stopped. He knew that voice. That was the voice of a developer negotiating with reality. The voice that says "we can optimize the query" instead of "we need an index." The voice that says "just add a filter" instead of "we need categories."

No. The answer wasn't better search. The answer was folders.

Chapter XXVII: The Architecture of Drawers

The creator had a choice.

Option A: Virtual folders. Tags. Metadata. A folder: field in the YAML frontmatter. Pure. Elegant. A lie — because the notes would still live in one flat directory, and every other tool on the system (ls, find, tree) would see chaos.

Option B: Real directories. Actual filesystem folders. Notes live where they belong. Move a note? mv. List a folder? ls. Delete a folder? rm -rf (carefully). Every Unix tool works because the truth is in the filesystem, not in metadata that only one app can read.

The creator chose Option B in under three seconds.

"If it doesn't work with ls," he muttered, "it doesn't work."

Chapter XXVIII: The Great Filing

917 lines of code later, deez-notes could think in hierarchies:

~/notes/
├── work/
│   ├── meetings/
│   │   ├── standup_2026-04-07.md
│   │   └── retro_q1.md
│   └── deploy_checklist.md
├── cooking/
│   ├── deployment_cake_recipe.md
│   └── pasta_carbonara.md
├── rust/
│   ├── lifetimes.md
│   └── existential_dread.md
└── shopping_list.md

Navigation: The side panel now shows the folder tree. Press Enter to dive into a folder. Press Backspace to go up. Press / to search within the current folder.

Moving notes: Select a note, press m, pick a destination folder. The note moves on the filesystem. No metadata. No database. Just rename().

Creating folders: Press F to create a new folder (or subfolder). It's a real mkdir under the hood.

Deleting folders: Select an empty folder, press d. Non-empty folders refuse to die — because rm -rf should be a conscious decision, not a keybinding accident.

The side panel, once a flat list of note titles, now shows breadcrumbs:

📁 work > meetings

And the status bar knows where you are:

[work/meetings] 2 notes | sorted by date

Chapter XXIX: The Persistence of Memory

While building the folder system, the creator noticed something that had been annoying him for weeks: every time he launched deez-notes, it forgot his preferences.

Set the theme to gruvbox? Gone on restart. Sort by title instead of date? Reset. It was like the tool had amnesia.

So he added config persistence. Theme and sort preferences now survive across restarts:

[general]
theme = "gruvbox"
sort_by = "title"
sort_order = "asc"

Change the theme with t? Saved. Change the sort with s? Saved. Close and reopen? Everything's exactly where you left it.

Small fix. Big quality of life.

Chapter XXX: The Satisfied Creator

For the first time in the history of deez-notes releases, xX_DarkTerminal_Xx had nothing to do with this one.

No angry DMs. No passive-aggressive GitHub issues. No demands for configurability. Just the creator, alone with his 87 notes, realizing he needed to organize his own mess.

And somewhere, in a Discord server the creator didn't know about, xX_DarkTerminal_Xx typed:

"Folders? FOLDERS?! I've been asking for this since— wait. I haven't actually asked for this. He just... did it? On his own?"

"...Character development."


What Changed

Component Before After
Note organization Flat list, single directory Real directory-based folder tree
Side panel Flat note list Hierarchical folder + note browser
Navigation Scroll + search only Folder drill-down (Enter/Backspace)
Move notes Not possible m to move to any folder
Create folders Not possible F to create folder/subfolder
Delete folders Not possible d on empty folders
Status bar Note count only Shows current path + note count
Theme persistence Reset on restart Saved to config automatically
Sort persistence Reset on restart Saved to config automatically
Files changed — 12 files, +917 lines

New Keybindings

Key Action
Enter Open folder / Open note
Backspace Go up one folder level
F Create new folder
m Move note to folder
d Delete empty folder

Configuration

Theme and sort preferences are now automatically persisted in your config file (~/.config/deez-notes/config.toml):

[general]
editor = "nvim"
pager = "mcat"
pager_args = ["--paging", "always"]
theme = "gruvbox"
sort_by = "date"
sort_order = "desc"

Who Should Update

  • Everyone with more than 20 notes — your sanity will thank you
  • Anyone who got tired of re-setting their theme every launch — it sticks now
  • The creator himself — because deployment_cake_recipe.md is finally in the right folder

Updating

Linux:

curl -L https://github.com/BaLaurent/deez-notes/releases/latest/download/deez-notes-linux-amd64 -o deez-notes
chmod +x deez-notes
sudo mv deez-notes /usr/bin/deez-notes

Windows:
Download deez-notes-windows-amd64.exe from the releases page and replace your existing binary.

From source:

cd deez-notes && git pull && cargo install --path .

Full Changelog: v0.2.3...v0.3.0

v0.2.3

Choose a tag to compare

@BaLaurent BaLaurent released this 16 Mar 12:24

The Pager Awakens: deez-notes v0.2.3

Chapter XXI: The Feature Request

It was a quiet Sunday morning. The creator was sipping coffee, basking in the afterglow of v0.2.2 — the release that taught deez-notes to tell floppy disk utilities apart from Markdown viewers. A surgical fix. Elegant. Clever, even.

Then the DM arrived.

u/xX_DarkTerminal_Xx opened Issue #44:

"Hey. So the mtools fix is cool and all. But I actually WANT to use mcat. The real one. The Skardyy one. I installed it specifically for your app. And now I have to hope your binary-sniffing code picks the right one? What if I install another tool called mcat tomorrow? What if someone forks mcat and calls it mcat2 and I want THAT?"

"Why can't I just... tell you which pager I want? You know. Like EDITOR. Like every Unix tool since 1974. Just let me configure it."

"Also my mcat needs --paging always or it just dumps and exits. So I need to pass args too."

The creator stared at the screen. Then at external.rs. Then at the is_mtools_mcat() function — 12 lines of code that spawned a subprocess, captured its output, and string-matched against "Mtools" just to figure out if a binary was the right binary.

"He's right," the creator muttered. "I built a lie detector for binaries when I should have just asked the user."

Chapter XXII: The Reckoning

The is_mtools_mcat() function was a band-aid on a broken design. The real problem was never "which mcat is this?" — it was "why is the app guessing at all?"

The editor had solved this years ago:

[general]
editor = "micro"

Clean. Explicit. No binary interrogation. No subprocess spawning. No string matching against vendor names. Just: "Hey user, what do you want?"

The pager deserved the same respect.

Chapter XXIII: The Liberation

40 lines of detection logic were deleted. In their place: two config fields.

[general]
pager = "mcat"
pager_args = ["--paging", "always"]

That's it. That's the whole feature.

  • pager — the binary to use for read-only view mode (Ctrl+V)
  • pager_args — arguments passed before the file path, because every pager speaks its own dialect

No pager configured? Falls back to cat. Always has. Always will. cat is the cockroach of Unix — it survives everything.

The code that replaced 40 lines of guesswork:

let (viewer, is_pager) = match pager {
    Some(name) if !name.is_empty() => (name.to_string(), true),
    _ => ("cat".to_string(), false),
};

Seven lines. No subprocesses. No string matching. No "Mtools" detection. Just a config value and a fallback.

Deleted forever:

  • is_mtools_mcat() — the binary interrogator
  • FALLBACK_VIEWERS — the guessing chain
  • PAGER_VIEWERS — the hardcoded pager list
  • find_viewer() — the resolution roulette
  • viewer_is_pager() — the identity crisis resolver

Rest in peace, you beautiful overengineered mess.

Chapter XXIV: The Pact

xX_DarkTerminal_Xx, thirsting for customization, desired the power to choose his own pager. The creator, emboldened by this relentless quest for growth and perpetual improvement, decided to honor Dark Terminal's request — and gave all users the ability to configure their own pager to their heart's content.

What had started as a thorn in the creator's side had now blossomed into a symbiotic bond: xX_DarkTerminal_Xx walked away with a better tool, and the creator gained an external voice that pushed him to refine his creation.

u/xX_DarkTerminal_Xx commented:

"FINALLY. I set pager = mcat, added my args, and it just works. No binary guessing. No mtools drama. No floppy disk flashbacks. Just my Markdown, rendered beautifully, with syntax highlighting and a built-in pager."

"You know what this is? This is growth. Character development. We went from 'your app crashed trying to read my floppy disk' to 'I can configure my own pager like a civilized human being.' That's a three-patch redemption arc."

"10/10. I'm not even deducting points this time."

The creator read the comment twice. No point deductions. No sarcastic asterisks. No passive-aggressive feature requests buried in the praise.

For the first time, xX_DarkTerminal_Xx was fully satisfied.

The creator immediately checked outside the window for flying pigs.


What Changed

Component Before After
Pager resolution Auto-detect mcat → cat with mtools sniffing User-configured pager + pager_args
is_mtools_mcat() 12 lines of subprocess interrogation Deleted
FALLBACK_VIEWERS / find_viewer() Hardcoded chain with identity checks Deleted — replaced by config
No pager configured Guessed mcat → cat Falls back to cat directly
Pager arguments Hardcoded --paging always for mcat only Configurable per-pager via pager_args
Config fields editor only editor, pager, pager_args

Configuration Example

[general]
editor = "nvim"
pager = "mcat"                       # any pager: mcat, bat, less, glow...
pager_args = ["--paging", "always"]  # arguments passed before the file path

Some popular pager configurations:

Pager Config
mcat pager = "mcat", pager_args = ["--paging", "always"]
bat pager = "bat", pager_args = ["--paging=always"]
glow pager = "glow", pager_args = ["-p"]
less pager = "less", pager_args = ["-R"]

No pager configured? cat does the job. No frills, no crashes, no floppy disk nostalgia.

Who Should Update

  • Everyone — the old mtools detection is gone; if you relied on auto-detected mcat, set it explicitly now
  • mcat users — add pager = "mcat" and pager_args = ["--paging", "always"] to your config
  • bat/glow/less users — you can now use your preferred pager instead of cat
  • u/xX_DarkTerminal_Xx — your three-patch redemption arc is complete

Updating

Linux:

curl -L https://github.com/BaLaurent/deez-notes/releases/latest/download/deez-notes-linux-amd64 -o deez-notes
chmod +x deez-notes
sudo mv deez-notes /usr/bin/deez-notes

Windows:
Download deez-notes-windows-amd64.exe from the releases page and replace your existing binary.

From source:

cd deez-notes && git pull && cargo install --path .

Full Changelog: v0.2.2...v0.2.3

v0.2.2

Choose a tag to compare

@BaLaurent BaLaurent released this 15 Mar 20:06

The Identity Crisis: deez-notes v0.2.2

Chapter XVI: The Return of the DM

It had been barely 24 hours since the Great Theme Reconciliation of v0.2.1. The creator was finally sleeping. Peacefully. Dreaming of a world where every pixel knew its color.

Then the notification hit.

u/xX_DarkTerminal_Xx commented on r/commandline:

"Yo @deez-notes dev. Me again. So I installed your app on my Debian server — the one I use over SSH for my homelab notes. Launched it. Pressed Ctrl+V to view a note. And this happened."

Attached: a screenshot. The kind that makes senior developers involuntarily close their laptops.

mcat: invalid option -- '-'
Mtools version 4.0.49, dated June 14th, 2025
Usage: mcat [-V] [-w] device
       -w write on device else read

Viewer error: Viewer 'mcat' exited with status 1

--- Press any key to return ---

"Bro tried to read my floppy disk. I DON'T HAVE A FLOPPY DISK. It's 2026."

The post received the coveted "Bruh Moment" award.

Chapter XVII: The Impostor

The creator rubbed their eyes, read the error three times, and then opened a terminal.

$ which mcat
/usr/bin/mcat
$ mcat --version
Mtools version 4.0.49, dated June 14th, 2025

"…Mtools?"

Turns out, the mtools package — a collection of utilities for reading MS-DOS floppy disks — ships a binary called mcat. Its purpose? Reading raw data from floppy disk devices. Its flags? -V for version and -w for write mode. That's it. That's the whole program.

And deez-notes, in its infinite wisdom, found this binary on $PATH, went "ah yes, a Markdown viewer!", and handed it --paging always ~/notes/todo.md.

mcat (mtools edition) stared at --paging like a golden retriever staring at a calculus textbook.

mcat: invalid option -- '-'

"I am a floppy disk reader," it replied. "I don't know what a Markdown is. I barely know what a hard drive is."

Chapter XVIII: The Lineup

The creator opened external.rs and looked at the viewer resolution chain:

const FALLBACK_VIEWERS: &[&str] = &["mcat", "cat"];

The logic was simple — and fatally naïve:

  1. Is there a binary called mcat on PATH? → Yes ✅
  2. Then it must be the Skardyy Markdown viewer! → No ❌
  3. Pass --paging always → 💥

It was the software equivalent of calling "Hey John!" in a crowded room and being surprised when the wrong John answered.

Chapter XIX: The Interrogation

The fix needed to be surgical. You can't just remove mcat from the fallback chain — it's the good viewer when it's actually installed. The problem isn't that mcat is on PATH. The problem is which mcat is on PATH.

So the creator added an identity check:

/// Returns true if the mcat on $PATH is the mtools FAT-disk utility
/// rather than the Markdown viewer we actually want.
fn is_mtools_mcat() -> bool {
    Command::new("mcat")
        .arg("--version")
        .output()
        .map(|o| {
            let text = [&o.stdout[..], &o.stderr[..]].concat();
            let text = String::from_utf8_lossy(&text);
            text.contains("Mtools")
        })
        .unwrap_or(false)
}

"State your name and purpose," the code now asks every mcat it encounters.

If the response contains "Mtools" — "I'm here about the floppy disks" — the viewer is politely escorted out of the lineup and cat steps up instead.

If the response is anything else — "I render Markdown with syntax highlighting and a built-in pager" — welcome aboard.

Chapter XX: The Debrief

u/xX_DarkTerminal_Xx tested the fix:

"WORKS. My note opened in cat like a normal program. No floppy disk references. No existential crisis. No '90s hardware nostalgia trip."

"Although honestly? The error message was kind of funny. 'Mtools version 4.0.49' in a note-taking app. That's like opening Spotify and getting a fax machine."

"9.5/10. The 0.5 is for making me google what mtools is. I learned things I didn't want to know about FAT12 file systems."

The creator committed the fix, tagged the release, and added a mental note to never trust a binary by its name alone.


What Changed

Component Before After
find_viewer() Trusts any mcat on PATH Checks if mcat is the mtools impostor
mtools mcat present 💥 Crash: invalid option -- '-' Skipped gracefully → falls back to cat
Skardyy mcat present Works Still works — no behavior change
Neither mcat present Falls back to cat Falls back to cat (unchanged)

Who Should Update

  • Anyone on Debian/Ubuntu/Fedora where mtools is often pre-installed or pulled as a dependency
  • SSH/server users where the Skardyy mcat isn't installed but mtools is
  • u/xX_DarkTerminal_Xx — at this point he deserves a contributor badge

If you already have the Skardyy mcat installed, this doesn't affect you. Your viewer experience is unchanged.


Updating

Linux:

curl -L https://github.com/BaLaurent/deez-notes/releases/latest/download/deez-notes-linux-amd64 -o deez-notes
chmod +x deez-notes
sudo mv deez-notes /usr/bin/deez-notes

Windows:
Download deez-notes-windows-amd64.exe from the releases page and replace your existing binary.

From source:

cd deez-notes && git pull && cargo install --path .

Full Changelog: v0.2.1...v0.2.2

v0.2.1

Choose a tag to compare

@BaLaurent BaLaurent released this 14 Mar 20:17

The Hotfix Chronicles: deez-notes v0.2.1

Chapter XI: The DM

Three days after the Great Theme Update, u/xX_DarkTerminal_Xx slid into the repo's issues tab. Not with praise. Not with a feature request. With a screenshot.

Issue #42: "SearchBar doesn't respect my Matugen theme in Terminal mode"

"Bro. BRO. I spent 4 hours getting my Matugen rice PERFECT. My waybar? Chef's kiss. My dunst? Immaculate. My deez-notes? THE SEARCH BAR IS GRAY. GRAY. Like a sad office carpet from 1997. The status bar too. My entire rice is RUINED."

Attached: a screenshot so cursed it made three CSS developers quit their jobs.

The post received a single comment: "skill issue" — which was promptly downvoted into oblivion.

Chapter XII: The Investigation

The creator opened search_bar.rs at 11 PM on a Friday. Because that's when all the best debugging happens — right between "one more episode" and "I should really sleep."

The crime scene was immediately obvious:

// SearchBar — the WRONG way
let paragraph = Paragraph::new(line)
    .style(Style::default().bg(self.theme.bg_bar));
// Only colors cells WITH text. Empty cells? ¯\_(ツ)_/¯

Meanwhile, StatusBar — the responsible sibling — had been doing it right all along:

// StatusBar — the RIGHT way
for x in area.x..area.x + area.width {
    buf[(x, area.y)].set_style(bg_style);  // Fill EVERYTHING
    buf[(x, area.y)].set_char(' ');
}

"You had ONE job, SearchBar," muttered the creator. "ONE. JOB."

Chapter XIII: The Deeper Betrayal

But the rabbit hole went deeper. The Terminal theme itself was the accomplice:

bg_main: Color::Reset,    // ✅ Follows terminal palette — good citizen
bg_bar: Color::DarkGray,  // ❌ HARDCODED — ignores Matugen/pywal entirely

Color::Reset means: "Hey terminal, YOU decide the color." Perfect for dynamic themes.

Color::DarkGray means: "I don't care what your theme says, I'm going with ANSI index 8." The equivalent of wearing a Hawaiian shirt to a black-tie event.

When Matugen regenerates the terminal palette, bg_main obediently follows the new background. But bg_bar sits there like a stubborn DarkGray rectangle, refusing to participate. A rogue pixel militia.

Chapter XIV: The Two Fixes

Fix #1 — The SearchBar Learns Manners:

SearchBar now pre-fills its entire area with bg_bar before rendering text — exactly like StatusBar does. No more half-colored bars that look like a loading screen froze at 60%.

Fix #2 — Terminal Theme Goes Full Reset:

// Before (the crime):
bg_bar: Color::DarkGray,  // "I do what I want"

// After (rehabilitation):
bg_bar: Color::Reset,     // "The terminal is my shepherd, I shall not hardcode"

The Terminal theme now uses Color::Reset for ALL backgrounds. Matugen, pywal, wal-telegram, flavours — whatever dynamic theme tool you're running — deez-notes gets out of the way and lets YOUR palette do its thing.

Chapter XV: The Result

u/xX_DarkTerminal_Xx updated his issue:

"CLOSED. It works. My SearchBar is now the same beautiful dark chocolate #0a0a0a as everything else. My rice is saved. My crops are watered. My skin is clear. 10/10."

He then immediately opened Issue #43: "feat: can the note list have rounded corners?"

The creator closed the laptop.


What Changed

Component Before After
SearchBar rendering Only colored cells with text Pre-fills entire area with bg_bar
Terminal theme bg_bar Color::DarkGray (hardcoded ANSI 8) Color::Reset (follows terminal palette)
Dynamic theme compat Broken — bars ignored pywal/Matugen Fixed — bars blend with terminal theme

Who Should Update

  • Everyone using Terminal theme with a dynamic palette tool (Matugen, pywal, etc.)
  • Anyone who noticed gray bars that didn't match their terminal background
  • u/xX_DarkTerminal_Xx specifically

If you're using a built-in theme (Catppuccin, Nord, etc.) or a custom [[themes]] block, this doesn't affect you — those already used explicit hex colors.


Updating

Linux:

curl -L https://github.com/BaLaurent/deez-notes/releases/latest/download/deez-notes-linux-amd64 -o deez-notes
chmod +x deez-notes
sudo mv deez-notes /usr/bin/deez-notes

Windows:
Download deez-notes-windows-amd64.exe from the releases page and replace your existing binary.

From source:

cd deez-notes && git pull && cargo install --path .

Full Changelog: v0.2.0...v0.2.1

v0.2.0

Choose a tag to compare

@BaLaurent BaLaurent released this 13 Mar 20:30

The Saga Continues: deez-notes v0.2.0

Chapter V: The Complaint

Barely three hours after the release of v0.1.0, a lone developer — known only as u/xX_DarkTerminal_Xx — posted on r/commandline:

"Just tried deez-notes. It's fast, I'll give it that. But why does it look like a PowerPoint from 2003? Every TUI I have is Catppuccin Mocha. This one? Terminal default gray. My eyes are bleeding. 2/10 would not rice."

The post received 847 upvotes and a "Helpful" award.

Chapter VI: The Creator Listens

By pure coincidence — or perhaps divine intervention — the creator of deez-notes was doom-scrolling Reddit at 2 AM instead of sleeping like a responsible adult.

"He's right," the creator whispered, staring at the hardcoded Color::Cyan scattered across 48 lines of code. "We can do better."

And so began The Great Refactoring.

Chapter VII: The Palette Wars

48 hardcoded colors were slain. In their place rose 11 semantic color roles — a system so elegant it made design system engineers weep:

Role Purpose
fg_primary Main text — no more random Color::White
fg_secondary Muted text, dates, the stuff you half-ignore
accent Borders, headings — the "look at me" color
highlight Status messages, inline code — the "hey, this matters" color
success Green stuff that means "good job"
error Red stuff that means "oh no"
bg_main The background — finally configurable, no more terminal roulette
bg_bar Status & search bar background
bg_selection Selected item glow
fg_selection Text on selected items
tag_colors Because tags deserve to be fabulous

Chapter VIII: The Six Themes

Six themes were forged in the fires of hex codes:

  • 🖥️ Terminal — The OG. Respects your terminal's palette like a polite guest.
  • 🐱 Catppuccin — For u/xX_DarkTerminal_Xx and the other 847 upvoters. You're welcome.
  • 🎨 Monokai — For those who peaked in the Sublime Text era (no shame).
  • 🧊 Nord — Cold, Scandinavian, minimalist. Like your commit messages should be.
  • 🌽 Gruvbox — Warm, retro, earthy. Like a terminal from a cozy cabin.
  • 🦇 Darcula — For JetBrains refugees who miss the darkness.

Press Ctrl+P to open the theme selector and browse them like you're picking a Netflix show.

Chapter IX: The Custom Path

"But what if I want MY OWN theme?" asked another Redditor, immediately.

Done. Add [[themes]] blocks to your config.toml:

[[themes]]
name = "Sakura"
fg_primary = "#e8d5c4"
fg_secondary = "#7a6b63"
accent = "#f0a0b0"
highlight = "#f5c6aa"
success = "#b4d9a0"
error = "#e06070"
bg_main = "#1e1518"
bg_bar = "#2a2025"
bg_selection = "#f0a0b0"
fg_selection = "#1e1518"
tag_colors = ["#f0a0b0", "#b4d9a0", "#f5c6aa", "#a0c4e8", "#d0a0e0", "#e0c080"]

Colors accept named values (cyan, red) or hex (#rrggbb). Custom themes appear alongside built-ins in the Ctrl+P selector.

Chapter X: What Else?

  • Ctrl+K now opens the help dialog (because F1 is so 1995)
  • Rust edition bumped from 2021 to 2024 (we live in the future now)
  • README updated with theme documentation

Epilogue II: The Response

u/xX_DarkTerminal_Xx edited his post:

"UPDATE: The madman actually did it. Catppuccin support AND custom themes. Changing my rating to 9/10. Minus one point because it still doesn't make coffee. Yet."

The creator smiled, closed Reddit, and opened a new issue titled "feat: coffee brewing integration."


Updating

Linux:

curl -L https://github.com/BaLaurent/deez-notes/releases/latest/download/deez-notes-linux-amd64 -o deez-notes
chmod +x deez-notes
sudo mv deez-notes /usr/bin/deez-notes

Windows:
Download deez-notes-windows-amd64.exe from the releases page and replace the existing binary in your PATH.

From source:

cd deez-notes
git pull
cargo install --path .

Your config.toml is untouched — existing configuration carries over automatically. New features (themes, Ctrl+P, Ctrl+K) just work out of the box.


Full Changelog: v0.1.0...v0.2.0

v0.1.0

Choose a tag to compare

@BaLaurent BaLaurent released this 13 Mar 10:21

The Epic Origins of deez-notes

Chapter I: The Darkness Before

In the beginning, there were no notes. Mankind wandered the terminal, lost and confused, grepping through endless directories like a cat chasing a laser pointer — fast, furious, and ultimately pointless.

"Where did I put that TODO list?" whispered a developer into the void. The void did not respond. It was too busy segfaulting.

Chapter II: The Prophecy

An ancient scroll (actually a Stack Overflow post from 2019) foretold the coming of a tool — a TUI so elegant, so keyboard-driven, that even Vim users would shed a single tear of approval.

"And lo, from the crates of Rust, shall rise a note manager. And it shall be fast. And it shall have fuzzy search. And it shall have... deez notes."

The prophecy was unclear about the name. Some say it was divinely inspired. Others say the developer just thought it was funny at 3 AM. Both are correct.

Chapter III: The Forging

Built upon the sacred foundations of Ratatui and tempered in the fires of cargo build --release, deez-notes emerged — a TUI note manager that could:

  • 📂 Browse your Markdown notes faster than you can say "where's my documentation"
  • 🔍 Fuzzy search so good it found notes you didn't even know you had (and some you wish you hadn't)
  • 🏷️ Tag filtering, because organizing notes is the closest most developers get to organizing their lives
  • ✏️ Create, rename, and delete notes without ever touching a mouse (mice are for the weak)
  • ⌨️ Vim-style j/k navigation, because arrow keys are just spicy j and k

Chapter IV: The Release

And so, v0.1.0 was released unto the world. Two sacred artifacts were forged:

Artifact Realm
deez-notes-linux-amd64 For the chosen ones
deez-notes-windows-amd64.exe For those who have yet to see the light (but we still love you)

Installation

Linux (the noble path):

curl -L https://github.com/BaLaurent/deez-notes/releases/latest/download/deez-notes-linux-amd64 -o deez-notes
chmod +x deez-notes
sudo mv deez-notes /usr/bin/deez-notes

Windows (we don't judge... much):
Download deez-notes-windows-amd64.exe and add it to your PATH. May your backslashes be ever in your favor.

Epilogue

"But what does it actually do?" asked a confused project manager.

"It manages deez notes," replied the developer, before immediately alt-tabbing back to the terminal.


Full Changelog: https://github.com/BaLaurent/deez-notes/commits/v0.1.0