Skip to content

Hooks

daft hooks define clear boundaries as your code evolves. They are a local, parallel approach to GitHub Actions — every stage of code's lifecycle gets a well-defined gate.

Each stage in your code's journey through development has different needs:

  • When you start isolated work, you want the right env booted up
  • When you commit a change, you want format/lint/fast-tests to gate it
  • When you merge, you want the equivalent of PR checks to gate it
  • When you tear down a worktree, you want artifacts persisted and state reclaimed

daft models each of these as a hook stage. They share one configuration system, one trust model, one job orchestrator.

The boundaries

StageHook typeBoundary semanticsStatus
End of clone setuppost-cloneOne-shot bootstrap of a fresh repoShipped
Start of isolated devWorktree hooks (worktree-pre/post-create)Set up local dev env (deps, services)Shipped
Sealing a unit of changeCommit hooksProgressive code-replication boundary — format, lint, fast tests before the change is recordedRoadmap (#468)
Letting a change escape isolationMerge hooks (pre-merge, post-merge)PR-check parity — full tests, integration, security gates before code leaves the branchShipped
Reclaiming an isolated envWorktree teardown (worktree-pre/post-remove)Teardown, persist artifacts, sync stateShipped

How daft hooks differ from lefthook

Two distinctions:

  1. Lefthook is commit-time-only. daft covers the full code-evolution lifecycle. Commit hooks are one stage among many — they share the trust model, the YAML schema, and the job orchestrator with worktree-lifecycle hooks. (See #468 for the lefthook drop-in plan.)
  2. Boundaries before changes leave your machine. CI traditionally runs after code reaches the central repo; daft hooks run before. CI shifts left.

daft and your existing git hooks

daft's hooks do not replace git's own. Every daft-initiated git push honors the repository's pre-push hook — whether it lives in .git/hooks or is managed by lefthook, husky, or pre-commit via core.hooksPath. A failing pre-push gate blocks the push and fails the command; its run is reported as a pre-push phase on the same surface lifecycle hooks use. The one conditional site is the automatic upstream push on branch creation: it consults the hook only when it would publish commits the remote does not already have, so branching off a fully-pushed base skips it (tunable via daft.checkout.pushVerify). Pass --no-verify to any pushing command to skip it for one invocation. And because the shared hook always runs in the pushed branch's own worktree under daft push, that command is the way to push another worktree's branch without the hook validating the wrong tree. See Git Hooks for the details.

Where to next

Released under MIT or Apache-2.0.