Skip to content

Repository files navigation

chitin

a modular and extensible shell framework inspired by the natural composition of chitin — the material forming the shells of many organisms

Structure

The framework's taxonomy mirrors how chitin builds shells:

  • helper: individual shell functions
  • chain: collections of helpers focused on specific domains. Chains are composed of interlinked chitin molecules.
  • fiber: top-level modules grouped by domain. Fibers provide structure by linking chains together.
  • module: general term for for chains and fibers, used when something is applicable to either
chitin-core
├── chitin-dev [fiber]
│   ├── docker [chain]
│   │   ├── build_image() [helper]
│   │   ├── run_container() [helper]
│   ├── git [chain]
│       ├── clone_repo() [helper]
│       ├── commit_changes() [helper]
├── chitin-cloud [fiber]
    ├── aws [chain]
    │   ├── launch_instance() [helper]
    │   ├── list_buckets() [helper]
    ├── kubernetes [chain]
        ├── deploy_pod() [helper]
        ├── scale_deployment() [helper]

Setup

  1. Clone this repository to your project dir (the directory where you usually run git clone)

  2. Add the following line to your profile (ie .zshrc or .bashrc), substituting <project dir>:

    source <project dir>/chitin/init.sh
  3. Start a new shell session, and follow the instructions to configure chitin by running chiConfigUserModify

Note: if you would prefer to not automatically load fibers (such as for performance reasons), set CHI_AUTOINIT_DISABLED=true, and use the command chiShell when you want to load them on-demand

Recovery: a fiber whose fiberDeps cannot be satisfied (misspelled, not cloned, or disabled in your userConfig) is reported with giving up on fiber and skipped; the shell still starts. If startup itself breaks, export CHI_AUTOINIT_DISABLED=true in the terminal before opening a new shell, fix the problem, then run chiShell.

Configuration

The framework can be configured at three levels: user, fiber, and chain.

Special Fields

*Dir fields support path expansions:

  • ~: -> $HOME
  • localshare -> $HOME/.local/share

User Configuration

The user configuration contains global settings, and allows you to set machine-specific overrides:

  • dotfilesDir: directory where you store your dotfiles (absolute path)
  • projectDir: directory you clone git repositories to (absolute path)
  • installToolDeps: whether any missing tool dependencies should be automatically installed

Modify this config by running chiConfigUserModify.

Module Configuration

Both fiber and chain configurations support the following fields:

  • enabled: whether this module should be loaded (default: true)
  • tools: allows you to declare and configure tools that modules can depend on
  • toolDeps: which tools this module depends on, and should not be loaded without

Tool Configuration

Tools can be declared in any module, and then referenced in the toolDeps of that module or any depenendent ones, such as a child chain or a dependent fiber and its chains.

Tools can be configured with:

In addition, the following configuration options can be set:

  • optional: whether this tool should be checked for presence
  • postInstall: a command to be run after a successful install
Install Method

Tools can be automatically installed if installToolDeps is set, using the following install methods:

  • brew: install with brew; all subfields are optional
    • name: can be used to override the tool name
    • cask: indicates that the tool is a brew cask
    • tap: set to the name of a brew tap if the formula requires it
    • tapUrl: set if the tap requires a specific URL
  • git: install with a git clone
    • url: the URL of the git repo to clone
    • target: the directory to clone the repo into
  • script: install by fetching and running a bash script
  • artifact: install by fetching an artifact to a certain path
    • url: the URL of the artifact to fetch
    • target: the directory to fetch the artifact into
    • appendFilename: whether to append the last url segment to the target
  • command: install by running a given bash command
Presence Checks

On module load, all tools will be checked for presence on the system, even if they are not explicitly set in toolDeps, unless the tool is marked as optional.

The following checks can be configured:

  • checkCommand: check for the presence of an executable in the PATH (default)
    • the default check method. if not explicitly set, will use the tool name
    • can be set to true to explicitly override one of the other check methods, such as when using the brew install method
  • checkBrew: check with brew if its been installed
    • automatically used when the tool is using the brew install method with the cask option set to true
  • checkPath: check for the presence of the given file
  • checkEval: run the given command and check the exit code
Version Checks

In addition to presence checking, a tool can optionally be configured to require a specific version (or range):

  • version: the expected semantic version
    • will validate up to the minor version, not checking patch
  • versionCommand: the command with which to get the tool's installed version

Fiber Configuration

The following fields are unique to fiber configurations:

  • fiberDeps: which fibers must be loaded prior to this one
  • moduleConfig: allows you to set overrides for child chains' configuration

Modify this config by running chiConfigModuleModify <fiber name>.

Chain Configuration

chain configurations are optional, and are merged with any matching parent moduleConfig fields, higher-level ones overriding lower.

Modify this config by running chiConfigModuleModify <fiber name:chain name>.

Chains

Secret

This chain provides a configurable secrets-management interface for other chains to use; it was designed with the pass command in mind, but can be used with others, given a compatible CLI.

Configuration:

Add a section to your chiConfig with the command to use:

{
  "chains": {
    "secret": {
      "command": "pass"
    }
  }
}

Functions:

  • chiSecretGet: retrieves a secret with the given name from the secret store

Startup performance

Chitin loads in every interactive shell, so its startup cost is the shell's startup cost. Measure it with the benchmark, never with time zsh -i -c exit: a non-TTY shell trips the lite-mode guard in ~/.zshenv and skips chitin entirely, reporting ~0.03s.

just bench                 # 3 timed startups of ~/.zshrc under a pseudo-terminal
just bench --profile       # plus zprof's top functions by self time
just bench --trace         # plus the slowest call sites and external-command counts
just bench --init ./init.sh   # measure this checkout instead of ~/Projects/chitin
just check                 # zsh -n on every shell file; shellcheck on *.sh when installed

Baseline recorded 2026-09-25 on an M-series MacBook with the core, dev, cloud and dotfiles fibers enabled and tool checks off: ~20s per shell (21.8 / 20.0 / 19.6s). About 17.6s is the loader's config plumbing: 47 chain loads at ~320ms each and roughly 2,900 external commands per startup (just bench --trace: sed 1,708, jq 487, paste 447, envsubst 155, yq 16 at 150 to 400ms each) plus thousands of command-substitution subshells. Sourcing the 94 chain files without the loader takes ~130ms, which is the floor a startup cache can reach.

Startup snapshot

The config-merge work above is a pure function of about 30 YAML files that rarely change, so after a full ("cold") load chitin persists its results under ~/.cache/chitin/snapshot/<checkout>/ and replays them on the next startup when none of those files changed: a warm shell starts in about 2 seconds instead of 20. The check itself is fork-free (zsh's builtin stat), and the snapshot is keyed by checkout path, so a session clone never shares one with ~/Projects/chitin.

  • chiSnapshotStatus says whether the current snapshot is valid and, if not, which file changed.
  • chiShellRebuild clears it and does a full load; chiSnapshotClear only clears.
  • CHI_SNAPSHOT_DISABLED=true forces a full load and writes nothing.
  • A stale snapshot logs which input changed and rebuilds on its own; a missing one says so.

Known limits: replay re-sources chain files without the positional parameters chiLoadDir happened to have, and a new file inside a nested chain subdirectory is only picked up once something else changes (or on chiShellRebuild). zsh only; under bash every load is cold.

Used By

This project is used by:

About

building blocks for shell frameworks

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages