You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -33,7 +32,7 @@ import KanvasCTA from "../../../../sections/Kanvas/kanvas-cta";
33
32
<h2>The Surprise</h2>
34
33
35
34
<p>
36
-
AI coding assistants like Claude Code, Cline, Aider, and similar tools spawn child shell processes to run commands on your behalf. From where you sit, the terminal looks identical to the one you use every day. But the shell those tools launch is fundamentally different from the one you interact with — and that difference determines which startup files are read, which means it determines what is on your PATH.
35
+
AI coding assistants like Claude Code, Gemini, Copilot, Cline, Aider, and similar tools spawn child shell processes to run commands on your behalf. From where you sit, the terminal looks identical to the one you use every day. But the shell those tools launch is fundamentally different from the one you interact with — and that difference determines which startup files are read, which means it determines what is on your PATH.
37
36
</p>
38
37
39
38
<p>
@@ -46,7 +45,7 @@ import KanvasCTA from "../../../../sections/Kanvas/kanvas-cta";
46
45
Zsh loads different configuration files depending on how it was launched. There are four main files, and they are read in this order:
47
46
</p>
48
47
49
-
<table>
48
+
<tableclassName="table-2">
50
49
<thead>
51
50
<tr>
52
51
<th>File</th>
@@ -102,9 +101,9 @@ import KanvasCTA from "../../../../sections/Kanvas/kanvas-cta";
102
101
</li>
103
102
</ul>
104
103
105
-
<Blockquote
106
-
quote="A non-interactive, non-login shell sources only ~/.zshenv. Everything in ~/.zshrc is invisible to it — including every PATH export most developers have ever written."
107
-
/>
104
+
<Callouttype="note">
105
+
<p>A non-interactive, non-login shell sources only <code>{"~/.zshenv"}</code>. Everything in <code>{"~/.zshrc"}</code> is invisible to it — including every PATH export most developers have ever written.</p>
106
+
</Callout>
108
107
109
108
<h2>What PATH a Non-Interactive Shell Actually Sees</h2>
110
109
@@ -163,11 +162,9 @@ zsh -i -c 'which node'
163
162
The <code>-i</code> flag forces an interactive shell, which sources <code>{"~/.zshrc"}</code>. If <code>zsh -c 'which gh'</code> prints <code>gh not found</code> but <code>zsh -i -c 'which gh'</code> prints the correct path, your PATH export is in <code>{"~/.zshrc"}</code> and you have confirmed the root cause.
164
163
</p>
165
164
166
-
<divclassName="note">
167
-
<p>
168
-
<strong>Quick diagnosis:</strong> Run <code>zsh -c 'which gh'</code> (no <code>-i</code> flag). If this fails but <code>which gh</code> in your normal terminal works, your PATH is only set in <code>{"~/.zshrc"}</code>. Move the relevant exports to <code>{"~/.zshenv"}</code> to fix it.
169
-
</p>
170
-
</div>
165
+
<Callouttype="note"title="Quick diagnosis">
166
+
<p>Run <code>zsh -c 'which gh'</code> (no <code>-i</code> flag). If this fails but <code>which gh</code> in your normal terminal works, your PATH is only set in <code>{"~/.zshrc"}</code>. Move the relevant exports to <code>{"~/.zshenv"}</code> to fix it.</p>
167
+
</Callout>
171
168
172
169
<h2>The Fix: Move PATH Exports to <code>{"~/.zshenv"}</code></h2>
173
170
@@ -233,10 +230,8 @@ zsh -c 'which node'
233
230
Moving everything to <code>{"~/.zshenv"}</code> is not the right answer. Some configuration should stay in <code>{"~/.zshrc"}</code> because it only makes sense in interactive contexts or because it has side effects that slow down non-interactive shells unnecessarily.
234
231
</p>
235
232
236
-
<divclassName="tip">
237
-
<p>
238
-
<strong>Guiding principle:</strong> If it is an environment variable that a program needs to find another program, it belongs in <code>{"~/.zshenv"}</code>. If it is a user-facing customization for your interactive terminal experience, it belongs in <code>{"~/.zshrc"}</code>.
239
-
</p>
233
+
<Callouttype="tip"title="Guiding principle">
234
+
<p>If it is an environment variable that a program needs to find another program, it belongs in <code>{"~/.zshenv"}</code>. If it is a user-facing customization for your interactive terminal experience, it belongs in <code>{"~/.zshrc"}</code>.</p>
240
235
241
236
<p><strong>Keep in <code>{"~/.zshenv"}</code>:</strong></p>
242
237
<ul>
@@ -256,7 +251,7 @@ zsh -c 'which node'
256
251
<li><code>zsh</code> plugins and plugin managers</li>
257
252
<li>Anything that prints output (welcome messages, <code>neofetch</code>, etc.)</li>
258
253
</ul>
259
-
</div>
254
+
</Callout>
260
255
261
256
<h2>The Broader Pattern: Any Tool That Spawns Subshells</h2>
262
257
@@ -277,11 +272,9 @@ zsh -c 'which node'
277
272
If you have ever fixed a <em>works on my machine</em> problem by adding <code>export PATH=...</code> to a CI configuration or a Dockerfile, you have already solved the same class of problem. The <code>{"~/.zshenv"}</code> fix is just the developer workstation equivalent.
278
273
</p>
279
274
280
-
<Blockquote
281
-
quote="If a command works in your terminal but fails in a script, a CI job, or an AI agent, the first question to ask is: which startup files does this shell read?"
282
-
/>
283
-
284
-
<KanvasCTA />
275
+
<Callouttype="tip">
276
+
<p>If a command works in your terminal but fails in a script, a CI job, or an AI agent, the first question to ask is: which startup files does this shell read?</p>
277
+
</Callout>
285
278
286
279
<h2>Putting It Together: A Minimal <code>{"~/.zshenv"}</code> Template</h2>
0 commit comments