<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: martinimarcello00</title>
    <description>The latest articles on DEV Community by martinimarcello00 (@martinimarcello00).</description>
    <link>https://dev.to/martinimarcello00</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F155611%2Fbbc52ebe-cbb8-49aa-8a06-12214178da25.png</url>
      <title>DEV Community: martinimarcello00</title>
      <link>https://dev.to/martinimarcello00</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/martinimarcello00"/>
    <language>en</language>
    <item>
      <title>How this site is built</title>
      <dc:creator>martinimarcello00</dc:creator>
      <pubDate>Tue, 25 Aug 2026 17:46:44 +0000</pubDate>
      <link>https://dev.to/martinimarcello00/how-this-site-is-built-52eb</link>
      <guid>https://dev.to/martinimarcello00/how-this-site-is-built-52eb</guid>
      <description>&lt;p&gt;Every personal site I built before this one died the same way. A CMS I stopped updating, a database I had to back up, a plugin that broke on a version bump. The fix was to make the site something I already maintain every day: a repository.&lt;/p&gt;

&lt;p&gt;There is no server, no database, nothing to patch. The whole thing is text files that get turned into HTML on a machine that lives for forty seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hugo, because the preview is instant
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://gohugo.io/" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt;&lt;/strong&gt; — A website that is just files in a repository.&lt;/p&gt;

&lt;p&gt;This site is Hugo: Markdown for the words, YAML and JSON for the structured parts, Go templates for everything else. Builds finish in under half a second, which matters more than it sounds, because a preview that is instant is a preview you actually look at. No database, no runtime, nothing to patch at three in the morning.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Markdown for the words, YAML and JSON for the structured parts, Go templates for everything else. The full site rebuilds in about four hundred milliseconds.&lt;/p&gt;

&lt;p&gt;That number is not vanity. A preview that is instant is a preview you actually look at, so you fix the spacing you would otherwise have shrugged at.&lt;/p&gt;

&lt;p&gt;The part that took longest to appreciate is the &lt;code&gt;data/&lt;/code&gt; directory. Anything that is a list belongs there, not in a template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# data/post_categories.yml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terminal&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terminal&lt;/span&gt;
  &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fa-terminal&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a category is now a three line diff instead of a hunt through layouts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pages that keep themselves current
&lt;/h2&gt;

&lt;p&gt;The pages I would forget to update are the ones nobody wants to see out of date: publications, repositories, what I have been reading.&lt;/p&gt;

&lt;p&gt;So they update themselves. A handful of Python scripts, standard library only so CI needs no install step, fetch from ORCID, Semantic Scholar, GitHub and Open Library and write plain JSON into &lt;code&gt;data/&lt;/code&gt;. Hugo reads it at build time.&lt;/p&gt;

&lt;p&gt;The tip worth stealing is the failure mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Refresh auto-updating data&lt;/span&gt;
  &lt;span class="c1"&gt;# Non-fatal: on API failure the committed data/*.json is used as fallback&lt;/span&gt;
  &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3 scripts/update_data.py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated JSON is committed. If ORCID is down, the step goes red, the build carries on and the site shows yesterday's data. A stale publication list beats a failed deploy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt; — The only deploy button, and it is a git push.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same workflow runs weekly on a cron, so the site refreshes even in a week where I push nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The logos on this page downloaded themselves
&lt;/h2&gt;

&lt;p&gt;The tool cards above carry real brand marks, and not one of them costs a request. A script reads &lt;code&gt;data/tools.json&lt;/code&gt;, resolves each entry to a Simple Icons slug, downloads the SVG into &lt;code&gt;assets/&lt;/code&gt; and records the brand colour next to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"githubactions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"icons/tools/githubactions.svg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hex"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#2088FF"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hugo inlines that file during the build, so the page ships with the icon already in the markup. No CDN, no call from the browser, nothing for a content security policy to argue with. Adding a tool is one JSON entry and one script run.&lt;/p&gt;

&lt;p&gt;The photo wall goes further. A script parses the EXIF out of the originals, reverse geocodes the coordinates once, caches the answer so the geocoder is never asked twice, and writes the result as JSON. The source photos keep their metadata in the repository. The published copies do not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[imaging.exif]&lt;/span&gt;
  &lt;span class="py"&gt;disableLatLong&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The place name reaches the page. The coordinates stay behind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Social cards drawn at build time
&lt;/h2&gt;

&lt;p&gt;This is my favourite trick in the repository. Every page has its own 1200x630 preview image, and nothing renders a screenshot.&lt;/p&gt;

&lt;p&gt;Hugo can draw text onto an image, so the card is a base gradient plus the page title, stamped during the build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ $base := resources.Get "images/og-base.png" }}
{{ $font := resources.Get "fonts/SpaceGrotesk.ttf" }}
{{ $card := $base.Filter (images.Text $title (dict
     "x" 80 "y" 160 "size" 68 "color" "#f8fafc" "font" $font)) }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details cost me an afternoon. &lt;code&gt;images.Text&lt;/code&gt; does not wrap, so the title has to be split into lines in the template. And the variable font renders at its lightest weight, so the text looked anaemic until I drew it three times at one pixel offsets to fake a bold.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search is a build step, not a service
&lt;/h2&gt;

&lt;p&gt;I wanted search without a third party and without shipping an index of the whole site to every visitor. &lt;a href="https://pagefind.app/" rel="noopener noreferrer"&gt;Pagefind&lt;/a&gt; reads the finished HTML after Hugo runs and writes an index next to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hugo &lt;span class="nt"&gt;--gc&lt;/span&gt; &lt;span class="nt"&gt;--minify&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; pagefind &lt;span class="nt"&gt;--site&lt;/span&gt; public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One attribute decides what gets indexed, which is also how the pages I do not want in search stay out of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="content"{{ if not .Params.noindex }} data-pagefind-body{{ end }}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press cmd+K anywhere on the site and it opens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copilot, and why the GitHub part matters
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;&lt;/strong&gt; — A fast first draft, never the final word.&lt;/p&gt;

&lt;p&gt;Used the way it is good: a fast first draft on code I can review, never on decisions I have not made yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The useful part was not autocomplete. It was that Copilot talks to GitHub through &lt;a href="https://modelcontextprotocol.io/" rel="noopener noreferrer"&gt;MCP&lt;/a&gt;, so it reads the repository, the issues and the workflow runs directly instead of me pasting context into a chat window.&lt;/p&gt;

&lt;p&gt;Asking why a deploy failed and having it read the actual run is a different activity from describing the failure from memory.&lt;/p&gt;

&lt;p&gt;It is still a draft machine. It wrote a breadcrumb partial for me and put the styling on a selector that only existed on half the pages, which I found by measuring the rendered page rather than by reading the diff. Verify, then keep.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; — The site is a repository, and that is the whole trick.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The crosspost that cannot duplicate itself
&lt;/h2&gt;

&lt;p&gt;A post opts in to dev.to with one line of front matter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;devto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A script renders it, rewrites the Hugo shortcodes into portable Markdown and sends it with a &lt;code&gt;canonical_url&lt;/code&gt; pointing back here, so the copy never competes with the original in search results. The version that lands there also gets a closing link home that this page does not have.&lt;/p&gt;

&lt;p&gt;The hard part was running it from CI, where there is no local state. Before sending anything the script asks dev.to what the account already holds and indexes it by canonical URL, so an article that exists is updated and never created twice, even on a fresh runner. The state file is only a cache plus a hash of the Markdown last sent, which is what stops an unchanged post being pushed back to the top of the feed on every deploy.&lt;/p&gt;

&lt;p&gt;Two things bit me. dev.to renders Markdown with hard wrapping on, so my eighty column source lines each became a &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; and the indented continuations of a list were torn out of their bullets, which is why paragraphs are unwrapped before they are sent. And the API returns 429 well before its documented limits, so writes are spaced out and retried on the &lt;code&gt;Retry-After&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;If you are reading this on dev.to, that is how it got here.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would tell myself at the start
&lt;/h2&gt;

&lt;p&gt;Put the content in &lt;code&gt;data/&lt;/code&gt; before you think you need to. Let the scripts fail loudly and the site fail quietly. And measure the thing in a browser, because the bug is usually in the gap between what the template says and what the page does.&lt;/p&gt;

&lt;p&gt;Every snippet above is the real thing, copied out of the repository rather than written for the occasion. Take what is useful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marcellomartini.tech/tools/" rel="noopener noreferrer"&gt;The rest of the toolbox&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This one first appeared on &lt;a href="https://marcellomartini.tech/posts/how-this-site-is-built/" rel="noopener noreferrer"&gt;my site&lt;/a&gt;, where I write about the systems I build and the tools I actually use — &lt;a href="https://marcellomartini.tech/posts/" rel="noopener noreferrer"&gt;the rest of the posts live here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>webdev</category>
      <category>githubactions</category>
      <category>staticsite</category>
    </item>
    <item>
      <title>The tools I actually use</title>
      <dc:creator>martinimarcello00</dc:creator>
      <pubDate>Tue, 25 Aug 2026 15:38:09 +0000</pubDate>
      <link>https://dev.to/martinimarcello00/the-tools-i-actually-use-360k</link>
      <guid>https://dev.to/martinimarcello00/the-tools-i-actually-use-360k</guid>
      <description>&lt;p&gt;Most "my setup" posts are shopping lists. This one is not, because the tools below earned their place by surviving contact with a bad week: a deadline, a broken laptop, a paper due, an evening where I could not stop scrolling. Everything else got uninstalled.&lt;/p&gt;

&lt;p&gt;Three of them are worth telling properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  chezmoi: my machine is a git clone
&lt;/h2&gt;

&lt;p&gt;I used to keep dotfiles in a repo with a &lt;code&gt;install.sh&lt;/code&gt; that symlinked things into place. It worked right up until my laptop and my home server needed &lt;em&gt;almost&lt;/em&gt; the same configuration: same aliases, different git email, different paths, and one of them absolutely must not carry a work SSH config.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.chezmoi.io/" rel="noopener noreferrer"&gt;chezmoi&lt;/a&gt; solves exactly that. The dotfiles live in one repository, the machine-specific bits are templates, and secrets are pulled from a password manager at apply time instead of sitting in git. Bootstrapping a new machine is now one command and a coffee.&lt;/p&gt;

&lt;p&gt;The unglamorous benefit is the one I care about: I stopped being afraid of reinstalling. When the setup is a &lt;code&gt;git clone&lt;/code&gt; away, wiping a machine is a chore rather than a decision.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.chezmoi.io/" rel="noopener noreferrer"&gt;chezmoi&lt;/a&gt;&lt;/strong&gt; — Dotfiles in git, secrets left out of it.&lt;/p&gt;

&lt;p&gt;Keeps my shell, editor and git configuration in one repository and templates the parts that differ per machine, so a work laptop and a home server share a setup without sharing their secrets. Bootstrapping a new machine is a single command instead of an afternoon of copy-paste.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Atuin: my shell history became searchable
&lt;/h2&gt;

&lt;p&gt;Every developer has a moment of typing &lt;code&gt;history | grep&lt;/code&gt; and hoping. Shell history is one of the most valuable datasets you generate, and by default it is a flat file that truncates, forgets which directory you were in, and vanishes when you open two terminals at once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://atuin.sh/" rel="noopener noreferrer"&gt;Atuin&lt;/a&gt; replaces &lt;code&gt;Ctrl-R&lt;/code&gt; with a real search over a SQLite database of every command, recorded with its directory, its exit code and how long it took. It syncs end-to-end encrypted between machines, and you can run the sync server yourself if you would rather not trust anyone with it.&lt;/p&gt;

&lt;p&gt;What changed is subtle. I stopped writing throwaway shell scripts for things I do twice a year, because "the &lt;code&gt;ffmpeg&lt;/code&gt; command from that conference talk" is now a two-second lookup instead of an archaeology project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://atuin.sh/" rel="noopener noreferrer"&gt;Atuin&lt;/a&gt;&lt;/strong&gt; — Shell history as a searchable database.&lt;/p&gt;

&lt;p&gt;Replaces Ctrl-R with a real search over every command I have ever run, recorded with its directory, exit code and duration. History syncs end-to-end encrypted between my laptop and my servers, and you can host the sync server yourself. The obscure ffmpeg invocation from eight months ago is now a two-second lookup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A brick, and the app behind it
&lt;/h2&gt;

&lt;p&gt;The one that is not software. I was properly hooked on my phone: in hand before my eyes were open, thumb scrolling through dinners and lectures. Willpower never fixed it.&lt;/p&gt;

&lt;p&gt;What fixed it was &lt;a href="https://marcellomartini.tech/brick/" rel="noopener noreferrer"&gt;a small orange square on my desk&lt;/a&gt;, a magnet and an NFC tag. Tap the phone against it and the apps I chose disappear. Tap again and they come back, but only if I walk to wherever I left the brick. That tiny bit of friction is the entire trick.&lt;/p&gt;

&lt;p&gt;Underneath it is &lt;a href="https://foqos.app/" rel="noopener noreferrer"&gt;Foqos&lt;/a&gt;, an open-source iOS app that ties Apple's Screen Time restrictions to an NFC tag. No account, no subscription, no streak to protect. Two weeks in, my screen time had halved and I had stopped missing it, which says more about the reflex than about the willpower.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://marcellomartini.tech/brick/" rel="noopener noreferrer"&gt;Focus Brick&lt;/a&gt;&lt;/strong&gt; — A magnet, an NFC tag, two taps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://foqos.app/" rel="noopener noreferrer"&gt;Foqos&lt;/a&gt;&lt;/strong&gt; — The open-source app behind the brick.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The rest of the toolbox
&lt;/h2&gt;

&lt;p&gt;These three are the ones with a story. The rest of what I use every day lives on the toolbox page: editor, terminal, research and focus tools, each with a note on why it earned its place, filterable by category.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marcellomartini.tech/tools/" rel="noopener noreferrer"&gt;See the full toolbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nothing here is sponsored and nothing is permanent. If one of these stops earning its place, it comes off the list.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This one first appeared on &lt;a href="https://marcellomartini.tech/posts/tools-i-actually-use/" rel="noopener noreferrer"&gt;my site&lt;/a&gt;, where I write about the systems I build and the tools I actually use — &lt;a href="https://marcellomartini.tech/posts/" rel="noopener noreferrer"&gt;the rest of the posts live here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>devtools</category>
      <category>dotfiles</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>Rebuilding my terminal from a git clone</title>
      <dc:creator>martinimarcello00</dc:creator>
      <pubDate>Tue, 25 Aug 2026 15:27:05 +0000</pubDate>
      <link>https://dev.to/martinimarcello00/rebuilding-my-terminal-from-a-git-clone-293o</link>
      <guid>https://dev.to/martinimarcello00/rebuilding-my-terminal-from-a-git-clone-293o</guid>
      <description>&lt;p&gt;I spend more hours in a terminal than in any other window, and for years the configuration behind it lived nowhere: a &lt;code&gt;.zshrc&lt;/code&gt; I had edited so many times I no longer knew which line did what, a colour scheme picked in a preferences dialog, an SSH config that only existed on one laptop.&lt;/p&gt;

&lt;p&gt;What follows is what that turned into. Not a list of everything installed on my Mac, but the terminal I actually type in and the two-part trick that keeps it reproducible: every setting is a plain-text file, and every plain-text file is in a repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  The terminal: Ghostty
&lt;/h2&gt;

&lt;p&gt;I moved off &lt;a href="https://iterm2.com/" rel="noopener noreferrer"&gt;iTerm2&lt;/a&gt; because I wanted a terminal that was fast and, more importantly, one whose entire appearance I could describe in text.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://ghostty.org/" rel="noopener noreferrer"&gt;Ghostty&lt;/a&gt;&lt;/strong&gt; — A fast terminal with no tabs of its own to manage.&lt;/p&gt;

&lt;p&gt;Native on macOS, GPU-accelerated, and quick enough that a long build log scrolls without the fan spinning up. The configuration is a single plain-text file with one setting per line, which means the whole appearance of my terminal is a handful of lines in my dotfiles rather than a screenshot of a preferences pane I would have to redo on the next machine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ghostty's &lt;a href="https://ghostty.org/docs/config" rel="noopener noreferrer"&gt;config&lt;/a&gt; is a single file, &lt;code&gt;~/.config/ghostty/config.ghostty&lt;/code&gt;, with &lt;code&gt;key = value&lt;/code&gt; on each line and &lt;code&gt;#&lt;/code&gt; for comments. That is the whole format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;dracula&lt;/span&gt;
&lt;span class="py"&gt;font-family&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"MesloLGS NF"&lt;/span&gt;
&lt;span class="py"&gt;font-size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;14&lt;/span&gt;
&lt;span class="py"&gt;window-padding-x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;8&lt;/span&gt;
&lt;span class="py"&gt;window-padding-y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;6&lt;/span&gt;
&lt;span class="py"&gt;macos-option-as-alt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;copy-on-select&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interesting part is &lt;code&gt;theme&lt;/code&gt;. A Ghostty &lt;a href="https://ghostty.org/docs/config/reference#theme" rel="noopener noreferrer"&gt;theme&lt;/a&gt; is just another config file, so any file dropped in &lt;code&gt;~/.config/ghostty/themes/&lt;/code&gt; can be selected by name. Mine is &lt;a href="https://draculatheme.com/ghostty" rel="noopener noreferrer"&gt;Dracula&lt;/a&gt; and starts like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;palette&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;0=#21222c&lt;/span&gt;
&lt;span class="py"&gt;palette&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1=#ff5555&lt;/span&gt;
&lt;span class="py"&gt;palette&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2=#50fa7b&lt;/span&gt;
&lt;span class="py"&gt;background&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="c"&gt;#282a36
&lt;/span&gt;&lt;span class="s"&gt;foreground = #f8f8f2&lt;/span&gt;
&lt;span class="py"&gt;cursor-color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="c"&gt;#f8f8f2
&lt;/span&gt;&lt;span class="s"&gt;selection-background = #44475a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sixteen palette entries and a handful of colours: that is the difference between "my terminal looks right" and "my terminal looked right on the old machine". &lt;code&gt;cmd+shift+,&lt;/code&gt; reloads the config without restarting, so tuning it is a live loop rather than a quit-and-relaunch cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shell: zsh, Oh My Zsh, Powerlevel10k
&lt;/h2&gt;

&lt;p&gt;macOS ships zsh, &lt;a href="https://ohmyz.sh/" rel="noopener noreferrer"&gt;Oh My Zsh&lt;/a&gt; handles plugin loading, and &lt;a href="https://github.com/romkatv/powerlevel10k" rel="noopener noreferrer"&gt;Powerlevel10k&lt;/a&gt; draws the prompt.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://ohmyz.sh/" rel="noopener noreferrer"&gt;Oh My Zsh&lt;/a&gt;&lt;/strong&gt; — A shell that tells me where I am.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two lines do most of the work in my &lt;code&gt;.zshrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ZSH_THEME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"powerlevel10k/powerlevel10k"&lt;/span&gt;
&lt;span class="nv"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;git zsh-syntax-highlighting z fzf-tab&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those four plugins are the ones that survived. &lt;code&gt;git&lt;/code&gt; for the aliases and the branch state, &lt;a href="https://github.com/zsh-users/zsh-syntax-highlighting" rel="noopener noreferrer"&gt;&lt;code&gt;zsh-syntax-highlighting&lt;/code&gt;&lt;/a&gt; because a command turning red before I press Enter has caught more typos than I would like to admit, &lt;a href="https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/z" rel="noopener noreferrer"&gt;&lt;code&gt;z&lt;/code&gt;&lt;/a&gt; to jump to a directory I visited last week by typing three letters of its name, and &lt;a href="https://github.com/Aloxaf/fzf-tab" rel="noopener noreferrer"&gt;&lt;code&gt;fzf-tab&lt;/code&gt;&lt;/a&gt; to hand tab-completion over to &lt;a href="https://github.com/junegunn/fzf" rel="noopener noreferrer"&gt;fzf&lt;/a&gt;, turning a wall of candidates into a fuzzy-searchable list.&lt;/p&gt;

&lt;p&gt;Powerlevel10k is configured with &lt;code&gt;p10k configure&lt;/code&gt; once, and the wizard writes &lt;code&gt;~/.p10k.zsh&lt;/code&gt; — which then goes into the dotfiles repo like everything else. Mine runs in &lt;code&gt;nerdfont-v3&lt;/code&gt; mode with the lean prompt, which means the prompt shows the git branch, the Python environment and the exit code of the last command. Most of my terminal mistakes used to be context mistakes: wrong branch, wrong virtualenv, wrong machine.&lt;/p&gt;

&lt;p&gt;One detail that is easy to miss: the p10k instant-prompt block has to stay at the very top of &lt;code&gt;.zshrc&lt;/code&gt;, above anything that might print or ask for input. It is the reason the prompt appears immediately instead of after the plugins finish loading.&lt;/p&gt;

&lt;h2&gt;
  
  
  History that is actually searchable
&lt;/h2&gt;

&lt;p&gt;The single biggest upgrade is not the prompt. It is replacing &lt;code&gt;Ctrl-R&lt;/code&gt; with something that remembers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://atuin.sh/" rel="noopener noreferrer"&gt;Atuin&lt;/a&gt;&lt;/strong&gt; — Shell history as a searchable database.&lt;/p&gt;

&lt;p&gt;Replaces Ctrl-R with a real search over every command I have ever run, recorded with its directory, exit code and duration. History syncs end-to-end encrypted between my laptop and my servers, and you can host the sync server yourself. The obscure ffmpeg invocation from eight months ago is now a two-second lookup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One line in &lt;code&gt;.zshrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;atuin init zsh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, every command is recorded in SQLite along with its directory, exit code and duration, and &lt;code&gt;Ctrl-R&lt;/code&gt; becomes a real search across all of it — end-to-end encrypted between machines, with a &lt;a href="https://atuin.sh/docs/self-hosting" rel="noopener noreferrer"&gt;sync server&lt;/a&gt; you can host yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The small stuff that adds up
&lt;/h2&gt;

&lt;p&gt;Aliases live in their own file rather than sprawling through &lt;code&gt;.zshrc&lt;/code&gt;, sourced at the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.zsh_aliases &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zsh_aliases
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of them are unremarkable — &lt;code&gt;gs&lt;/code&gt;, &lt;code&gt;ga&lt;/code&gt;, &lt;code&gt;gc&lt;/code&gt;, &lt;code&gt;gp&lt;/code&gt; for git, &lt;code&gt;grep --color=auto&lt;/code&gt;, &lt;code&gt;rm -i&lt;/code&gt; because I would rather be asked. The ones I actually notice are the navigation shortcuts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; .&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd .."&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; ...&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ../../.."&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; ....&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cd ../../../.."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two more lines worth stealing. &lt;a href="https://micro-editor.github.io/" rel="noopener noreferrer"&gt;&lt;code&gt;micro&lt;/code&gt;&lt;/a&gt; as the editor, because I want a terminal editor that behaves like every other text field when I am editing a commit message at 11pm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'micro'&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VISUAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'micro'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the binding that opens the current command line in that editor, which turns a long unreadable one-liner into something you can actually see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;autoload &lt;span class="nt"&gt;-U&lt;/span&gt; edit-command-line
zle &lt;span class="nt"&gt;-N&lt;/span&gt; edit-command-line
bindkey &lt;span class="s1"&gt;'^x^e'&lt;/span&gt; edit-command-line
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Making all of it reproducible
&lt;/h2&gt;

&lt;p&gt;Everything above is text files. The part that makes it a setup rather than a collection is &lt;a href="https://www.chezmoi.io/" rel="noopener noreferrer"&gt;chezmoi&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.chezmoi.io/" rel="noopener noreferrer"&gt;chezmoi&lt;/a&gt;&lt;/strong&gt; — Dotfiles in git, secrets left out of it.&lt;/p&gt;

&lt;p&gt;Keeps my shell, editor and git configuration in one repository and templates the parts that differ per machine, so a work laptop and a home server share a setup without sharing their secrets. Bootstrapping a new machine is a single command instead of an afternoon of copy-paste.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My dotfiles repository maps one-to-one onto my home directory — &lt;code&gt;dot_zshrc&lt;/code&gt; becomes &lt;code&gt;~/.zshrc&lt;/code&gt;, &lt;code&gt;dot_config/ghostty/themes/dracula&lt;/code&gt; becomes &lt;code&gt;~/.config/ghostty/themes/dracula&lt;/code&gt; — plus three &lt;a href="https://www.chezmoi.io/user-guide/use-scripts-to-perform-actions/" rel="noopener noreferrer"&gt;scripts&lt;/a&gt; that only run the first time chezmoi is applied on a machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one installs &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; if missing and runs &lt;a href="https://docs.brew.sh/Brew-Bundle-and-Brewfile" rel="noopener noreferrer"&gt;&lt;code&gt;brew bundle&lt;/code&gt;&lt;/a&gt; against a &lt;code&gt;Brewfile&lt;/code&gt; that carries every formula, cask, App Store app and VS Code extension;&lt;/li&gt;
&lt;li&gt;one clones Oh My Zsh, Powerlevel10k, &lt;code&gt;fzf-tab&lt;/code&gt; and &lt;code&gt;zsh-syntax-highlighting&lt;/code&gt; into the right places;&lt;/li&gt;
&lt;li&gt;one applies the macOS defaults I would otherwise click through in System Settings — dark mode, Dock size, Finder path bar, key repeat.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The naming does the work: a file called &lt;code&gt;run_once_install-deps.sh&lt;/code&gt; runs once and chezmoi remembers its hash, so applying the dotfiles again does not reinstall Homebrew.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets stay out of the repository
&lt;/h3&gt;

&lt;p&gt;The reason a dotfiles repo usually stops at "shell config" is SSH keys. chezmoi solves that with &lt;a href="https://www.chezmoi.io/user-guide/templating/" rel="noopener noreferrer"&gt;templates&lt;/a&gt;: a managed file can call out to a &lt;a href="https://www.chezmoi.io/user-guide/password-managers/bitwarden/" rel="noopener noreferrer"&gt;password manager&lt;/a&gt; at apply time. My signing key is a two-line file in the repo that contains no key at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{- (bitwarden "item" "ssh-git-signing").sshKey.privateKey }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The public keys and &lt;code&gt;~/.ssh/config&lt;/code&gt; are committed as plain files, the private halves are rendered from &lt;a href="https://bitwarden.com/" rel="noopener noreferrer"&gt;Bitwarden&lt;/a&gt; at apply time and never touch git. The same mechanism fills in per-machine values — my &lt;code&gt;.chezmoi.toml.tmpl&lt;/code&gt; pulls a few cloud subscription IDs from a Bitwarden item so the helper scripts in &lt;code&gt;~/.local/bin&lt;/code&gt; know which subscription to talk to without those IDs living in a public repo.&lt;/p&gt;

&lt;p&gt;Once the keys are in place, git &lt;a href="https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification" rel="noopener noreferrer"&gt;signs commits with SSH&lt;/a&gt; rather than GPG, which is three lines and no keyring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[user]&lt;/span&gt;
    &lt;span class="py"&gt;signingkey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;~/.ssh/id_ed25519_signing.pub&lt;/span&gt;
&lt;span class="nn"&gt;[gpg]&lt;/span&gt;
    &lt;span class="py"&gt;format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ssh&lt;/span&gt;
&lt;span class="nn"&gt;[commit]&lt;/span&gt;
    &lt;span class="py"&gt;gpgsign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A new machine, start to finish
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Homebrew&lt;/span&gt;
/bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# 2. The three tools needed to bootstrap the rest&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;chezmoi bitwarden-cli gh

&lt;span class="c"&gt;# 3. Auth: gh for the private repo, Bitwarden for the secrets&lt;/span&gt;
gh auth login &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; gh auth setup-git
bw login &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BW_SESSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;bw unlock &lt;span class="nt"&gt;--raw&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# 4. Everything else&lt;/span&gt;
chezmoi init &lt;span class="nt"&gt;--apply&lt;/span&gt; gh:&amp;lt;user&amp;gt;/dotfiles
&lt;span class="nb"&gt;exec &lt;/span&gt;zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step two is the whole bootstrap surface: chezmoi, the &lt;a href="https://bitwarden.com/help/cli/" rel="noopener noreferrer"&gt;Bitwarden CLI&lt;/a&gt; and the &lt;a href="https://cli.github.com/" rel="noopener noreferrer"&gt;GitHub CLI&lt;/a&gt;. Step four clones the repo, installs the Brewfile, applies the macOS defaults and renders every dotfile including the secrets. It takes as long as Homebrew takes.&lt;/p&gt;

&lt;p&gt;Day to day it stays out of the way: &lt;code&gt;chezmoi edit ~/.zshrc&lt;/code&gt; to change something, &lt;code&gt;chezmoi diff&lt;/code&gt; to see what would change, &lt;code&gt;chezmoi apply&lt;/code&gt; to commit to it, &lt;code&gt;chezmoi update&lt;/code&gt; on the other machine to pull it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that is still manual
&lt;/h2&gt;

&lt;p&gt;Powerlevel10k needs a &lt;a href="https://www.nerdfonts.com/" rel="noopener noreferrer"&gt;Nerd Font&lt;/a&gt;, and mine is not in the &lt;code&gt;Brewfile&lt;/code&gt; — I installed &lt;a href="https://github.com/romkatv/powerlevel10k/blob/master/font.md" rel="noopener noreferrer"&gt;MesloLGS NF&lt;/a&gt; by hand at some point and never went back. So on a fresh machine the prompt comes up with boxes where the icons should be until I fix it, which is exactly the kind of thing this whole setup is supposed to prevent. It is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;cask&lt;/span&gt; &lt;span class="s2"&gt;"font-meslo-lg-nerd-font"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is a decent summary of how this works in practice. The setup is not finished and never will be; it just gets one line less manual every time something annoys me enough.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marcellomartini.tech/tools/" rel="noopener noreferrer"&gt;See the full toolbox&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This one first appeared on &lt;a href="https://marcellomartini.tech/posts/terminal-from-a-git-clone/" rel="noopener noreferrer"&gt;my site&lt;/a&gt;, where I write about the systems I build and the tools I actually use — &lt;a href="https://marcellomartini.tech/posts/" rel="noopener noreferrer"&gt;the rest of the posts live here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>terminal</category>
      <category>zsh</category>
      <category>dotfiles</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
