ery time.
A practical rule
Keep the task names stable and the descriptions explicit. Taskfile’s built-in descriptions make it easier to discover available commands, which helps new contributors quickly understand the project’s workflow. If a command is painful to type or easy to forget, it belongs in the Taskfile.
Step 2: Add pre-commit checks
Pre-commit hooks are your safety net for local quality control, because they run automatically before a commit is finalized. They are best used for fast checks: formatting, linting, small validation scripts, and lightweight tests. The goal is not to replace CI; it is to stop obvious problems before they leave your machine.
A simple .pre-commit-config.yaml can look like this:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: end-of-file-fixer
- id: check-yaml
- id: trailing-whitespace
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v9.13.0
hooks:
- id: eslint
additional_dependencies: []
Enter fullscreen mode Exit fullscreen mode
Install and activate the hooks once per clone:
pre-commit install
pre-commit run all-files
Enter fullscreen mode Exit fullscreen mode
A good hook set should be fast enough that you barely notice it during normal work. If a check is slow, move it to Taskfile or CI so commits stay responsive.
Step 3: Use worktrees for parallel work
Git worktrees let one repository have multiple checked-out branches in separate directories. That makes them perfect for situations where you are fixing a bug, reviewing a PR, and starting a new feature on the same day. Instead of stashing changes repeatedly, you can keep each task isolated and open in its own editor window.
A simple setup looks like this:
git worktree add ../project-auth feature/auth
git worktree add ../project-fix-login hotfix/login-edge-case
git worktree list
Enter fullscreen mode Exit fullscreen mode
A good habit is to name the folder after the branch or task so it is obvious what lives there. When you are done, clean up with:
git worktree remove ../project-auth
git worktree prune
Enter fullscreen mode Exit fullscreen mode
This is especially useful if you use separate terminals or AI tools per branch, because it reduces cross-branch mistakes and watcher collisions.
Step 4: Connect the pieces
The workflow becomes powerful when these tools reinforce each other. Taskfile gives you a single command surface, pre-commit enforces local quality, and worktrees give each task its own space. That means you can open a fresh worktree, run task setup, make your change, and commit only after the hook checks pass.
A typical day might look like this:
- Create a worktree for the feature.
- Run
task setup in that directory.
- Make the change in small steps.
- Run
task lint and task test.
- Commit, letting pre-commit catch formatting drift.
- Remove the worktree after merge.
This pattern reduces the number of decisions you have to make during focused work, which is often where productivity gains really come from.
Step 5: Keep tasks and hooks fast
Fast feedback is the difference between a workflow people use and a workflow they bypass. Make your hook chain short, and avoid stuffing expensive integration tests into the commit path. Reserve heavier checks for task ci or the actual CI pipeline so your local loop stays tight.
A useful split is:
- Pre-commit: formatting, linting, file hygiene, tiny validation checks.
- Taskfile local commands: setup, test, build, generate, CI simulation.
- CI: full test matrix, deployment checks, and slower verification.
If a check keeps failing for non-obvious reasons, simplify it. A workflow that is reliable but slightly less ambitious is better than a clever one that developers work around.
Example project setup
Here is a compact pattern you can drop into many JavaScript or TypeScript repos:
### Taskfile.yml
version: '3'
tasks:
setup:
cmds:
- npm install
dev:
cmds:
- npm run dev
format:
cmds:
- npm run format
lint:
cmds:
- npm run lint
test:
cmds:
- npm test
check:
deps: [format, lint, test]
Enter fullscreen mode Exit fullscreen mode
### .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-yaml
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v9.13.0
hooks:
- id: eslint
Enter fullscreen mode Exit fullscreen mode
### one-time per clone
pre-commit install
### normal use
task setup
task check
git worktree add ../my-feature feature/my-feature
Enter fullscreen mode Exit fullscreen mode
This gives you a clean path from checkout to commit without relying on memory or tribal knowledge.
Common mistakes
One mistake is using Taskfile as a dumping ground for every shell script in the repo. The better approach is to expose only the commands people actually need often, and keep the names obvious. Another mistake is making pre-commit too heavy, which leads to no-verify habits and defeats the point. A third is creating lots of worktrees without cleaning them up, which makes the file system and your mental model both messy.
A good workflow is not about adding tools for their own sake. It is about turning repeated decisions into defaults so you spend more attention on the code itself.
A simple rollout plan
If you are introducing this in an existing repo, do it in this order: first add Taskfile commands for setup, lint, test, and CI-like checks. Next add a small, fast pre-commit configuration that enforces formatting and obvious hygiene. Finally, start using worktrees for parallel branches or hotfixes, and document the commands in the repository README.
That staged rollout keeps the adoption cost low and makes each improvement easy to evaluate. Once the workflow is visible in the repo, it becomes part of the codebase instead of a personal preference.
-
Rizwan Saleem | https://rizwansaleem.co
Sources