The Problem
I take a lot of notes. They’re mostly markdown files — quick thoughts, daily logs, stuff I want to reference later. The problem is I live in the terminal, and most note apps assume you don’t.
I tried Obsidian. It’s fine, I guess — the graph view is cool, plugins are everywhere, and I get why everyone recommends it. But I open terminals all day. The idea of clicking out of my workflow just to write a note felt wrong. I wanted something that lived where I already lived.
Kiroku
So I built Kiroku. It’s a TUI note manager. Fuzzy search, markdown preview, git sync for backup. No Electron, no GUI, just a binary that runs in any terminal.
The workflow is basically: type to search, arrow keys to navigate, enter to open. Sort of like lazygit meets yazi, but for notes. That’s really all I wanted.
Learning Rust
I’ve been wanting to learn Rust for years. I’d do exercism problems, read the book, build tiny toy programs — and then forget everything a week later. I needed something real to work on.
Kiroku was that thing. It’s small enough to finish, but big enough to run into real problems:
- The borrow checker fought me on the search logic for way too long
- Working with
serde_yamlfor frontmatter was straightforward once I figured out the right types ratatuiis well-documented but there’s a learning curve to immediate-mode rendering
One specific moment: I spent 3 hours on a compiler error that turned out to be a missing &. That’s Rust in a nutshell for me so far.
The Stack
- ratatui — TUI framework. Good docs, active maintenance.
- fuzzy-matcher — For search. Simple, fast.
- serde + serde_yaml — Parsing YAML frontmatter
The search code is the part I’m most happy with:
pub fn update_search(&mut self) {
if self.search_query.is_empty() {
self.notes = self.all_notes.clone();
} else {
let matcher = SkimMatcherV2::default();
let mut matches: Vec<(&Note, i64)> = self
.all_notes
.iter()
.filter_map(|note| {
matcher
.fuzzy_match(¬e.title, &self.search_query)
.map(|score| (note, score))
})
.collect();
matches.sort_by(|a, b| b.1.cmp(&a.1));
self.notes = matches.into_iter().map(|(n, _)| n.clone()).collect();
}
}
What’s Next
I use Kiroku every day now. A few things I want to add:
- Calendar view for time-based note browsing
- Better file watcher performance (it chokes on large directories)
- Homebrew and AUR packages
If you try it and have thoughts, feel free to open an issue. Or don’t — it’s here if you need it.
Source on GitHub.