One-off tip

Support checkout

  1. 1 Choose amount
  2. 2 Payment
  3. 3 Thank you

Choose amount

Pick the level of support that feels right. You can keep it simple or enter a custom amount, then continue to secure payment.

Choose a one-off amount
Keeping your zsh config out of Copilot's terminals
Cover image: Two hands reaching toward each other against a pink background — Photo by Igor Omilaev on Unsplash
engineering tooling dotfiles

Keeping your zsh config out of Copilot's terminals

How a single env var separates your shell from the agent's

Published
31 March 2026
Read time
3 min read

If you use GitHub Copilot in VS Code and have a heavily configured zsh with Powerlevel10k, a bunch of aliases, nvm or pyenv hooks, you’ve probably noticed the agent making a mess of its terminal output, or occasionally failing because something in your .zshrc conflicts with what it’s trying to run.

The problem is simple: Copilot spins up non-interactive shells to execute commands. Your .zshrc loads anyway, because that’s what .zshrc does. The agent doesn’t need your prompt theme; it just needs to run git status and get on with its life. Your customisations are noise at best, a source of failures at worst.

Suppressing them without also killing them in your regular VS Code terminal is the tricky part.

The naive fix and why it breaks things

The obvious approach is to skip customisations for all VS Code terminals:

~/.zshrc
if [[ "$TERM_PROGRAM" != "vscode" ]]; then
# load powerlevel10k, aliases, nvm, etc.
fi

VS Code sets TERM_PROGRAM=vscode in every terminal it opens, including the ones you open yourself. So this guard works for the agent, but it also strips your prompt and aliases from your regular integrated terminal. Not what you want.

Why PATH isn’t a reliable signal

The next idea is to detect the Copilot agent via $PATH, since the extension injects its CLI tools into it. The problem: VS Code injects those PATH entries into all terminals, integrated and agent alike. You can’t use it to tell them apart.

The fix: a custom env var

VS Code has a per-platform setting that injects environment variables into terminals the user opens: terminal.integrated.env.osx, terminal.integrated.env.linux, and terminal.integrated.env.windows. Critically, these settings do not apply to terminals that extensions spin up programmatically. This is the clean signal we need.

In VS Code settings.json, add whichever keys match your platform(s):

settings.json
"terminal.integrated.env.osx": { "VSCODE_USER_TERMINAL": "1" },
"terminal.integrated.env.linux": { "VSCODE_USER_TERMINAL": "1" },
"terminal.integrated.env.windows": { "VSCODE_USER_TERMINAL": "1" }

Then in .zshrc, update the guard:

~/.zshrc
if [[ "$TERM_PROGRAM" != "vscode" || -n "$VSCODE_USER_TERMINAL" ]]; then
# load powerlevel10k, aliases, nvm, etc.
fi

The logic reads: load customisations if this is not a VS Code terminal, or if it is one that the user opened (as confirmed by the injected var).

Why this works

TerminalTERM_PROGRAMVSCODE_USER_TERMINALCustomisations load?
Any terminal outside VS Codeapp-specific or unsetunsetYes — first condition passes
VS Code integrated terminalvscode1Yes — second condition passes
Copilot agent terminalvscodeunsetNo — both conditions fail

The key is that terminal.integrated.env.* is a VS Code UI concern: it only kicks in when a human is on the other end of the terminal. Agent terminals bypass it entirely, giving you a reliable, low-friction way to distinguish the two situations.

That’s it

The guard is a single if condition and the env var is harmless to everything else in your environment. Add only the platform keys you need: if you only ever work on macOS, one line is enough.

Working on something similar?

Need help raising the bar?

I help teams improve engineering practice through hands-on delivery, pragmatic reviews, and mentoring. If you want a second pair of eyes or practical support, let's talk.

  • Engineering practice review
  • Hands-on delivery
  • Team mentoring
Get guidance

If this has been useful, you can back the writing with a one-off tip through a secure Stripe checkout.

Comments

Loading comments…

Leave a comment

Free · Practical · One email per post

Get practical engineering notes

One short email when a new article goes live. Useful if you are breaking into tech, growing as an engineer, or improving engineering practice on your team.