Development
Working on shellkit itself. The rules for contributors, human or agent, are in
AGENTS.md. This page is the tour.
Repository layout
| Path | Role |
|---|---|
zsh/zshrc, zsh/zshenv
|
the zsh config, symlinked by zsh/install.sh
|
zsh/prompt.zsh |
the prompt: blocks, background jobs, layers, rendering |
zsh/prompt.check.zsh |
its self-check (no network) |
zsh/shkit.zsh |
the shkit command, its completion, the auto-update |
zsh/plugin/ |
schema.json, validate.jq and example/, a template plugin |
bash/bashrc, bash/completion.sh
|
the bash fallback |
shell/aliases.sh |
aliases and functions shared by both shells |
shell/install-local.sh |
creates and migrates ~/.config/shkit/
|
docs/ |
this documentation |
.github/workflows/ |
check.yml (CI) and release.yml (releases) |
.github/smoke.zsh, .github/smoke.bash
|
the installed shells, tested end to end in CI |
.claude/skills/ |
agent skills (below), including config-commit/check.sh
|
Principles
-
Plain shell, no framework. Startup stays under 60 ms (
check.sh), and around 35 ms is usual. The README's speed table comes from.github/bench/run.sh(zsh-bench, in Docker). The prompt GIFs (docs/assets/demo-*.gif) come from.github/demo/render.sh: the real prompt, recorded by VHS in Docker, onlyglaband a slowgit fetchsimulated. They stay in the README: the site's build takes PNG only, and a looping GIF has no stop control (RGAA 13.8). -
Linux and macOS, fully. No GNU-only flags, no
/procwithout a fallback. A zsh builtin (zstat,$EPOCHREALTIME,:A) is better than an$OSTYPEbranch, because then Linux runs the Mac's code too. The install scripts must run on macOS's bash 3.2. - The prompt's synchronous path stays local: under 50 ms in a large repository. Anything networked goes through the background cache.
-
Nothing dynamic reaches the prompt unescaped, and
PROMPT_SUBSTstays off. -
No secret in the repository, ever. The code uses variables, and the values
live in
~/.config/shkit/secrets.sh. -
noclobberis on: overwrite a file with>|.
Checks
Run before every commit, after git add:
.claude/skills/config-commit/check.sh| Check | What |
|---|---|
| syntax |
zsh -n / bash -n / sh -n on every script |
| prompt self-check |
zsh/prompt.check.zsh: blocks, layers, shkit, plugins, updates. It forces the macOS fallbacks on Linux too (no timeout, no /proc) |
| project self-check |
shell/projects.check.sh, run with bash and zsh: fake project trees in a temporary HOME, matching and completion |
| startup | the working tree's zshrc prints nothing on stderr, and starts in ≤ 60 ms (best of 5) |
| secrets | the exact values of your secrets.sh, then common token shapes, in the index |
Exit code 1 means don't commit. To run the self-check alone:
zsh zsh/prompt.check.zshCI
.github/workflows/check.yml runs on every push to a branch and on every pull
request, on Ubuntu and macOS:
-
check.sh(the startup time is reported, not enforced, on shared runners); - the install scripts, with macOS's own
/bin/bash3.2 there; - the installed shells, as a user gets them:
zsh -i .github/smoke.zshandbash -i .github/smoke.bash, with aliases, prompt, directory jump and a real plugin install; - on macOS,
bashrcstopping cleanly under bash 3.2.
A feature the self-check can't cover gets a line in the smoke tests.
Website
The site, https://fmatsos.github.io/shellkit/, lives on the gh-pages branch: the
landing page, the templates and build.py. Its documentation pages are these docs/,
rebuilt by .github/workflows/pages.yml at every push to main that touches them
(or by hand: Actions → pages → Run workflow). build.py renders them with GitHub's
Markdown API and fails on a broken link between pages or to an anchor, so a doc that
only works on github.com shows up there.
To change the site itself, check out gh-pages, edit src/ and run
python3 build.py <path to main's docs/> before committing: see its README.md.
Releasing
A release is a tag vX.Y.Z:
git tag -a v1.2.0 -m v1.2.0
git push origin v1.2.0.github/workflows/release.yml runs the full CI on the tag. If it passes, it:
- creates the GitHub release, with notes generated from the commits since the
previous tag. A tag with a suffix (
v2.0.0-rc.1) becomes a pre-release; - for a stable tag, moves the
releasebranch to it, fast-forward only.
Clones follow the release branch, never raw tags: shkit update, and a background
job at startup at most once a day (see Updating).
Only a tag that passed CI ever reaches a clone. So:
- follow semver: a breaking change of settings or of the block contract is a major version;
- never push to
releaseby hand, and never rewrite it. Clones refuse a rewritten release branch; - never move or delete a published tag;
- a failed release is fixed by a new tag (
v1.2.1). There is nothing to roll back.
Agent skills
.claude/skills/ holds instructions for coding agents working in this repository:
| Skill | For |
|---|---|
config-commit |
checks, then commit in the repository's style (check.sh) |
shell-config |
options, aliases, completion, install scripts, where a setting belongs |
prompt-theme |
the prompt engine: blocks, jobs, colors, layers, shkit
|
prompt-plugin |
writing a plugin |
website |
the site on gh-pages: pages, build, accessibility and performance checks, publishing |
visuals |
the mascot, illustrations, sprite sheets and screenshots, generated with Codex (sprite-check.py) |
shellkit