Plugins
A plugin is a git repository of prompt blocks and themes
that anyone can install with shkit plugin add.
- Using plugins
- Updating
- Security
- Writing a plugin
- The manifest:
plugin.json - Testing and CI
- Publishing and versioning
Using plugins
shkit plugin add git@github.com:someone/prompt-extras.gitadd clones the repository into a staging area and checks the manifest and the
files against the schema. It then shows what will be sourced and the commands the
plugin needs that are missing here, and asks. Only on yes is the plugin kept, as
~/.config/shkit/plugins/<name>/. The name comes from its manifest, not from the URL.
Once installed:
shkit show # its blocks are listed, its themes too
shkit set format '{dir} · {git} · {php}' # use a block
shkit set theme prompt-extras/dark # use a theme (layer 2)
shkit set -p theme prompt-extras/light # …or only in this project
shkit plugin list # installed plugins, version, commit
shkit plugin remove prompt-extrasA plugin theme sits under your theme.zsh and project files, so your own
settings always win (see settings layers).
Updating
Plugins never update on their own:
shkit plugin update # every plugin
shkit plugin update prompt-extras # oneFor each plugin, update fetches, then:
- refuses a rewritten history (a force push upstream), so remove and add the plugin again if you trust the new one;
- shows the new commits and the diff stat;
- checks the new
plugin.jsonand files, and refuses a plugin that renamed itself; - asks, then fast-forwards.
Security
[!WARNING] A plugin is code that every new shell runs. Read it before
addand before eachupdate, as you would any script you pipe into a shell.
- Nothing is fetched or updated unless you ask.
-
addandupdateshow what comes and ask first.-yskips the question, so keep it for scripts and your own plugins. - Credentials in a URL (
https://user:token@host/…) are never printed, but git stores the URL in the clone's.git/config. For a private repository, use an ssh URL or a git credential helper instead.
Writing a plugin
shkit scaffolds the layout and keeps plugin.json in step with the files:
shkit plugin new prompt-extras && cd prompt-extras # plugin.json + git init
shkit plugin new-block php 'PHP version of the project'
shkit plugin new-theme dark 'Dark background, soft colors'
$EDITOR blocks/php.zsh themes/dark.zsh
shkit plugin check # the check add runs
git add -A && git commit -m 'First version'The result:
prompt-extras/
├── plugin.json # the manifest
├── blocks/php.zsh # defines _prompt_seg_php, shown as {php}
└── themes/dark.zsh # SHKIT_* assignments
Other files (README, LICENSE, tests, CI) are free. blocks/ and themes/ must
hold exactly the declared files, and each block must define its
_prompt_seg_<name>. The block and theme rules are in Writing a block
and Writing a theme.
The plugin name ([a-z0-9-]) is its install directory and the prefix of its themes
(prompt-extras/dark). It can never change: an update that renames the plugin
is refused.
To remove a block or a theme, delete its file and its entry in plugin.json.
A complete example lives in zsh/plugin/example/.
The manifest: plugin.json
It must follow zsh/plugin/schema.json (JSON Schema
2020-12). Unknown keys are refused.
{
"$schema": "https://github.com/fmatsos/shellkit/zsh/plugin/schema.json",
"name": "prompt-extras",
"version": "1.0.0",
"description": "PHP version block and a dark theme",
"author": { "name": "Jane Doe", "email": "jane@example.com", "url": "https://example.com" },
"license": "MIT",
"homepage": "https://github.com/jane/prompt-extras",
"repository": "https://github.com/jane/prompt-extras.git",
"keywords": ["php", "dark"],
"requires": ["php"],
"blocks": [{ "name": "php", "description": "PHP version of the project" }],
"themes": [{ "name": "dark", "description": "Dark background, soft colors" }]
}| Key | Required | Rule |
|---|---|---|
name |
✓ |
^[a-z0-9][a-z0-9-]*$, never changes |
version |
✓ |
semver: 1.2.3, 1.3.0-beta.1
|
description |
✓ | non-empty |
blocks |
✓ blocks or themes
|
at least one { name, description? }, name ^[a-z0-9_]+$
|
themes |
✓ blocks or themes
|
at least one { name, description? }, name ^[a-z0-9][a-z0-9_-]*$
|
author |
{ name, email?, url? } |
|
license, homepage, repository
|
strings | |
keywords |
array of strings | |
requires |
commands the blocks run. add tells users which are missing |
|
$schema |
for editors |
Testing and CI
Locally, add needs a commit (it clones):
shkit plugin check # after each change
git commit -am wip
shkit plugin add -y ~/src/prompt-extras # a local path works as a URL
shkit set -p format '{php}' # see the block alone, in one project
# …change, commit, then:
shkit plugin update -y prompt-extras
shkit plugin remove prompt-extras # when doneIn the plugin's own CI, validate the manifest with jq. Copy
schema.json and
validate.jq into the repository:
# .github/workflows/check.yml
on: [push, pull_request]
jobs:
manifest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: |
errors=$(jq -r --slurpfile schema schema.json -f validate.jq plugin.json)
[ -z "$errors" ] || { echo "$errors"; exit 1; }No output means valid. Otherwise there is one error per line, such as
plugin.json.version: "1" must match ….
Publishing and versioning
- Push to any git host users can reach: GitHub, GitLab, your own server.
- Bump
versionwith every change users will get. -
Never rewrite published history (force push, amended or rebased
main):updaterefuses it, and every user would have to remove and add the plugin again. - Users only get changes when they run
shkit plugin update, which shows them your commits: keep them small and clearly described.
shellkit