Memory is volatile. My /docs folder became a graveyard for dead ideas. I’d write a perfect spec, then the code would diverge in a week. The docs lied. The code was the only truth, but reading raw commits to remember why I built a garbage collector for my downloads folder was pain.
The fix? I stopped writing docs and started writing a dev journal. A single LOG.md inside the project root. No structure, no templates, just raw stream of consciousness while I pipe curl into jq.
This naturally evolved into a public blog. But I don’t write articles. I publish annotated logs. Here’s the stack and the hard lessons.
The “Log, Then Blog” Pipeline
My rule: if it takes more than 15 minutes to document, the tooling sucks.
Source of Truth: Markdown files in the project repo. No external CMS. I keep it stupid.
Structure:
project-root/
├── src/
├── logs/
│ ├── 2026-05-01_async-queue-debug.md
│ └── 2026-05-06_switching-to-sqlite.md
- Why this works: The context is literally next to the bug. Future-me can
grepthe log and the source in the same terminal window.
Translation & Publishing: I write in a messy mix of Russian and English. Tech terms stay in English. Always. I built a tiny Go script (yeah, a wheel-reinventor, I know) that:
- Parses my Markdown.
- Wraps English/Russian blocks in
<div>tags for the i18n switcher. - Converts frontmatter to the format Astro needs.
// sanitize.go — keeps tech terms intact regardless of language
func processLine(line string) string {
// Systemd, Kubernetes, namespaces — never translate
re := regexp.MustCompile(`(\b(?:systemd|k8s|api|json|yaml|http|sql)\b)`)
return re.ReplaceAllString(line, `<span class="no-translate">$1</span>`)
}
Doing it yourself means you control the edge cases. Translation APIs choke on kubectl exec.
Tools I Built Because of the Blog
Writing about problems forces you to solve them properly. No more “it works on my machine” duct tape.
1. ClipWipe (Context cleaner)
Problem: While writing a post about my clipboard hijacking macOS, I kept pasting API keys into the draft. Tool: A daemon that watches the clipboard and wipes anything matching a regex pattern (AWS keys, JWT tokens) within 5 seconds.
# Not a joke. Saved me from leaking a PAT twice this month.
clipwipe --patterns "sk-[a-zA-Z0-9]{20,}" --timeout 5
2. Snippet Vault
Problem: I described a complex jq transformation in a blog post. Three months later, I needed it again and couldn’t find it.
Tool: A CLI snippet manager. I type snip how-to-flatten-json and it spits out the code directly to stdout so I can pipe it.
snip flatten-json | pbcopy
# No browser, no mouse, no scrolling through old articles.
The Graveyard of Mistakes
Here’s where the journal becomes a survival tool.
Grabl: The “Dual Language” DOM Mess
When I set up the bilingual plugin, I used style="display:none" and style="display:block" via JavaScript toggle.
What happened: Cumulative Layout Shift (CLS) on the Astro static build. The hidden English block would load, then vanish, pushing the content up. A white flash of death.
The Fix: Don’t mess with display.
/* Hide without losing layout space */
[data-i18n-block] {
visibility: visible;
height: auto;
}
[data-i18n-block][style*="display:none"] {
visibility: hidden;
height: 0;
overflow: hidden;
}
And the toggle should be a MutationObserver, not a click event relying on React state. Keep it vanilla.
Grabl: The Git Hook that Killed Productivity
I wrote a pre-commit hook to check for broken links in my markdown. It pinged every external URL.
Result: A commit took 47 seconds. I ctrl+c’d and just force-pushed. Deleted the hook. Verifying links is a CI pipeline job, not a commit gate.
The Takeaway
Your blog doesn’t need a niche. It needs to be the external hard drive for your brain. If you fixed a cron job at 2 AM, write a markdown file. Don’t polish it. Publish the log.
The process naturally makes you write cleaner code because you’re embarrassed to explain the messy parts in public. That’s the point.