# nothooks Nushell hook runner for the notfiles workspace. Executes `.nu` scripts in two distinct lifecycle phases — **dot** (always) and **setup** (once) — with state persistence so setup hooks are not re-run across invocations. ## Concepts ### HookPhase Each hook belongs to exactly one phase: | Phase | When it runs | Typical use | |-------|-------------|-------------| | `dot` | Every time nothooks is invoked | Apply shell config, set env vars, refresh symlinks | | `setup` | Once per machine (tracked in state) | Install packages, create dirs, first-time configuration | ### HookSpec A hook is described by three fields (defined in `notcore`): ```toml [[hooks]] name = "install-starship" script = "hooks/setup/install-starship.nu" phase = "setup" [[hooks]] name = "set-default-shell" script = "hooks/dot/shell.nu" phase = "dot" ``` ### State tracking Setup hooks are tracked in `.nothooks-state.toml` in the state directory (typically the dotfiles root). Once a setup hook completes successfully its name is recorded and it will be **skipped** on all future runs. ```toml # .nothooks-state.toml (auto-generated, do not edit manually) completed_setup_hooks = ["install-starship", "configure-git"] ``` Dot hooks are **never** recorded in state — they run unconditionally on every invocation. ### --force re-run To re-run setup hooks (e.g. after a machine rebuild or to apply changes), construct the runner with `HookRunner::with_force`. This bypasses the state check so all setup hooks execute regardless of prior completion. The notstrap CLI exposes this as `--force`. ## Hook script lifecycle ``` notstrap / nothooks invoked │ ├── dot phase │ └── for each hook where phase == "dot" │ └── nu