From deb3472900880d336959990e3e70374de7c1c60b Mon Sep 17 00:00:00 2001
From: Sal <59910950+ss-o@users.noreply.github.com>
Date: Sat, 19 Sep 2026 04:11:56 +0100
Subject: [PATCH 1/5] docs(installation): add an Agent tab for AI coding agents
installing Zi
Add an Agent tab beside the existing automated-setup tabs with the two supported non-interactive installer invocations (`-a loader`, and `-i skip` for install-only), the rules an agent must follow (drive the installer, never edit `.zshrc` or the configuration home, respect `ZDOTDIR` and absolute `XDG_*` values, no root, no interactive shell during installation, stop on installer refusals), verification for each profile, and a copyable instruction block that names the planned `zi-install` skill.
The tab documents the installer as it is on z-shell/src main after #210 and #214; the planner from ADR-0025 (z-shell/src#208) is not mentioned until it ships.
Closes #921
---
docs/getting_started/01_installation.mdx | 60 ++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/docs/getting_started/01_installation.mdx b/docs/getting_started/01_installation.mdx
index a9f450d8..aea21720 100644
--- a/docs/getting_started/01_installation.mdx
+++ b/docs/getting_started/01_installation.mdx
@@ -6,6 +6,7 @@ image: /img/png/theme/z/320x320.png
description: Installation Guide
keywords:
- install
+ - agent
---
import Tabs from "@theme/Tabs";
@@ -84,6 +85,65 @@ Install and include minimal configuration with recommended
+
+
+Let an AI coding agent install Zi through the installer, never by editing .zshrc by hand. Copy the instruction block at the end of this tab into the agent's prompt, or point the agent at this tab.
+
+The machine needs zsh, git, and curl or wget. Two profiles are supported for agents. Both run without a terminal and read nothing from standard input.
+
+Loader profile: installs Zi, places the [loader](#loader) in the configuration home, and appends the loader snippet to .zshrc:
+
+```sh
+sh -c "$(curl -fsSL get.zshell.dev)" -- -a loader
+```
+
+Install only: clones Zi into its home and leaves .zshrc untouched, for setups where the user integrates Zi later:
+
+```sh
+sh -c "$(curl -fsSL get.zshell.dev)" -- -i skip
+```
+
+Rules the agent must follow:
+
+- Drive the installer with its flags (`-a loader`, `-i skip`, `-b `). Do not write to .zshrc or to the Zi configuration home yourself. The installer owns the integration block, detects an existing one, and a rerun appends nothing.
+- Respect the user's environment. The installer edits `${ZDOTDIR:-$HOME}/.zshrc` and honours `XDG_CONFIG_HOME` and `XDG_DATA_HOME` only when their values are absolute paths. Do not export new values to force a location, and do not set `ZI_HOME` unless the user asked for a specific root.
+- Run as the user who owns the shell. Never run the installer as root or through sudo: the checkout then lands in root's home, or leaves root-owned files that the user's shell cannot update.
+- Do not start an interactive shell while installing (`exec zsh`, `zsh -i`, or `zsh -l`). The installer needs none, and a shell that waits for a prompt blocks the agent. Verification below uses one fresh `zsh -ic` invocation that exits on its own.
+- Stop and report when the installer refuses or skips: an existing Zi integration was detected, the checkout cannot be fast-forwarded (the installer prints `git status` and leaves the checkout untouched), or the `-b` value is not a valid branch name. Do not work around these by editing files.
+
+Verify the loader profile with a fresh shell. Both conditions must hold: `zi` is defined, and `zzinit` is gone, because the loader removes `zzinit` and its helpers only after a successful run:
+
+```zsh
+zsh -ic 'zi -h' >/dev/null && echo "zi ok"
+zsh -ic '(( ${+functions[zi]} && ! ${+functions[zzinit]} )) && print "loader ok" || { print -u2 "zzinit did not complete"; exit 1 }'
+```
+
+Verify the install-only profile with the path the installer printed after `Successfully installed at`, since it may be a legacy ~/.zi, an explicit `ZI_HOME`, or the XDG data home:
+
+```zsh
+zsh -f -c 'builtin source "$1" && zi -h' zsh "/zi.zsh" >/dev/null && echo "zi ok"
+```
+
+Hand this block to the agent. It points at the zi-install skill, the machine-readable companion of this tab, tracked in [z-shell/.github#636](https://github.com/z-shell/.github/issues/636) until it is published:
+
+```text title="Instructions for the agent"
+Install the Zi plugin manager for Zsh on this machine.
+
+- Use only the official installer, non-interactively:
+ sh -c "$(curl -fsSL get.zshell.dev)" -- -a loader
+ Use "-- -i skip" instead if I asked for install-only. Add "-b " only if I named a branch.
+- Never write to ~/.zshrc, $ZDOTDIR/.zshrc, or the Zi configuration home yourself. The installer owns them.
+- Run as my user, never as root or with sudo. Keep my ZDOTDIR, XDG_CONFIG_HOME, and XDG_DATA_HOME as they are; do not set ZI_HOME unless I asked.
+- Do not start an interactive shell (exec zsh, zsh -i, zsh -l) while installing.
+- If the installer refuses or reports an existing integration, stop and show me its message. Do not edit files to work around it.
+- When done, verify with a fresh shell and show me the output:
+ zsh -ic 'zi -h' >/dev/null && echo "zi ok"
+ zsh -ic '(( ${+functions[zi]} && ! ${+functions[zzinit]} )) && print "loader ok" || { print -u2 "zzinit did not complete"; exit 1 }'
+ For install-only, source /zi.zsh in "zsh -f -c" and run "zi -h" instead.
+- Reference: https://wiki.zshell.dev/docs/getting_started/installation (Agent tab). If the zi-install skill from z-shell/.github is available, follow it.
```
From 200ba80b8f864cec265e6878585e591e4278e2cf Mon Sep 17 00:00:00 2001
From: Sal <59910950+ss-o@users.noreply.github.com>
Date: Sat, 19 Sep 2026 04:57:49 +0100
Subject: [PATCH 2/5] docs(installation): fetch the installer to a file and
accept the update message in the Agent tab
Address the Copilot review on #922. The Agent tab now downloads the installer with curl or wget to a file, compares its sha256 with the published checksum, and runs the file, so a failed download exits non-zero instead of handing an empty script to sh. The environment rule tells the agent to stop on a relative ZDOTDIR or ZI_HOME, since the installer changes directory before using them. Install-only verification accepts the checkout directory printed by either the fresh-install or the update path and states that it already includes the bin checkout name. The copyable instruction block carries the same changes.
---
docs/getting_started/01_installation.mdx | 32 ++++++++++++++++--------
1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/docs/getting_started/01_installation.mdx b/docs/getting_started/01_installation.mdx
index aea21720..4b42f2ea 100644
--- a/docs/getting_started/01_installation.mdx
+++ b/docs/getting_started/01_installation.mdx
@@ -92,24 +92,32 @@ sh -c "$(curl -fsSL get.zshell.dev)" -- -a zunit
Let an AI coding agent install Zi through the installer, never by editing .zshrc by hand. Copy the instruction block at the end of this tab into the agent's prompt, or point the agent at this tab.
-The machine needs zsh, git, and curl or wget. Two profiles are supported for agents. Both run without a terminal and read nothing from standard input.
+The machine needs zsh, git, and curl or wget. Fetch the installer to a file first. A failed download then stops with a non-zero exit instead of handing an empty script to sh, and the file can be checked against the published [checksum][checksum-txt] before it runs:
+
+```sh
+curl -fsSL https://get.zshell.dev -o zi-install.sh # or: wget -qO zi-install.sh https://get.zshell.dev
+curl -fsSL https://raw.githubusercontent.com/z-shell/src/main/public/checksum.txt | grep 'public/sh/install.sh$'
+sha256sum zi-install.sh # macOS: shasum -a 256 zi-install.sh
+```
+
+The two hashes must match. Then run one of the two supported profiles. Both run without a terminal and read nothing from standard input.
Loader profile: installs Zi, places the [loader](#loader) in the configuration home, and appends the loader snippet to .zshrc:
```sh
-sh -c "$(curl -fsSL get.zshell.dev)" -- -a loader
+sh zi-install.sh -a loader
```
Install only: clones Zi into its home and leaves .zshrc untouched, for setups where the user integrates Zi later:
```sh
-sh -c "$(curl -fsSL get.zshell.dev)" -- -i skip
+sh zi-install.sh -i skip
```
Rules the agent must follow:
- Drive the installer with its flags (`-a loader`, `-i skip`, `-b `). Do not write to .zshrc or to the Zi configuration home yourself. The installer owns the integration block, detects an existing one, and a rerun appends nothing.
-- Respect the user's environment. The installer edits `${ZDOTDIR:-$HOME}/.zshrc` and honours `XDG_CONFIG_HOME` and `XDG_DATA_HOME` only when their values are absolute paths. Do not export new values to force a location, and do not set `ZI_HOME` unless the user asked for a specific root.
+- Respect the user's environment. The installer edits `${ZDOTDIR:-$HOME}/.zshrc` and honours `XDG_CONFIG_HOME` and `XDG_DATA_HOME` only when their values are absolute paths. Do not export new values to force a location, and do not set `ZI_HOME` unless the user asked for a specific root. If `ZDOTDIR` or `ZI_HOME` is set to a relative path, stop and ask: the installer changes directory before it uses them.
- Run as the user who owns the shell. Never run the installer as root or through sudo: the checkout then lands in root's home, or leaves root-owned files that the user's shell cannot update.
- Do not start an interactive shell while installing (`exec zsh`, `zsh -i`, or `zsh -l`). The installer needs none, and a shell that waits for a prompt blocks the agent. Verification below uses one fresh `zsh -ic` invocation that exits on its own.
- Stop and report when the installer refuses or skips: an existing Zi integration was detected, the checkout cannot be fast-forwarded (the installer prints `git status` and leaves the checkout untouched), or the `-b` value is not a valid branch name. Do not work around these by editing files.
@@ -121,10 +129,10 @@ zsh -ic 'zi -h' >/dev/null && echo "zi ok"
zsh -ic '(( ${+functions[zi]} && ! ${+functions[zzinit]} )) && print "loader ok" || { print -u2 "zzinit did not complete"; exit 1 }'
```
-Verify the install-only profile with the path the installer printed after `Successfully installed at`, since it may be a legacy ~/.zi, an explicit `ZI_HOME`, or the XDG data home:
+Verify the install-only profile with the checkout directory the installer printed: after `Successfully installed at` on a fresh install, or after `Updating (z-shell/zi) plugin manager at` on a rerun. Do not guess it, since it may be a legacy ~/.zi, an explicit `ZI_HOME`, or the XDG data home, and the printed directory already includes the `bin` checkout name:
```zsh
-zsh -f -c 'builtin source "$1" && zi -h' zsh "/zi.zsh" >/dev/null && echo "zi ok"
+zsh -f -c 'builtin source "$1" && zi -h' zsh "/zi.zsh" >/dev/null && echo "zi ok"
```
Hand this block to the agent. It points at the zi-install skill, the machine-readable companion of this tab, tracked in [z-shell/.github#636](https://github.com/z-shell/.github/issues/636) until it is published:
@@ -132,17 +140,19 @@ Hand this block to the agent. It points at the zi-install skill, the
```text title="Instructions for the agent"
Install the Zi plugin manager for Zsh on this machine.
-- Use only the official installer, non-interactively:
- sh -c "$(curl -fsSL get.zshell.dev)" -- -a loader
- Use "-- -i skip" instead if I asked for install-only. Add "-b " only if I named a branch.
+- Download the official installer to a file and verify it before running it:
+ curl -fsSL https://get.zshell.dev -o zi-install.sh (or: wget -qO zi-install.sh https://get.zshell.dev)
+ Compare the file's sha256 with the public/sh/install.sh line of https://raw.githubusercontent.com/z-shell/src/main/public/checksum.txt and stop if they differ.
+- Run it non-interactively: sh zi-install.sh -a loader
+ Use "-i skip" instead if I asked for install-only. Add "-b " only if I named a branch.
- Never write to ~/.zshrc, $ZDOTDIR/.zshrc, or the Zi configuration home yourself. The installer owns them.
-- Run as my user, never as root or with sudo. Keep my ZDOTDIR, XDG_CONFIG_HOME, and XDG_DATA_HOME as they are; do not set ZI_HOME unless I asked.
+- Run as my user, never as root or with sudo. Keep my ZDOTDIR, XDG_CONFIG_HOME, and XDG_DATA_HOME as they are; do not set ZI_HOME unless I asked. If ZDOTDIR or ZI_HOME is set to a relative path, stop and ask me.
- Do not start an interactive shell (exec zsh, zsh -i, zsh -l) while installing.
- If the installer refuses or reports an existing integration, stop and show me its message. Do not edit files to work around it.
- When done, verify with a fresh shell and show me the output:
zsh -ic 'zi -h' >/dev/null && echo "zi ok"
zsh -ic '(( ${+functions[zi]} && ! ${+functions[zzinit]} )) && print "loader ok" || { print -u2 "zzinit did not complete"; exit 1 }'
- For install-only, source /zi.zsh in "zsh -f -c" and run "zi -h" instead.
+ For install-only, source zi.zsh from the directory the installer printed ("Successfully installed at" or "Updating ... at") in "zsh -f -c" and run "zi -h" instead.
- Reference: https://wiki.zshell.dev/docs/getting_started/installation (Agent tab). If the zi-install skill from z-shell/.github is available, follow it.
```
From c5ba9351f3cd6489507a08c577f080323fcf3b7e Mon Sep 17 00:00:00 2001
From: Sal <59910950+ss-o@users.noreply.github.com>
Date: Sat, 19 Sep 2026 05:26:47 +0100
Subject: [PATCH 3/5] docs(installation): align the Agent tab with the
published zi-install skill
z-shell/.github#637 and #638 published the zi-install skill while #922 was open. Link the tab and the copyable block to the skill instead of the tracking issue, adopt its fetch, verify, and run sequence with an exact checksum comparison, its reading of the installer's result lines, and its positive loader probe: sourcing the installed init.zsh in a clean shell, running zzinit, and requiring every loader helper to be removed. The earlier check passed for a pre-existing direct integration without the loader ever running.
---
docs/getting_started/01_installation.mdx | 69 ++++++++++++++----------
1 file changed, 42 insertions(+), 27 deletions(-)
diff --git a/docs/getting_started/01_installation.mdx b/docs/getting_started/01_installation.mdx
index 4b42f2ea..28dcb957 100644
--- a/docs/getting_started/01_installation.mdx
+++ b/docs/getting_started/01_installation.mdx
@@ -90,70 +90,84 @@ sh -c "$(curl -fsSL get.zshell.dev)" -- -a zunit
-Let an AI coding agent install Zi through the installer, never by editing .zshrc by hand. Copy the instruction block at the end of this tab into the agent's prompt, or point the agent at this tab.
+Let an AI coding agent install Zi through the installer, never by editing .zshrc by hand. The [zi-install skill][zi-install-skill] in z-shell/.github is the machine-readable form of this tab: agents with skill support can install it with `gh skill install z-shell/.github .github/skills/zi-install --dir .github/skills`, and every other agent gets the instruction block at the end of this tab.
-The machine needs zsh, git, and curl or wget. Fetch the installer to a file first. A failed download then stops with a non-zero exit instead of handing an empty script to sh, and the file can be checked against the published [checksum][checksum-txt] before it runs:
+The machine needs zsh, git, and curl or wget. Fetch the installer to a file, verify the file, then run it. Do not use `sh -c "$(curl ...)"` on a user's behalf: a failed fetch inside the substitution becomes an empty script that still exits 0, and an existing installation then passes verification although nothing ran.
```sh
-curl -fsSL https://get.zshell.dev -o zi-install.sh # or: wget -qO zi-install.sh https://get.zshell.dev
-curl -fsSL https://raw.githubusercontent.com/z-shell/src/main/public/checksum.txt | grep 'public/sh/install.sh$'
-sha256sum zi-install.sh # macOS: shasum -a 256 zi-install.sh
+tmp="$(mktemp -d)" && curl -fsSL https://get.zshell.dev -o "$tmp/install.sh" && curl -fsSL https://raw.githubusercontent.com/z-shell/src/main/public/checksum.txt -o "$tmp/checksum.txt"
```
-The two hashes must match. Then run one of the two supported profiles. Both run without a terminal and read nothing from standard input.
+With wget, replace each `curl -fsSL -o ` with `wget -qO `. The `public/sh/install.sh` line of the published [checksum][checksum-txt] must equal the digest of the fetched file. Use `shasum -a 256` where `sha256sum` is absent, and stop on a mismatch or a missing line:
+
+```sh
+expected="$(awk '$2 == "public/sh/install.sh" { print $1 }' "$tmp/checksum.txt")" && actual="$(sha256sum "$tmp/install.sh" | awk '{ print $1 }')" && [ -n "$expected" ] && [ "$expected" = "$actual" ] && echo 'checksum ok'
+```
+
+Run only after `checksum ok`, with one of the two supported profiles. Both run without a terminal and read nothing from standard input.
Loader profile: installs Zi, places the [loader](#loader) in the configuration home, and appends the loader snippet to .zshrc:
```sh
-sh zi-install.sh -a loader
+sh "$tmp/install.sh" -a loader
```
Install only: clones Zi into its home and leaves .zshrc untouched, for setups where the user integrates Zi later:
```sh
-sh zi-install.sh -i skip
+sh "$tmp/install.sh" -i skip
```
Rules the agent must follow:
-- Drive the installer with its flags (`-a loader`, `-i skip`, `-b `). Do not write to .zshrc or to the Zi configuration home yourself. The installer owns the integration block, detects an existing one, and a rerun appends nothing.
+- Drive the installer with its flags (`-a loader`, `-i skip`, `-b `). Do not write to .zshrc or to the Zi configuration home yourself. The installer owns the integration block, detects an existing one, and a rerun updates the checkout and appends nothing.
- Respect the user's environment. The installer edits `${ZDOTDIR:-$HOME}/.zshrc` and honours `XDG_CONFIG_HOME` and `XDG_DATA_HOME` only when their values are absolute paths. Do not export new values to force a location, and do not set `ZI_HOME` unless the user asked for a specific root. If `ZDOTDIR` or `ZI_HOME` is set to a relative path, stop and ask: the installer changes directory before it uses them.
- Run as the user who owns the shell. Never run the installer as root or through sudo: the checkout then lands in root's home, or leaves root-owned files that the user's shell cannot update.
- Do not start an interactive shell while installing (`exec zsh`, `zsh -i`, or `zsh -l`). The installer needs none, and a shell that waits for a prompt blocks the agent. Verification below uses one fresh `zsh -ic` invocation that exits on its own.
-- Stop and report when the installer refuses or skips: an existing Zi integration was detected, the checkout cannot be fast-forwarded (the installer prints `git status` and leaves the checkout untouched), or the `-b` value is not a valid branch name. Do not work around these by editing files.
+- Read the result instead of assuming it. For the loader profile, exit 0 plus the line `Loader added` is the evidence that the block was written; the closing `Successfully installed` banner alone is not. Stop and report when the installer refuses or skips: `Seems that .zshrc already sources Zi` means an integration exists and the block was not written, `cannot be fast-forwarded` means the checkout has local changes (the installer prints `git status` and leaves it untouched), and `Invalid -b value` means the branch name was rejected. Do not work around these by editing files.
+
+Verify the loader profile in two steps. A fresh interactive shell proves that the user's own startup loads Zi:
+
+```zsh
+zsh -ic 'zi -h' >/dev/null && echo 'zi ok'
+```
-Verify the loader profile with a fresh shell. Both conditions must hold: `zi` is defined, and `zzinit` is gone, because the loader removes `zzinit` and its helpers only after a successful run:
+That cannot tell which integration answered, so the probe below sources the installed loader in a clean shell, runs `zzinit`, and requires it to remove itself and its helpers, which the loader does only after a successful run. Expect `loader ok`; report any other line verbatim:
```zsh
-zsh -ic 'zi -h' >/dev/null && echo "zi ok"
-zsh -ic '(( ${+functions[zi]} && ! ${+functions[zzinit]} )) && print "loader ok" || { print -u2 "zzinit did not complete"; exit 1 }'
+zsh -f -c '
+unfunction zzinit _zi_err _zi_fetch _zi_check_stream _zi_setup _zi_source _zi_comps _zi_pmod 2>/dev/null
+typeset -gA ZI
+if [[ -n ${XDG_CONFIG_HOME:-} && $XDG_CONFIG_HOME == /* ]]; then d="$XDG_CONFIG_HOME/zi"; else d="$HOME/.config/zi"; fi
+source "$d/init.zsh" || { print "loader missing"; exit 1 }
+(( ${+functions[zzinit]} )) || { print "loader defined no zzinit"; exit 1 }
+zzinit || { print "zzinit failed"; exit 1 }
+for f in zzinit _zi_err _zi_fetch _zi_check_stream _zi_setup _zi_source _zi_comps _zi_pmod; do
+ (( ${+functions[$f]} )) && { print "helper not removed: $f"; exit 1 }
+done
+print "loader ok"
+'
```
Verify the install-only profile with the checkout directory the installer printed: after `Successfully installed at` on a fresh install, or after `Updating (z-shell/zi) plugin manager at` on a rerun. Do not guess it, since it may be a legacy ~/.zi, an explicit `ZI_HOME`, or the XDG data home, and the printed directory already includes the `bin` checkout name:
```zsh
-zsh -f -c 'builtin source "$1" && zi -h' zsh "/zi.zsh" >/dev/null && echo "zi ok"
+zsh -f -c 'builtin source "$1" && zi -h' zsh "/zi.zsh" >/dev/null && echo 'zi ok'
```
-Hand this block to the agent. It points at the zi-install skill, the machine-readable companion of this tab, tracked in [z-shell/.github#636](https://github.com/z-shell/.github/issues/636) until it is published:
+Hand this block to an agent that cannot load the skill:
```text title="Instructions for the agent"
-Install the Zi plugin manager for Zsh on this machine.
+Install the Zi plugin manager for Zsh on this machine by following the zi-install skill:
+https://github.com/z-shell/.github/blob/main/.github/skills/zi-install/SKILL.md
-- Download the official installer to a file and verify it before running it:
- curl -fsSL https://get.zshell.dev -o zi-install.sh (or: wget -qO zi-install.sh https://get.zshell.dev)
- Compare the file's sha256 with the public/sh/install.sh line of https://raw.githubusercontent.com/z-shell/src/main/public/checksum.txt and stop if they differ.
-- Run it non-interactively: sh zi-install.sh -a loader
- Use "-i skip" instead if I asked for install-only. Add "-b " only if I named a branch.
+- Profile: loader ("-a loader"). Use "-i skip" instead if I asked for install-only. Add "-b " only if I named a branch.
+- Fetch the installer from https://get.zshell.dev to a file, verify its sha256 against the public/sh/install.sh line of https://raw.githubusercontent.com/z-shell/src/main/public/checksum.txt, and only then run the file. Never run sh -c "$(curl ...)".
- Never write to ~/.zshrc, $ZDOTDIR/.zshrc, or the Zi configuration home yourself. The installer owns them.
- Run as my user, never as root or with sudo. Keep my ZDOTDIR, XDG_CONFIG_HOME, and XDG_DATA_HOME as they are; do not set ZI_HOME unless I asked. If ZDOTDIR or ZI_HOME is set to a relative path, stop and ask me.
- Do not start an interactive shell (exec zsh, zsh -i, zsh -l) while installing.
-- If the installer refuses or reports an existing integration, stop and show me its message. Do not edit files to work around it.
-- When done, verify with a fresh shell and show me the output:
- zsh -ic 'zi -h' >/dev/null && echo "zi ok"
- zsh -ic '(( ${+functions[zi]} && ! ${+functions[zzinit]} )) && print "loader ok" || { print -u2 "zzinit did not complete"; exit 1 }'
- For install-only, source zi.zsh from the directory the installer printed ("Successfully installed at" or "Updating ... at") in "zsh -f -c" and run "zi -h" instead.
-- Reference: https://wiki.zshell.dev/docs/getting_started/installation (Agent tab). If the zi-install skill from z-shell/.github is available, follow it.
+- If the installer refuses, or says .zshrc already sources Zi, stop and show me its message. Do not edit files to work around it.
+- When done, verify exactly as the skill describes (zsh -ic 'zi -h', then the loader probe; for install-only, zi.zsh under the directory the installer printed) and show me the output.
```
@@ -308,6 +322,7 @@ The module transparently and automatically compiles sourced scripts and lists of
{/* external */}
[checksum-txt]: https://raw.githubusercontent.com/z-shell/src/main/public/checksum.txt
+[zi-install-skill]: https://github.com/z-shell/.github/blob/main/.github/skills/zi-install/SKILL.md
[completion-system]: https://zsh.sourceforge.io/Doc/Release/Completion-System.html#Use-of-compinit
[discuss]: https://github.com/orgs/z-shell/discussions/new
[dockerfile]: https://github.com/robobenklein/configs/blob/master/Dockerfile
From ceebb3dcd657ca50d412ca59db5f063a14c11dfe Mon Sep 17 00:00:00 2001
From: Sal <59910950+ss-o@users.noreply.github.com>
Date: Sat, 19 Sep 2026 05:36:59 +0100
Subject: [PATCH 4/5] docs(installation): pin the skill install, select the
digest tool, and flag the trailing period
Address the Copilot review of c5ba9351 on #922. The skill install command carries `--pin ` so an installed copy is a reviewed revision. The checksum fence uses sha256sum and falls back to shasum -a 256, prints nothing with neither tool, on a mismatch, or on a missing line, and was tested in all four states. The install-only verification says the fresh-install line currently ends with a period that is not part of the path (z-shell/src#215), and the copyable block says the same.
---
docs/getting_started/01_installation.mdx | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/docs/getting_started/01_installation.mdx b/docs/getting_started/01_installation.mdx
index 28dcb957..345d5077 100644
--- a/docs/getting_started/01_installation.mdx
+++ b/docs/getting_started/01_installation.mdx
@@ -90,7 +90,7 @@ sh -c "$(curl -fsSL get.zshell.dev)" -- -a zunit
-Let an AI coding agent install Zi through the installer, never by editing .zshrc by hand. The [zi-install skill][zi-install-skill] in z-shell/.github is the machine-readable form of this tab: agents with skill support can install it with `gh skill install z-shell/.github .github/skills/zi-install --dir .github/skills`, and every other agent gets the instruction block at the end of this tab.
+Let an AI coding agent install Zi through the installer, never by editing .zshrc by hand. The [zi-install skill][zi-install-skill] in z-shell/.github is the machine-readable form of this tab: agents with skill support install a reviewed commit of it with `gh skill install z-shell/.github .github/skills/zi-install --pin --dir .github/skills`, so a later change to the skill cannot alter what an installed copy does, and every other agent gets the instruction block at the end of this tab.
The machine needs zsh, git, and curl or wget. Fetch the installer to a file, verify the file, then run it. Do not use `sh -c "$(curl ...)"` on a user's behalf: a failed fetch inside the substitution becomes an empty script that still exits 0, and an existing installation then passes verification although nothing ran.
@@ -98,10 +98,10 @@ The machine needs zsh, git, and curl or wg
tmp="$(mktemp -d)" && curl -fsSL https://get.zshell.dev -o "$tmp/install.sh" && curl -fsSL https://raw.githubusercontent.com/z-shell/src/main/public/checksum.txt -o "$tmp/checksum.txt"
```
-With wget, replace each `curl -fsSL -o ` with `wget -qO `. The `public/sh/install.sh` line of the published [checksum][checksum-txt] must equal the digest of the fetched file. Use `shasum -a 256` where `sha256sum` is absent, and stop on a mismatch or a missing line:
+With wget, replace each `curl -fsSL -o ` with `wget -qO `. The `public/sh/install.sh` line of the published [checksum][checksum-txt] must equal the digest of the fetched file. The command uses `sha256sum` and falls back to `shasum -a 256` where it is absent, as on macOS; with neither tool, or on a mismatch or a missing line, it prints nothing and the agent must stop:
```sh
-expected="$(awk '$2 == "public/sh/install.sh" { print $1 }' "$tmp/checksum.txt")" && actual="$(sha256sum "$tmp/install.sh" | awk '{ print $1 }')" && [ -n "$expected" ] && [ "$expected" = "$actual" ] && echo 'checksum ok'
+expected="$(awk '$2 == "public/sh/install.sh" { print $1 }' "$tmp/checksum.txt")" && actual="$({ sha256sum "$tmp/install.sh" 2>/dev/null || shasum -a 256 "$tmp/install.sh"; } | awk '{ print $1 }')" && [ -n "$expected" ] && [ "$expected" = "$actual" ] && echo 'checksum ok'
```
Run only after `checksum ok`, with one of the two supported profiles. Both run without a terminal and read nothing from standard input.
@@ -149,7 +149,7 @@ print "loader ok"
'
```
-Verify the install-only profile with the checkout directory the installer printed: after `Successfully installed at` on a fresh install, or after `Updating (z-shell/zi) plugin manager at` on a rerun. Do not guess it, since it may be a legacy ~/.zi, an explicit `ZI_HOME`, or the XDG data home, and the printed directory already includes the `bin` checkout name:
+Verify the install-only profile with the checkout directory the installer printed: after `Successfully installed at` on a fresh install, or after `Updating (z-shell/zi) plugin manager at` on a rerun. Do not guess it, since it may be a legacy ~/.zi, an explicit `ZI_HOME`, or the XDG data home, and the printed directory already includes the `bin` checkout name. The fresh-install line currently ends with a period after the directory ([z-shell/src#215](https://github.com/z-shell/src/issues/215)); that period is not part of the path:
```zsh
zsh -f -c 'builtin source "$1" && zi -h' zsh "/zi.zsh" >/dev/null && echo 'zi ok'
@@ -167,7 +167,7 @@ https://github.com/z-shell/.github/blob/main/.github/skills/zi-install/SKILL.md
- Run as my user, never as root or with sudo. Keep my ZDOTDIR, XDG_CONFIG_HOME, and XDG_DATA_HOME as they are; do not set ZI_HOME unless I asked. If ZDOTDIR or ZI_HOME is set to a relative path, stop and ask me.
- Do not start an interactive shell (exec zsh, zsh -i, zsh -l) while installing.
- If the installer refuses, or says .zshrc already sources Zi, stop and show me its message. Do not edit files to work around it.
-- When done, verify exactly as the skill describes (zsh -ic 'zi -h', then the loader probe; for install-only, zi.zsh under the directory the installer printed) and show me the output.
+- When done, verify exactly as the skill describes (zsh -ic 'zi -h', then the loader probe; for install-only, zi.zsh under the directory the installer printed, without the trailing period on that line) and show me the output.
```
From 686dd8e32d28c0ddfb5afeba7a799e4a3bc18f7c Mon Sep 17 00:00:00 2001
From: Sal <59910950+ss-o@users.noreply.github.com>
Date: Sat, 19 Sep 2026 05:44:14 +0100
Subject: [PATCH 5/5] docs(installation): mark the annex skip line as expected
and separate verification by profile
Address the two notes in the Copilot review of ceebb3dc on #922. `Skipped all annexes` is printed on every loader and default run, so the result guidance names it as expected output and lists only the three refusal lines as stop conditions; the fast-forward refusal covers local commits as well as changes. The loader checks are stated as loader-only, install-only keeps its single check, and the copyable block separates the two.
---
docs/getting_started/01_installation.mdx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/getting_started/01_installation.mdx b/docs/getting_started/01_installation.mdx
index 345d5077..dd5e9877 100644
--- a/docs/getting_started/01_installation.mdx
+++ b/docs/getting_started/01_installation.mdx
@@ -124,9 +124,9 @@ Rules the agent must follow:
- Respect the user's environment. The installer edits `${ZDOTDIR:-$HOME}/.zshrc` and honours `XDG_CONFIG_HOME` and `XDG_DATA_HOME` only when their values are absolute paths. Do not export new values to force a location, and do not set `ZI_HOME` unless the user asked for a specific root. If `ZDOTDIR` or `ZI_HOME` is set to a relative path, stop and ask: the installer changes directory before it uses them.
- Run as the user who owns the shell. Never run the installer as root or through sudo: the checkout then lands in root's home, or leaves root-owned files that the user's shell cannot update.
- Do not start an interactive shell while installing (`exec zsh`, `zsh -i`, or `zsh -l`). The installer needs none, and a shell that waits for a prompt blocks the agent. Verification below uses one fresh `zsh -ic` invocation that exits on its own.
-- Read the result instead of assuming it. For the loader profile, exit 0 plus the line `Loader added` is the evidence that the block was written; the closing `Successfully installed` banner alone is not. Stop and report when the installer refuses or skips: `Seems that .zshrc already sources Zi` means an integration exists and the block was not written, `cannot be fast-forwarded` means the checkout has local changes (the installer prints `git status` and leaves it untouched), and `Invalid -b value` means the branch name was rejected. Do not work around these by editing files.
+- Read the result instead of assuming it. For the loader profile, exit 0 plus the line `Loader added` is the evidence that the block was written; the closing `Successfully installed` banner alone is not, and `Skipped all annexes` is expected output for both profiles. Stop and report on these lines: `Seems that .zshrc already sources Zi` means an integration exists and the block was not written, `cannot be fast-forwarded` means the checkout has local commits or changes (the installer prints `git status` and leaves it untouched), and `Invalid -b value` means the branch name was rejected. Do not work around these by editing files.
-Verify the loader profile in two steps. A fresh interactive shell proves that the user's own startup loads Zi:
+Verify the loader profile in two steps; neither applies to install-only, which leaves .zshrc untouched. A fresh interactive shell proves that the user's own startup loads Zi:
```zsh
zsh -ic 'zi -h' >/dev/null && echo 'zi ok'
@@ -149,7 +149,7 @@ print "loader ok"
'
```
-Verify the install-only profile with the checkout directory the installer printed: after `Successfully installed at` on a fresh install, or after `Updating (z-shell/zi) plugin manager at` on a rerun. Do not guess it, since it may be a legacy ~/.zi, an explicit `ZI_HOME`, or the XDG data home, and the printed directory already includes the `bin` checkout name. The fresh-install line currently ends with a period after the directory ([z-shell/src#215](https://github.com/z-shell/src/issues/215)); that period is not part of the path:
+Verify the install-only profile with this check only, using the checkout directory the installer printed: after `Successfully installed at` on a fresh install, or after `Updating (z-shell/zi) plugin manager at` on a rerun. Do not guess it, since it may be a legacy ~/.zi, an explicit `ZI_HOME`, or the XDG data home, and the printed directory already includes the `bin` checkout name. The fresh-install line currently ends with a period after the directory ([z-shell/src#215](https://github.com/z-shell/src/issues/215)); that period is not part of the path:
```zsh
zsh -f -c 'builtin source "$1" && zi -h' zsh "/zi.zsh" >/dev/null && echo 'zi ok'
@@ -167,7 +167,7 @@ https://github.com/z-shell/.github/blob/main/.github/skills/zi-install/SKILL.md
- Run as my user, never as root or with sudo. Keep my ZDOTDIR, XDG_CONFIG_HOME, and XDG_DATA_HOME as they are; do not set ZI_HOME unless I asked. If ZDOTDIR or ZI_HOME is set to a relative path, stop and ask me.
- Do not start an interactive shell (exec zsh, zsh -i, zsh -l) while installing.
- If the installer refuses, or says .zshrc already sources Zi, stop and show me its message. Do not edit files to work around it.
-- When done, verify exactly as the skill describes (zsh -ic 'zi -h', then the loader probe; for install-only, zi.zsh under the directory the installer printed, without the trailing period on that line) and show me the output.
+- When done, verify exactly as the skill describes and show me the output. Loader: zsh -ic 'zi -h', then the loader probe. Install-only: only that zi.zsh exists under the directory the installer printed (without the trailing period on that line); the loader checks do not apply.
```