# Contributor handoff — ohmyzsh/ohmyzsh

> Canonical page: https://codevetter.com/unpack/ohmyzsh/agent-handoff

# Contributor handoff — ohmyzsh/ohmyzsh

Scanned commit 86ef6555e068663736a33376e4055aca9c1acc89 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

This is a pure-shell repo: no build step, no package manifest, no unit-test harness wired to CI. The safe edit boundary is 'add or modify files, don't reorder init'. Read oh-my-zsh.sh first (it defines load order and the _omz_source override contract), then the specific lib/ or plugins/ file. Validate changes with `zsh -n` on every touched file — that is literally all CI runs. Mind zsh-only syntax (emulate modes, zstyle, zparseopts, associative arrays), POSIX-sh vs zsh script split (install.sh is sh; upgrade.sh/tools are zsh), and that many variables/hooks are user-facing API you cannot rename.
- Read order for any task: oh-my-zsh.sh (init order, _omz_source, compinit handling) -> templates/zshrc.zsh-template (the user-facing config contract) -> the target lib/*.zsh or plugins/<n>/<n>.plugin.zsh -> CONTRIBUTING.md commit conventions. — [oh-my-zsh.sh](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/oh-my-zsh.sh) [templates/zshrc.zsh-template](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/templates/zshrc.zsh-template) [CONTRIBUTING.md#L172-241](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/CONTRIBUTING.md#L172-L241)
- Never reorder the load sequence in oh-my-zsh.sh: plugin fpath entries must precede compinit, lib files precede plugins, $ZSH_CUSTOM/*.zsh loads last, and the theme loads after everything so it can use lib-defined functions. — [oh-my-zsh.sh#L88-98](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/oh-my-zsh.sh#L88-L98) [oh-my-zsh.sh#L228-264](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/oh-my-zsh.sh#L228-L264)
- tools/install.sh is POSIX sh (#!/bin/sh, run via curl|sh) while tools/upgrade.sh, tools/check_for_upgrade.sh, and tools/changelog.sh are zsh scripts — do not use zsh-isms in install.sh or assume sh semantics in the tools. — [tools/install.sh#L1](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/install.sh#L1) [tools/upgrade.sh#L1-14](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/upgrade.sh#L1-L14) [tools/changelog.sh#L1-3](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/changelog.sh#L1-L3)
- The only CI gate is `zsh -n` over oh-my-zsh.sh, lib/*.zsh, plugins/*/*.plugin.zsh, plugins/*/_*, and themes/*.zsh-theme — replicate it locally before submitting; there is no formatter config for shell (only .prettierrc for docs at 110 cols). — [.github/workflows/main.yml#L35-43](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/.github/workflows/main.yml#L35-L43) [.prettierrc](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/.prettierrc)
- Public API you must not break: plugin/theme/env-var names (ZSH_THEME, plugins, ZSH_CUSTOM, ZSH_CACHE_DIR, DISABLE_*, HIST_STAMPS), zstyle contexts ':omz:...', prompt functions (git_prompt_info, parse_git_dirty, *_prompt_info stubs), and aliases — all are consumed by user dotfiles and external themes/plugins. — [templates/zshrc.zsh-template](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/templates/zshrc.zsh-template) [lib/prompt_info_functions.zsh](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/prompt_info_functions.zsh) [lib/git.zsh#L230-236](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/git.zsh#L230-L236)
- When writing shell that runs at startup, avoid forks and subshells; the codebase caches probes in $ZSH_CACHE_DIR (grep-alias, localhostname, appearance-probes) precisely to avoid per-start process spawns — follow that pattern for new probes. — [lib/grep.zsh](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/grep.zsh) [lib/theme-and-appearance.zsh#L16-38](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/theme-and-appearance.zsh#L16-L38) [oh-my-zsh.sh#L101-127](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/oh-my-zsh.sh#L101-L127)
- Quote % in anything that reaches the prompt: git.zsh escapes % to %% in branch names and upstreams, vcs_info.zsh exists because unquoted hook_com fields enabled command substitution (CVE-2021-45444), and _omz::log sets nopromptsubst for the same reason. — [lib/git.zsh#L49](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/git.zsh#L49) [lib/vcs_info.zsh](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/vcs_info.zsh) [lib/cli.zsh#L137-141](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/cli.zsh#L137-L141)
- Use `command`/`builtin` prefixes for external calls in lib code (diagnostics.zsh documents why: users redefine echo/which), and route git prompt calls through __git_prompt_git so GIT_OPTIONAL_LOCKS=0 is set. — [lib/diagnostics.zsh](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/diagnostics.zsh) [lib/git.zsh#L3-12](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/git.zsh#L3-L12)
- ZDOTDIR is a first-class citizen: all .zshrc-mutating code resolves ${ZDOTDIR:-$HOME}, and the installer picks $ZDOTDIR/ohmyzsh as $ZSH when ZDOTDIR is set and != HOME — replicate this resolution rather than hardcoding ~/.zshrc. — [lib/cli.zsh#L297-299](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/cli.zsh#L297-L299) [tools/install.sh#L82-92](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/install.sh#L82-L92)
- Trap: editing the plugin-enable/disable awk logic means updating two copies — lib/cli.zsh and the duplicated copy inside lib/tests/cli.test.zsh. — [lib/cli.zsh#L250-295](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/cli.zsh#L250-L295) [lib/tests/cli.test.zsh#L9-55](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/tests/cli.test.zsh#L9-L55)
- The devcontainer (.devcontainer/devcontainer.json) symlinks the workspace to ~/.oh-my-zsh and installs templates/minimal.zshrc as ~/.zshrc — the fastest way to smoke-test a change is a new container or `zsh -f` with a minimal zshrc sourcing the repo. — [.devcontainer/devcontainer.json](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/.devcontainer/devcontainer.json) [templates/minimal.zshrc](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/templates/minimal.zshrc)
- New aliases face an explicit bar in CONTRIBUTING.md (used by many, common tasks, prefer generic over specific, don't shadow existing commands), and new themes are currently not accepted at all — check these policies before generating either. — [CONTRIBUTING.md#L93-127](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/CONTRIBUTING.md#L93-L127) [README.md#L65-66](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/README.md#L65-L66)
- Known fragile spots to test manually: compfix/compinit interaction (ZSH_DISABLE_COMPFIX), async prompt registration ordering (_defer_async_git_register must run before _omz_async_request), and the update.lock EXIT trap's $ret propagation for SIGINT. — [oh-my-zsh.sh#L153-164](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/oh-my-zsh.sh#L153-L164) [lib/git.zsh#L193-213](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/git.zsh#L193-L213) [tools/check_for_upgrade.sh#L223-235](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/check_for_upgrade.sh#L223-L235)
- Commit messages must follow Conventional Commits with scope = plugin/theme name (e.g. feat(git):, fix(agnoster):) because tools/changelog.sh parses subjects into the user-facing changelog; '!' marks breaking changes. — [CONTRIBUTING.md#L172-219](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/CONTRIBUTING.md#L172-L219) [tools/changelog.sh](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/changelog.sh)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
