OpenCode en het onvolledige PATH: waarom waren je tools niet in de shell van de agent?
Gepubliceerd op 21 April 2026
- De scène: een blinde agent in een wereld van tools
- Anatomie van de bug: twee shells, twee werelden
- De schuldigen: .zshrc vs .zshenv
- Stap-voor-stap diagnose
- De oplossing : .zshenv + de juiste paden
- Het NVM-geval: wanneer de versiebeheerder vergeet een spoor achter te laten
- Overzichtstabel van de paden
- Valkuilen en mitigaties
- Geleerde lessen
- Eindcontrole
- Links
Je start OpenCode in je terminal, alles werkt. De agent probeert een`gh`— niet te vinden. Een`java -version`— afwezig. een`node`— nergens. Desondanks zijn deze tools er gewoon in jouw shell. Het probleem? OpenCode lanceert shellsniet-interactiefdie nooit uw lezen`.zshrc`. Zo kun je dit netjes diagnosticeren en oplossen.
De scène: een blinde agent in een wereld van tools
Het was dinsdagavond. Ik had net geïnstalleerdhttps://opencode.ai[OpenCode], de AI-agent die beloofde mijn manier van coderen te transformeren. Eerste test: hem vragen om mijn GitHub-repositories op te lijsten.
$ opencode
> Utilise gh pour lister mes repos
❌ bash: gh: command not found
Vreemd.`gh`werkte perfect in mijn terminal. Ik probeer iets anders :
> Vérifie la version de Java
❌ bash: java: command not found
Dan :
> Lance le build Gradle
❌ bash: gradle: command not found
Java, Gradle, Node,gh— niets was onzichtbaar voor de agent. Mijn terminal, hij, zag alles. Alsof de agent en ik in twee parallelle werelden leefden.
Ik deed er uren over om te begrijpen. Uren van`echo $PATH`, de which java, van toenemende frustratie. Ik begon te beseffen dat het probleem niet de tools waren — het was deschil. OpenCode, net als elke agent die sub-processen start, werkt in shellsniet-interactief. En Zsh, in deze shells, negeert gewoon uw`.zshrc`.
Dit volgende is het volledige verhaal van deze diagnose, van de oplossing en van de les die ik heb geleerd. Als u een AI-agent gebruikt — OpenCode, Aider, Cursor, of zelfs cron-scripts — zal dit probleem ooit van toepassing zijn op u.
Anatomie van de bug: twee shells, twee werelden
Wanneer je een terminal opent, behandelt Zsh het als een shellinteractief. Hij laadt`.zshrc`, wat alles initialiseert: SDKMAN, NVM, pnpm, de aliassen, je mooie prompt. Je omgeving is compleet.
Maar wanneer OpenCode een opdracht uitvoert, start het geen interactieve terminal. Het start een shell.niet-interactief— een taakshell, zonder mens achter het scherm. En Zsh, in deze context, springt`.zshrc`. Hij leest alleen`.zshenv`.
Waarom bestaat dit onderscheid? Omdat een niet-interactieve shell is ontworpen om scripts uit te voeren, niet om een menselijke gebruiker te dienen. Het laden van aliassen, de prompt en de aanvullingen in een script dat op de achtergrond draait, zou verspilling zijn. Het probleem is dat uw PATH — de belangrijkste informatie om uitvoerbare bestanden te vinden — vaak wordt geïnitialiseerd in`.zshrc`, niet in`.zshenv`.
@startuml skinparam backgroundColor #FEFEFE actor "U" as user actor "OpenCode\n(agent)" as agent participant "Interactieve\nshell\n(.zshrc geladen)" as ishell participant "Niet-interactieve\nshell\n(.zshrc genegeerd)" as nshell user -> ishell : gh, java, node ✅ agent -> nshell : gh, java, node ❌ note right of ishell Bron .zshrc : - SDKMAN init - NVM init - ~/apps in PATH - pnpm in PATH end note note right of nshell .zshrc genegeerd ! PATH = /usr/bin:/bin + enkele standaardmappen end note @enduml
De kern van het probleem :Zsh source .zshrc alleen voor interactieve shells. OpenCode, net als elke IA-agent die subprocessen start, gebruikt niet-interactieve shells. Deze shells lezen alleen`.zshenv`.
De schuldigen: .zshrc vs .zshenv
Zsh heeftvier initialisatiebestanden, elk met een nauwkeurige rol. Het is een elegant ontwerp — maar dat is ook de knoop van het probleem:
| Bestand | Bron wanneer | Rol | Pas het PATH aan? |
|---|---|---|---|
|
Altijd(interactief + niet-interactief + login) |
Essentiële omgevingsvariabelen, PATH |
✅ Ja — het is SA plaats |
|
Alleen login-shells |
Langzame opdrachten (een keer per sessie) |
mogelijk |
|
Alleen interactieve shells |
Alias, prompt, completie, interactieve tools |
❌ Niet voor kritieke variabelen |
|
Inlogshells (na .zshrc) |
Welkomstberichten, afronding |
zelden |
De tabel geeft een aanwijzing, maar je moet het grondig begrijpen. Denk er aan als de kamers van een huis:
-
`.zshenv`is deentreehal— iedereen passeert hier, bezoeker of inwoner. Als je iets hier plaatst, kan elke shell het zien.
-
`.zshrc`is dewoonkamer— alleen de bewoners (interactieve shells) gaan er binnen. De bezoekers (niet-interactieve shells) blijven in de hal.
-
.zprofileet `.zlogin`zijn speciale onderdelen voor login-shells (zoals wanneer je inlogt via SSH).
Het drama is dat de meeste van ons de PATH in de woonkamer plaatsen. En de AI-agent, hij, heeft nooit het recht daar binnen te gaan.
Het probleem in één diagram :
@startuml
skinparam backgroundColor #FEFEFE
start
if (Shell interactif ?) then (Oui)
:Source .zshenv;
:Source .zprofile;
:Source .zshrc;
:Source .zlogin;
note right
SDKMAN ✅
NVM ✅
~/apps ✅
pnpm ✅
end note
else (Non — shell non-interactif)
:Source .zshenv uniquement;
note right
SDKMAN ❌
NVM ❌
~/apps ❌
pnpm ❌
end note
endif
stop
@enduml
Wanneer je een terminal opent, is Zsh interactief: het leest`.zshrc`, alles werkt. Wanneer OpenCode een shell start om een opdracht uit te voeren, is Zsh niet-interactief: het slaat over`.zshrc`, leest alleen`.zshenv`. Et si `.zshenv`bestaat niet of bevat niet het PATH — het is de woestijn.
|
Waarom doet Zsh dat?Dit is een ontwerpkeuze die is overgenomen van Unix. Een niet-interactieve shell moet zijnsnel et reproduceerbaar. Laden van aliases, gekleurde prompts en zware initialisaties van SDKMAN in een cron-script of een IA-agent zou traag en breekbaar zijn. De scheiding is dus logisch :`.zshenv`voor het grootste deel (variabelen, PATH)`.zshrc`voor het comfort (aliases, prompt, vullen aan). Het probleem treedt op wanneer we het essentiële in het comfort plaatsen. |
Stap-voor-stap diagnose
Voordat je corrigeert, moet je begrijpen wat er precies ontbreekt. Hier is een reproduceerbare diagnostische methode — bewaar deze in je favorieten als je werkt met AI-agents.
1. Controleer het PATH van de agent
We vergelijken wat je interactieve terminal ziet met wat een niet-interactieve shell ziet — dat wil zeggen wat OpenCode ziet.
# Dans votre terminal interactif (tout fonctionne)
echo $PATH | tr ':' '\n' | grep -v '^/usr' | sort
Typisch resultaat :
/home/cheroliv/apps
/home/cheroliv/.nvm/versions/node/v22.19.0/bin
/home/cheroliv/.sdkman/candidates/java/current/bin
/home/cheroliv/.sdkman/candidates/gradle/current/bin
/home/cheroliv/.local/share/pnpm
/home/cheroliv/.local/bin
Laten we nu simuleren wat de agent ziet — een niet-interactieve shell:
# Shell non-interactif : pas de .zshrc
zsh -c 'echo $PATH' | tr ':' '\n' | grep -v '^/usr' | sort
Resultaat:
/home/cheroliv/.local/bin
Vijf van de zes paden zijn verdwenen.De agent is voor 83% geamputeerd van zijn omgeving. Het is alsof je wordt gevraagd om te koken zonder de helft van je keukengerei — je zou water kunnen koken, maar niet veel meer.
|
de opdracht`zsh -c 'echo $PATH'`is jouwdiagnosetool nummer 1. Als een tool die je dagelijks gebruikt ontbreekt in het resultaat, kan je IA-agent hem ook niet zien. Test het voor en na elke wijziging van`.zshenv`. |
2. Identificeer wat er in .zshrc zit maar niet in `.zshenv
Nu zoeken we de schuldige in`.zshrc`. We filteren de regels die onze tools vermelden :
grep -n 'apps\|SDKMAN\|NVM\|PNPM\|PATH' ~/.zshrc
Men vindt typisch:
119: PATH="/usr/bin/python3:$HOME/apps:$PATH" # ← pas exporté !
171: export NVM_DIR="$HOME/.nvm"
172: [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # ← NVM init
176: nvm use --lts --silent # ← active une version
179: export PNPM_HOME="/home/cheroliv/.local/share/pnpm"
187: export SDKMAN_DIR="$HOME/.sdkman"
188: [[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"
Dit alles isonzichtbaarvoor OpenCode. En het`PATH`van regel 119 is zelfs niet`export`é — het verlaat nooit de huidige shell. Dit is een cruciaal technisch detail: een variabele zonder`export`blijft lokaal bij de shell die het definieert. Subshells — zoals die gestart worden door OpenCode — erven het nooit.
3. Controleren of .zshenv bestaat
cat ~/.zshenv 2>/dev/null || echo "FICHIER ABSENT"
Als het antwoord « FICHIER ABSENT » is, daar wordt alles beslist.
De oplossing : .zshenv + de juiste paden
De strategie is eenvoudig, maar ze vraagt om precisie: plaatsen in`.zshenv` alleende essentiële paden, zonder de zware initialisatiescripts te bronnen. Men verplaatst niet`.zshrc`in`.zshenv`— we halen de essentie.
Maak .zshenv met alle essentiële paden
`.zshenv`is deenkel bestanddat Zsh garandeert om te sourcer inallede contexten. Dit is waar de PATH naartoe moet.
export SDKMAN_DIR="$HOME/.sdkman"
export NVM_DIR="$HOME/.nvm"
export PNPM_HOME="$HOME/.local/share/pnpm"
export PATH="$HOME/apps:$HOME/.sdkman/candidates/java/current/bin:$HOME/.sdkman/candidates/gradle/current/bin:$HOME/.nvm/current/bin:$PNPM_HOME:$HOME/.local/bin:$HOME/.local/share/JetBrains/Toolbox/scripts:/usr/bin/python3:$PATH"
|
We gebruiken`$HOME/.nvm/current/bin`en niet`$HOME/.nvm/versions/node/v22.19.0/bin`. De reden: de Node-versies veranderen. Een hard gecodeerd pad wordt onjuist bij het volgende`nvm install`. Meer details in de volgende sectie. |
Waarom niet source sdkman-init.sh in .zshenv ?
De meest verleidelijke benadering zou zijn om eenvoudigweg te reproduceren in`.zshenv`wat we doen in`.zshrc`— de initialisatiescripts ophalen. Onzou kunnenverleed zijn om te doen :
# ❌ MAUVAISE IDÉE
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"
Problemen :
-
traag : `sdkman-init.sh`voert netwerkresoluties en controles uit bij elke shell. In een niet-interactieve shell is het een onnodige kosten.
-
Fragiel: SDKMAN verwacht een interactieve context. De initialisatie kan stil falen in een pijpleiding of een subshell.
-
Nutteloos: SDKMAN plaatst zijn kandidaten in`~/.sdkman/candidates/<tool>/current/bin`— stabiele symlinks die naar de actieve versie wijzen. Men kan ze gebruikenrechtstreeks.
De juiste aanpak: de initialisatie van SDKMAN omzeilen en direct naar de symlinks wijzen`current`. Dit is de sleutel van de hele oplossing :gebruik de bestandsstructuur als contract, in plaats van de initialisatiecode.
@startuml
skinparam backgroundColor #FEFEFE
rectangle "Benadering LENTE\n(source sdkman-init.sh)" as slow {
card ".zshenv source sdkman-init.sh\n2-3 seconden per shell\nNetwerkcontroles\nRisico op falen" as s1 #FDEDEC
}
rectangle "Benadering RAPIDE\n(directe symlinks)" as fast {
card ".zshenv export PATH=...current/bin\n0 ms\nGeen netwerk\nGeen initialisatie" as s2 #E8F8E8
}
slow --> fast : zelfde eindresultaat\nLe PATH wijst op current/bin\nin de twee gevallen
@enduml
Het NVM-geval: wanneer de versiebeheerder vergeet een spoor achter te laten
Het probleem NVM
Hier heeft het onderzoek mij het verst gebracht. SDKMAN heeft een elegant ontwerp: wanneer men`sdk install java 25.0.2-tem`, hij maakt een symlink aan :
~/.sdkman/candidates/java/current -> ~/.sdkman/candidates/java/25.0.2-tem
Deze symlink isaltijd up-to-date. Point erop in`.zshenv`en je bent gedekt, welk shell het ook is. Mooi.
NVM, hij, creëert nietnietsvan tel. Geen symlink`current`. Geen stabiel ankerpunt. We moeten wijzen op een hardgecodeerde versiepad, dat er zo uitziet:
~/.nvm/versions/node/v22.19.0/bin/node
bij de volgende`nvm install 24`, dit pad is dood. uw`.zshenv`Het zal wijzen naar een versie die niet langer de actieve versie is. Dat is een tijdbom.
|
Waarom doet NVM dat?NVM werkt door de PATH dynamisch bij elke`nvm use`. Het is ontworpen voor ontwikkelaars die vaak van versie wisselen, in een interactieve shell. De symlink`current`was niet in de initiële specificaties — het is een ontwerpfout die wij zelf gaan corrigeren |
@startuml
skinparam backgroundColor #FEFEFE
package "SDKMAN ✅" {
[~/.sdkman/candidates/java/current] as sdk_current
[~/.sdkman/candidates/java/25.0.2-tem/] as java_25
[~/.sdkman/candidates/java/21.0.7-tem/] as java_21
sdk_current --> java_25 : symlink
}
package "NVM ❌ (voor correctie)" as nvm_before {
[~/.nvm/versions/node/v22.19.0/] as node_22
[~/.nvm/versions/node/v20.16.0/] as node_20
note right of node_22
Geen symlink current!
.zshenv moet hardcoded verwijzen
Kapot bij de volgende nvm install
end note
}
package "NVM ✅ (na correctie)" as nvm_after {
[~/.nvm/current] as nvm_current
[~/.nvm/versions/node/v22.19.0/] as node_22b
[~/.nvm/versions/node/v20.16.0/] as node_20b
nvm_current --> node_22b : symlink\n(mis à jour auto)
}
@enduml
De oplossing: het symlink current aanmaken voor NVM
Aangezien NVM het niet doet, doen we het zelf. Het principe is hetzelfde als SDKMAN — een symlink`current`Het wijst altijd naar de actieve versie. We maken het één keer aan, en automatiseren het vervolgens zodat het zichzelf up-to-date houdt.
# Créer le symlink initial
ln -sfn "$HOME/.nvm/versions/node/v22.19.0" "$HOME/.nvm/current"
Nu, in`.zshenv`, men gebruikt :
$HOME/.nvm/current/bin
In plaats van:
# ❌ Chemin en dur — cassé au prochain changement de version
$HOME/.nvm/versions/node/v22.19.0/bin
Automatiseren de update van de symlink
Een symlink is niets waard als hij niet wordt bijgewerkt. De symlink`current`moet zich bijwerken wanneer men doet`nvm use` ou nvm install. De oplossing: eenomhulsel— een functie die de echte opdracht omhulst`nvm`en werkt de symlink bij na elke aanroep.
# À la fin de .zshrc, APRÈS le chargement de NVM
nvm use --lts --silent
ln -sfn "$(nvm_version_path "$(nvm current)")" "$NVM_DIR/current"
_nvm() {
command nvm "$@"
local rc=$?
ln -sfn "$(nvm_version_path "$(nvm current)")" "$NVM_DIR/current"
return $rc
}
alias nvm='_nvm'
Hoe het werkt, in detail:
@startuml skinparam backgroundColor #FEFEFE actor Développeur participant "nvm wrapper\n(_nvm)" as wrapper participant "echte nvm\n(commando nvm)" as realnvm participant "~/.nvm/current\n(symlink)" as symlink Développeur -> wrapper : nvm use 20 wrapper -> realnvm : command nvm use 20 realnvm --> wrapper : version activée wrapper -> symlink : ln -sfn .../v20.16.0 ~/.nvm/current wrapper --> Développeur : retour note right of symlink Altijd up-to-date! Gebruikt door `.zshenv` → toegankelijk via OpenCode end note @enduml
De wrapper`_nvm`roept de echte opdracht`nvm`, werkt vervolgens de symlink bij. Het alias`nvm='_nvm'`Zorg ervoor dat bij het typen`nvm`, we gaan via de wrapper. En bij de initialisatie van de shell, doen we hetzelfde daarna`nvm use --lts`.
|
`nvm_version_path`Dit is een interne functie van NVM die het volledige pad van een versie bepaalt. Het voorkomt dat je het pad handmatig hoeft op te bouwen. |
Overzichtstabel van de paden
Voordat je overgaat op de vallen, een visueel overzicht van de transformatie. Aan de linkerkant, wat je had (alles in`.zshrc`, onzichtbaar voor de agent). Aan de rechterkant, wat je nu hebt (de essentiële paden in`.zshenv`, overal zichtbaar).
| gereedschap | Voor (.zshrc alleen) | Na (.zshenv + symlink) | Zichtbaar door OpenCode? |
|---|---|---|---|
|
PATH niet geëxporteerd in .zshrc |
`$HOME/apps`in .zshenv |
✅ |
SDKMAN Java |
`sdkman-init.sh`gebronst in .zshrc |
`$HOME/.sdkman/candidates/java/current/bin`in .zshenv |
✅ |
SDKMAN Gradle |
`sdkman-init.sh`gebaseerd op .zshrc |
`$HOME/.sdkman/candidates/gradle/current/bin`in .zshenv |
✅ |
NVM Node |
`nvm use --lts`in .zshrc |
`$HOME/.nvm/current/bin`in .zshenv (symlink) |
(Empty) |
pnpm |
`$PNPM_HOME`in .zshrc |
`$PNPM_HOME`in .zshenv |
✅ |
JetBrains Toolbox |
Automatisch toegevoegd door Toolbox in .zshrc |
`$HOME/.local/share/JetBrains/Toolbox/scripts`in .zshenv |
[The translated text is empty, as no French text was provided to translate.] |
Python 3 |
`/usr/bin/python3`in PATH .zshrc |
Expliciet in .zshenv |
✅ |
Valkuilen en mitigaties
Niet alles is perfect met deze aanpak. Dit zijn de problemen die ik heb tegengekomen, en hoe je ze kunt omzeilen.
| val | Beschrijving | Mitigatie |
|---|---|---|
gedupliceerde PATH |
Als .zshenv en .zshrc dezelfde pad toevoegen, verschijnt het twee keer |
`.zshenv`is afkomstigvoor.zshrc. Beide worden gelezen in een interactieve shell. PATH kan dupliceren. Het is cosmetisch, niet functioneel. Om dit te voorkomen: plaats alleen die paden in .zshenv die afwezig zijn in de standaard PATH. |
NVM: hardcoded versie in .zshenv |
zetten`~/.nvm/versions/node/v22.19.0/bin`hardgecodeerd wordt onwaar bij het volgende`nvm install` |
Gebruik de symlink`$HOME/.nvm/current/bin`+ de wrapper`_nvm`in .zshrc |
SDKMAN : source sdkman-init.sh in .zshenv |
Langzaam, fragiel, nutteloos in een niet-interactieve shell |
Gebruik de symlinks`candidates/<tool>/current/bin`direct |
Ontbrekende alias na wijziging |
De wrapper`nvm='_nvm'`in .zshrc heeft pas effect na herladen |
Herstart de shell of`source ~/.zshrc` |
OpenCode ziet de wijzigingen niet |
De agent heeft al zijn subshells gelanceerd met het oude .zshenv |
Herstart OpenCode na wijziging van .zshenv |
.zshenv te zwaar |
Plaats zware functies of interactieve initialisaties in .zshenv |
.zshenv = omgevingsvariabelen + PATH alleen. Geen`source`, geen zware functies, geen prompts. |
Geleerde lessen
-
.zshrc` is interactief,
.zshenvis universeel— Als een variabele in alle shells (AI-agents, cron, scripts, IDE) moet bestaan, gaat deze naar`.zshenv`. De woonkamer is comfortabel, maar de entreehal is de enige plek waar iedereen passeert. -
Versiebeheerders zijn niet gelijk— SDKMAN maakt symlinks`current`per ontwerp. NVM niet. Je moet dit tekort handmatig opvullen. Dit is een belangrijke les: voordat je je PATH configureert, controleer of je pakketbeheerder een vast ankerpunt biedt.
-
Bron de init-scripts niet in .zshenv—
sdkman-init.shet `nvm.sh`zijn ontworpen voor een interactieve shell. Ze zijn traag en breekbaar in een niet-interactieve context. De symlinks`current`zijn voldoende en zijn onmiddellijk -
Altijd testen in een niet-interactieve shell—`zsh -c 'echo $PATH'`simuleert exact wat een agent ziet. Dit is de validatietest. Zonder deze test weet je niet of je configuratie werkt voor de agents.
-
Het wrapper-patroon is herbruikbaar— Hetzelfde patroon`_nvm`+`alias nvm='_nvm'`Is van toepassing op elke tool die de PATH dynamisch wijzigt zonder een stabiele spoor achter te laten. Het is een extra tool in jouw ideeënbak.
@startuml
skinparam backgroundColor #FEFEFE
rectangle "VOOR" as avant {
card "Interactieve shell: ✅\nNiet-interactieve shell: ❌\nOpenCode: ❌\nCron: ❌\nScripts: ❌" as av1 #FDEDEC
}
rectangle "NA" as apres {
card "Interactieve shell: ✅\nNiet-interactieve shell: ✅\nOpenCode: ✅\nCron: ✅\nScripts: ✅" as ap1 #E8F8E8
}
avant --> apres : .zshenv +\nsymlink ~/.nvm/current
@enduml
Eindcontrole
Na het maken`.zshenv`en de NVM symlink, controleer of alles werkt — in de twee contexten:
# Shell interactif (votre terminal)
gh --version && java -version && node --version
# Shell non-interactif (simulation OpenCode)
zsh -c 'gh --version && java -version && node --version'
Beide moeten slagen. Als ja, ziet uw IA-agent dezelfde tools als u. Als nee, ga terug naar de stap-voor-stapdiagnose — u bent waarschijnlijk een pad vergeten of de NVM-symlink is niet up-to-date.
|
Automatiseer deze test.Voeg deze controle toe in een healthcheck-script dat u uitvoert na elke update van uw tools. Een`zsh -c 'which java && which node && which gh'`in CI, het is een waarborg tegen verrassingen |
Hallo `world Een niet-interactieve shell is als een stille gast: hij leest alleen wat op de voordeur wordt weergegeven. Als de PATH in de woonkamer staat, zal hij het nooit zien. __
Links
Officiële documentatie
-
Zsh documentatie : opstartbestanden— De officiële referentie over de initialisatiebestanden van Zsh. Dit is waar alles wordt uitgelegd, zelfs als het vaak wordt vergeten.
-
OpenCode : configuratie— Hoe configureer je OpenCode en zijn runtime-omgeving.
Genoemde tools
-
NVM op GitHub— Node Version Manager. Beheerder van Node.js-versies.
-
SDKMAN — officiële site— SDKMAN! De versiebeheerder voor de JVM (Java, Kotlin, Gradle…)
-
SDKMAN : installatie— SDKMAN installatiegids.
-
gh` — GitHub CLI— De GitHub-opdrachtregeltool, onmisbaar voor elke ontwikkelaar.
-
Gradle — officiële site— Het buildsysteem dat we via SDKMAN installeren.
-
pnpm — officiële site— De snelle en ruimtezuinige Node.js-pakketbeheerder.
-
JetBrains Toolbox— De JetBrains IDE-beheerder, die zijn scripts toevoegt aan de PATH.
Verder gaan
-
Zsh dotfiles: een volledige gids— Diepgaand artikel over het beheren van Zsh dotfiles.
-
Zsh op ArchWiki— Een van de beste communitydocumentaties over Zsh.
-
NVM issues GitHub— Om de discussies rond de symlink te zien`current`en problemen met PATH.