<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us">
  <title>kai.dev 📓</title>
  <link href="https://kai.dev/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="https://kai.dev" rel="alternate" type="text/html"/><updated>2025-08-04T00:00:00Z</updated>
  <id>https://kai.dev/</id>
  <author>
    <name>Kai Mallea</name>
  </author>
  <subtitle>⚡ Developer productivity, 💻 software engineering, 🎵 music, and other 🧪 experiments.</subtitle>
  <generator uri="https://www.11ty.dev/" version="3.1.2">Eleventy</generator><entry>
    <title type="html">Effort Is All You Need</title>
    <link href="https://kai.dev/posts/effort-is-all-you-need/" rel="alternate" type="text/html" title="Effort Is All You Need"/>
    <published>2025-07-12T00:00:00Z</published>
    <updated>2025-07-12T00:00:00Z</updated>
    <id>https://kai.dev/posts/effort-is-all-you-need/</id>
    <content type="html">&lt;p class=&quot;has-drop-cap&quot;&gt;The year 2025 is an interesting time to be a software engineer. For better or worse, GenAI continues to disrupt, in all of its equally beneficial and harmful ways that I&#39;ve both witnessed and can foresee. I&#39;m left with conflicting feelings about AI in general that range from optimism to pessimism and everything in-between. How I personally feel about it doesn&#39;t really matter, though. The industry has embraced GenAI and in order for me to compete and stay relevant, I need to elevate my craft and expand my toolbelt to stay on top of my game. This is the case with GenAI, and it will be the case after the next disruption. I already know this. So why haven&#39;t I yet?&lt;/p&gt;
&lt;p&gt;While I have worked on a few experimental GenAI projects internally at Spotify, I did so because I &lt;em&gt;had&lt;/em&gt; to. Sure, it was cool and interesting and new, but I haven&#39;t done much outside of that in my own time. I read into that as a measurement of my interest; if something is not a hobby of mine, I must not be interested 🤷🏾. But I &lt;em&gt;am&lt;/em&gt; interested and I &lt;em&gt;do&lt;/em&gt; want to learn more. I know this because I think about it daily, but what I don&#39;t do daily is take &lt;em&gt;action&lt;/em&gt;. After an honest conversation with myself, the truth is I&#39;ve been stagnant and lazy, often putting blame on my lack of free time. And while free time &lt;em&gt;is&lt;/em&gt; much more limited these days, unless I become wealthy and retire tomorrow, the time constraint ain&#39;t going &lt;em&gt;anywhere&lt;/em&gt;, fam. Not until &lt;em&gt;I&lt;/em&gt; do something about it. I have way too many privileges to be complaining about time.&lt;/p&gt;
&lt;p&gt;Here are three actions I&#39;m already taking:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Therapy. I can get in my own way unconsciously through poor habits. I need an expert with an unbiased perspective, opinion, and no attachments, to tell me the things I won&#39;t or am too afraid to tell myself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This blog. This will be an outlet for me to share thoughts and talk tech. It&#39;s also a public space to hold myself accountable, so I&#39;m not just talking BS.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Effort. Consciously put forth a focused effort into everything that I care about. Such as my relationships with God, my family, my craft, and most importantly myself.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While I&#39;m here on this topic, I want to give a special shout out and thank you to my &lt;strong&gt;beautiful wife&lt;/strong&gt;, &lt;strong&gt;Makeda&lt;/strong&gt;, for all of your &lt;strong&gt;unconditional love and support 😘&lt;/strong&gt;. You&#39;ve always been right by my side, pushing and supporting me to be the best version of myself. Pushing me to create content, encouraging me to share my knowledge from my perspective, because you believe in me and my abilities. &lt;strong&gt;Thank you, I love you!&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Okay, so I started this post talking about GenAI 😅. To get to the standard of understanding that my brain needs to be happy, I need to learn and understand not only how to use it, but also how it works under the hood, so that I can have the intuition to manipulate it, make practical use of it in any context, and hack around it when I need to get creative. This learning process will be fun, enlightening, boring, full of mistakes, and frustrating at times. It will be a grind. So be it. Stay tuned as I document this journey, among other things.&lt;/p&gt;
&lt;h3&gt;Relevant Music&lt;/h3&gt;
&lt;p&gt;This is one of my favorite songs by Big Sean. I feel like it captures the vibe of this post.&lt;/p&gt;
&lt;blockquote&gt;
    &lt;iframe style=&quot;border-radius:12px&quot; src=&quot;https://open.spotify.com/embed/track/2pzuU8vLaG8W1P31X65ZP9&quot; width=&quot;100%&quot; height=&quot;152&quot; frameBorder=&quot;0&quot; allowfullscreen=&quot;&quot; allow=&quot;autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;/blockquote&gt;
</content>
    <author>
      <name>Kai Mallea</name>
    </author>
  </entry><entry>
    <title type="html">Follow the PATH, Part I: Basics</title>
    <link href="https://kai.dev/posts/follow-the-path-part-i-basics/" rel="alternate" type="text/html" title="Follow the PATH, Part I: Basics"/>
    <published>2025-08-03T00:00:00Z</published>
    <updated>2025-08-03T00:00:00Z</updated>
    <id>https://kai.dev/posts/follow-the-path-part-i-basics/</id>
    <content type="html">&lt;p class=&quot;has-drop-cap&quot;&gt;Any time you type a command in your terminal, your shell will try to locate that command on the filesystem. If found, your shell will run the command. Otherwise, you’ll typically see a “command not found” error or similar. You already know this.&lt;/p&gt;
&lt;p&gt;But where exactly is your shell looking for the command? It searches the &amp;quot;list&amp;quot; of the directories specified in your &lt;code&gt;PATH&lt;/code&gt; environment variable:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; echo $PATH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, you probably noticed that the &amp;quot;list&amp;quot; is actually a long string of colon-delimited directories. This is commonly referred to as the &amp;quot;search path.&amp;quot; Your shell will search each directory, in the order that they’re specified, stopping as soon as it finds the command you&#39;re attempting to run.&lt;/p&gt;
&lt;p&gt;This process is what makes it possible to have multiple versions of the same program installed, such as &lt;code&gt;python3&lt;/code&gt;. For example, macOS Tahoe ships with Python &lt;code&gt;3.9&lt;/code&gt; pre-installed to &lt;code&gt;/usr/bin/python3&lt;/code&gt;. But I want to use Python &lt;code&gt;3.12&lt;/code&gt;, so I use my favorite package manager, Homebrew, to &lt;code&gt;brew install python@3.12&lt;/code&gt;. This leaves me with two versions of &lt;code&gt;python3&lt;/code&gt; on my system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/usr/bin/python3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/opt/homebrew/bin/python3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which one will run when I type &lt;code&gt;python3&lt;/code&gt;? You can find out using the &lt;code&gt;which&lt;/code&gt; command:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; which python3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/usr/bin/python3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The outdated, pre-installed version will run because &lt;code&gt;/usr/bin&lt;/code&gt; appears in my search path, and &lt;code&gt;/opt/homebrew/bin&lt;/code&gt; is not present at all, as seen above in my &lt;code&gt;PATH&lt;/code&gt; output.&lt;/p&gt;
&lt;p&gt;To workaround this, you could type the full, absolute path to the newer version:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; /opt/homebrew/bin/python3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Python&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 3.13.5&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (main, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Jun&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 11&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 2025,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 15:36:57&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) [Clang &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;17.0.0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (clang&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1700&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;13&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)] on darwin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;help&quot;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;copyright&quot;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;credits&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;license&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; more&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; information.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The more idiomatic approach is to modify your &lt;code&gt;PATH&lt;/code&gt; environment variable so that &lt;code&gt;/opt/homebrew/bin&lt;/code&gt; is also in the search path. It&#39;s also important to ensure that it appears sooner than &lt;code&gt;/usr/bin&lt;/code&gt;, so that your shell looks there first:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; PATH&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/opt/homebrew/bin:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$PATH&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This takes the existing &lt;code&gt;PATH&lt;/code&gt; value and prepends it with &lt;code&gt;/opt/homebrew/bin&lt;/code&gt;, before assigning the new value back to &lt;code&gt;PATH&lt;/code&gt;. The &lt;code&gt;export&lt;/code&gt; directive makes the updated &lt;code&gt;PATH&lt;/code&gt; value available in any child processes or subshells.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; export&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; PATH&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/opt/homebrew/bin:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$PATH&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; echo $PATH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; which python3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/opt/homebrew/bin/python3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Manually typing it like this is a one-off override for your current shell session only. To persist it so that you don&#39;t need to do this again, put  &lt;code&gt;export PATH=...&lt;/code&gt; in your shell configuration file, such as &lt;code&gt;.bashrc&lt;/code&gt;, &lt;code&gt;.zshrc&lt;/code&gt;, or similar depending on which shell you use.&lt;/p&gt;
&lt;p&gt;Get familiar and comfortable with checking and manipulating your &lt;code&gt;PATH&lt;/code&gt;. Over time, as you install things, your search path will get messy and it&#39;s inevitable that at some point you&#39;ll need to go in and fix it yourself.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;echo&lt;/code&gt; vs &lt;code&gt;printenv&lt;/code&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;echo&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;To see the value of &lt;code&gt;PATH&lt;/code&gt; or any environment variable, most people typically use &lt;code&gt;echo&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; echo $PATH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When using this method, the dollar sign is a special character that tells your shell to replace &lt;code&gt;$PATH&lt;/code&gt; with its literal value. That literal value is then passed as an argument to &lt;code&gt;echo&lt;/code&gt;. As its name implies, &lt;code&gt;echo&lt;/code&gt; simply outputs or echos whatever you pass to it.&lt;/p&gt;
&lt;p&gt;One gotcha is that &lt;code&gt;echo&lt;/code&gt; always returns &lt;code&gt;0&lt;/code&gt; , even if the environment variable doesn’t exist, because echoing nothing is a still valid operation for &lt;code&gt;echo&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; echo $BLAH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; echo &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;$?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, I used &lt;code&gt;$?&lt;/code&gt; to output the return/exit code of the last command. Zero means success, non-zero means failure.&lt;/p&gt;
&lt;p&gt;Still, using &lt;code&gt;echo&lt;/code&gt; is completely fine for quickly inspecting environment variables.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;printenv&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;If you need the value of an environment variable &lt;em&gt;and&lt;/em&gt; you want to validate that there wasn’t an error retrieving it, such as when writing scripts for automation, I would encourage you to use &lt;code&gt;printenv&lt;/code&gt; instead:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; printenv PATH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; echo &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;$?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is no dollar sign, so nothing will be replaced. We are passing the literal string “PATH” to the command &lt;code&gt;printenv&lt;/code&gt;. It will then check that the variable exists (case-sensitive), and if so, returns its value. If not, there will be no output and the return code will be &lt;code&gt;1&lt;/code&gt;, indicating an error retrieving the value.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; printenv BLAH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; echo &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;$?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NOTE: One important caveat is that &lt;code&gt;printenv&lt;/code&gt; can only display environment variables and &lt;code&gt;export&lt;/code&gt;ed variables. To output local variables, you need to use &lt;code&gt;echo&lt;/code&gt;. Some might consider &lt;code&gt;printenv&lt;/code&gt; to be &amp;quot;safer&amp;quot; when you&#39;re checking specifically for environment variables. There &lt;em&gt;are&lt;/em&gt; other ways to test for values using &lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html#Bash-Conditional-Expressions-1&quot;&gt;conditionals expressions&lt;/a&gt;, however, they are similar to &lt;code&gt;echo&lt;/code&gt; in that they can&#39;t distinguish between local and environment/&lt;code&gt;export&lt;/code&gt;ed variables.&lt;/p&gt;
&lt;h2&gt;On Using GenAI to Manage Your PATH&lt;/h2&gt;
&lt;p&gt;Don&#39;t. No matter how good you think your GenAI utility is at managing your shell configuration files, you need to understand how the &lt;code&gt;PATH&lt;/code&gt; works and how to fix it yourself. After you install enough programs, your &lt;code&gt;PATH&lt;/code&gt; &lt;em&gt;will&lt;/em&gt; become messy and contribute to producing unexpected results at some point. No developer can avoid this with GenAI; it&#39;s a human cost. So don&#39;t waste your requests/tokens repairing something that you can easily repair yourself. Lastly, you haven&#39;t even seen the &lt;code&gt;PATH&lt;/code&gt;&#39;s final form (spoiler: I&#39;ll cover Python&#39;s virtual environments in the third post of this series 🙂).&lt;/p&gt;
&lt;h3&gt;Relevant Music&lt;/h3&gt;
&lt;p&gt;You can&#39;t avoid the human cost that must be paid. Learn the fundamentals, follow the &lt;code&gt;PATH&lt;/code&gt;, be more productive.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;iframe style=&quot;border-radius:12px&quot; src=&quot;https://open.spotify.com/embed/track/0utTUirKKwTkhacYSgl2q9?utm_source=generator&quot; width=&quot;100%&quot; height=&quot;152&quot; frameBorder=&quot;0&quot; allowfullscreen=&quot;&quot; allow=&quot;autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;/blockquote&gt;
</content>
    <author>
      <name>Kai Mallea</name>
    </author>
  </entry><entry>
    <title type="html">Follow the PATH, Part 2: Jump Around</title>
    <link href="https://kai.dev/posts/follow-the-path-part-2-jump-around/" rel="alternate" type="text/html" title="Follow the PATH, Part 2: Jump Around"/>
    <published>2025-08-04T00:00:00Z</published>
    <updated>2025-08-04T00:00:00Z</updated>
    <id>https://kai.dev/posts/follow-the-path-part-2-jump-around/</id>
    <content type="html">&lt;p class=&quot;has-drop-cap&quot;&gt;We&#39;re all familiar with using the &lt;code&gt;cd&lt;/code&gt; command to jump around directories. Normally you need to know and type either an absolute path or a relative directory name when using &lt;code&gt;cd&lt;/code&gt;, except for common shortcuts like:
&lt;/p&gt;&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/Users/kai&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cd ./code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/Users/kai/code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cd ..&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/Users/kai&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cd -&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/Users/kai/code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above examples, we jumped &lt;code&gt;$HOME&lt;/code&gt; (aka &lt;code&gt;~&lt;/code&gt;) by providing no arguments, then into an adjacent directory, into the parent directory, and back into the last directory, respectively. What I&#39;ve seen most people do in practice is either manually type most of the path/directory, and then rely on tab completion to cycle through and finish, or they create aliases to use a single command as a shortcut to jump to their favorite directory:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; alias&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;cd ~/code&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/Users/kai/code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These all work, but if you&#39;re like me, you have a hundred directories worth of projects that you navigate in and out of.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;CDPATH&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CDPATH&lt;/code&gt; works similar to &lt;code&gt;PATH&lt;/code&gt; in that you provide a comma-delimited list of directories that become the search path for the &lt;code&gt;cd&lt;/code&gt; command. Let&#39;s look at a practical example to understand the benefits. For this example, assume I keep my projects organized in &lt;code&gt;/Users/kai/code&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;/code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tree&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; alpha&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; beta&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; charlie&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; delta&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; foxtrot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; golf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;└──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; hotel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; directories,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can use &lt;code&gt;CDPATH&lt;/code&gt; to set &lt;code&gt;~/code&lt;/code&gt; as a search path for &lt;code&gt;cd&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CDPATH&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;/code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this set, I can now type &lt;code&gt;cd golf&lt;/code&gt;, from anywhere, and &lt;code&gt;cd&lt;/code&gt; will utilize the search path to look for matching subdirectory names in each of the top-level directories that I provided to &lt;code&gt;CDPATH&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Gotcha&lt;/h3&gt;
&lt;p&gt;In almost all cases, you will want the first directory in your &lt;code&gt;CDPATH&lt;/code&gt; to be the current directory (aka &lt;code&gt;.&lt;/code&gt;) so that you can continue to &lt;code&gt;cd&lt;/code&gt; into relative directories:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CDPATH&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;/code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if I have a subdirectory named &lt;code&gt;golf&lt;/code&gt; in my current working directory, I will &lt;code&gt;cd&lt;/code&gt; into the relative path, &lt;code&gt;./golf&lt;/code&gt;, rather than &lt;code&gt;/Users/kai/code/golf&lt;/code&gt;. But what if I preferred to go to the latter? The next section has the answer.&lt;/p&gt;
&lt;h2&gt;Zoxide (Recommended)&lt;/h2&gt;
&lt;p&gt;Now that you have intuition into how search paths work, I trust that you can fix &lt;code&gt;PATH&lt;/code&gt; issues yourself. Also, you don&#39;t actually need to use &lt;code&gt;CDPATH&lt;/code&gt; directly because there is a more productive solution.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ajeetdsouza/zoxide&quot;&gt;Zoxide&lt;/a&gt; provides the same jumpability benefit as &lt;code&gt;CDPATH&lt;/code&gt; and adds quality of life improvements such as completions, duplicate directory name resolution, and automatic directory tracking so that you don&#39;t ever need to manage any environment variables yourself.&lt;/p&gt;
&lt;p&gt;Install &lt;code&gt;zoxide&lt;/code&gt; and its dependency &lt;code&gt;fzf&lt;/code&gt;, then add the initialization script to your shell config and reload your shell:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; brew install zoxide fzf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;🍺&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  /opt/homebrew/Cellar/zoxide/0.9.8:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 18&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; files,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 1MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;🍺&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  /opt/homebrew/Cellar/fzf/0.65.1:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 19&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; files,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 4.5MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; echo &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;eval &quot;$(zoxide init zsh)&quot;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; &gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; ~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;/.zshrc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; exec zsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, from this point forward, use &lt;code&gt;z&lt;/code&gt; instead of &lt;code&gt;cd&lt;/code&gt;. Zoxide will remember where to jump around to, so that you can recall later even faster. Example:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot; data-lang=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; z golf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;zoxide:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; no&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; match&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; found&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; z &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;/code/golf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/Users/kai/code/golf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; z&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/Users/kai&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; z golf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/Users/kai/code/golf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since installing Zoxide, I haven&#39;t jumped to &lt;code&gt;~/code/golf&lt;/code&gt; before, so using &lt;code&gt;z golf&lt;/code&gt; found no matches. After I &lt;code&gt;z&lt;/code&gt; into the directory myself, Zoxide knows where I&#39;ve been, enabling me to jump back from anywhere via &lt;code&gt;z golf&lt;/code&gt;, or even with a partial word match like &lt;code&gt;z go&lt;/code&gt;. Eventually using something really short like &lt;code&gt;z go&lt;/code&gt; can become ambiguous once you visit any other directories that start with or contain &lt;code&gt;go&lt;/code&gt;. When path matches become similar, &lt;code&gt;Space+Tab&lt;/code&gt; to resolve.&lt;/p&gt;
&lt;p&gt;Here&#39;s a short animated demo, that I &lt;a href=&quot;https://github.com/ajeetdsouza/zoxide/blob/c070535968e04b1b34ff4d025162f5f68fdd7d69/contrib/tutorial.webp&quot;&gt;lifted&lt;/a&gt; directly from the official Zoxide GitHub repo.&lt;/p&gt;
&lt;img src=&quot;https://kai.dev/images/z-tutorial.webp&quot; /&gt;
&lt;h2&gt;Relevant Music&lt;/h2&gt;
&lt;p&gt;Only one song makes sense here. 😅&lt;/p&gt;
&lt;blockquote&gt;
  &lt;iframe style=&quot;border-radius:12px&quot; src=&quot;https://open.spotify.com/embed/track/6JymsaWDHk2Yj4e0yNBIFH?utm_source=generator&quot; width=&quot;100%&quot; height=&quot;152&quot; frameBorder=&quot;0&quot; allowfullscreen=&quot;&quot; allow=&quot;autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt;
&lt;/blockquote&gt;
</content>
    <author>
      <name>Kai Mallea</name>
    </author>
  </entry>
</feed>