Task Conventions
Every OHF project should feel the same to work with. An engineer should be able to clone any
repository, run mise run setup, then mise run dev, and be productive immediately — without
reading a bespoke README or figuring out which package manager commands to chain together.
This convention follows GitHub's
Scripts to Rule Them All pattern: a
script/ directory at the repo root with predictable names that every project implements.
Mise en Place wraps these scripts as tasks, providing runtime management,
dependency ordering, and a uniform mise run <task> interface.
| Area | Requirement | Why |
|---|---|---|
| Scripts | script/ directory in every repo | Portable, language-agnostic entry points. Work without mise installed. |
| Task Runner | Mise en Place | Wraps scripts with runtime management and depends. Declared in .mise.toml at the root. |
| CI Layer | CI calls scripts directly | GitHub Actions runs script/cibuild. Same scripts locally and in CI. |
Where Tasks Live
Section titled “Where Tasks Live”Mise is the single entry point for engineers. Running mise run lists every available task in
the project — no need to dig through package.json, script/, or CI config to find what's
available.
| Layer | Location | Role | Example |
|---|---|---|---|
| Entry point | .mise.toml | Global task registry. mise run lists everything | mise run dev, mise run setup |
| Lifecycle scripts | script/ | Standardized, portable scripts across all repos | script/setup, script/server, script/cibuild |
| CI scripts | package.json | Thin scripts consumed by GitHub Actions | "lint", "build", "typecheck" |
| Git hooks | .husky/ | Automated checks on commit | pre-commit → runs lint-staged |
Standard Scripts
Section titled “Standard Scripts”Every project must have a script/ directory with these files. Optional scripts should be added
when relevant.
| Script | Purpose | Required |
|---|---|---|
script/setup | First-time project setup: install deps, generate .env, run migrations | Yes |
script/update | Update project after git pull (deps, migrations, codegen) | Yes |
script/server | Start the local development server | Yes |
script/test | Run the test suite | Yes |
script/cibuild | Run the full CI suite (lint, format, typecheck, test, build) | Yes |
script/console | Open an interactive REPL or shell | Optional |
script/bootstrap | Install/update dependencies only (called by setup and update) | Optional |
Mise Task Mapping
Section titled “Mise Task Mapping”Mise tasks in .mise.toml unify everything under one interface. Some tasks call into the script/
directory, others call package.json scripts directly for convenience. Engineers always interact
with mise run <task>.
| Mise Task | Calls | Notes |
|---|---|---|
setup | script/setup | First-time setup |
update | script/update | Sync after pulling changes |
dev | script/server | Alias matches JS ecosystem convention (pnpm run dev) |
test | script/test | Direct mapping |
ci | script/cibuild | Direct mapping |
console | script/console | Direct mapping |
build | — | Convenience task; part of cibuild |
lint | — | Convenience task; part of cibuild |
format | — | Convenience task; part of cibuild |
typecheck | — | Convenience task; part of cibuild |
check | — | Runs all quality checks (lint, format, typecheck) without build |
Convenience tasks like lint, format, and check don't need a dedicated script — they are
defined directly in .mise.toml for developer ergonomics.
Script Conventions
Section titled “Script Conventions”- Scripts must be executable (
chmod +x script/*) - Scripts should be bash (
#!/usr/bin/env bash) withset -eat the top - Scripts should be idempotent — safe to run multiple times
script/setupshould callscript/bootstrap(or inline the same logic) before doing first-time configscript/updateshould callscript/bootstrapto refresh dependencies
Mise Naming Conventions
Section titled “Mise Naming Conventions”Sub-tasks use colon-separated names for variants of a base task:
lint:fix— run linter with auto-fixformat:check— check formatting without writing changesdev:host— start dev server accessible on the network
Example
Section titled “Example”script/setup
Section titled “script/setup”#!/usr/bin/env bashset -e
cd "$(dirname "$0")/.."
script/bootstrap
cp -n .env.example .env || truepnpm exec prisma migrate devscript/bootstrap
Section titled “script/bootstrap”#!/usr/bin/env bashset -e
cd "$(dirname "$0")/.."
pnpm installscript/server
Section titled “script/server”#!/usr/bin/env bashset -e
cd "$(dirname "$0")/.."
pnpm exec nest start --watchscript/test
Section titled “script/test”#!/usr/bin/env bashset -e
cd "$(dirname "$0")/.."
pnpm run testscript/cibuild
Section titled “script/cibuild”#!/usr/bin/env bashset -e
cd "$(dirname "$0")/.."
script/bootstrap
pnpm run lintpnpm run format:checkpnpm run typecheckpnpm run testpnpm run build.mise.toml
Section titled “.mise.toml”[tools]node = "24"
[tasks.setup]description = "First-time project setup"run = "script/setup"
[tasks.update]description = "Update project after git pull"run = "script/update"
[tasks.dev]description = "Start development server"run = "script/server"
[tasks.test]description = "Run tests"run = "script/test"
[tasks.ci]description = "Run full CI suite"run = "script/cibuild"
[tasks.console]description = "Open interactive console"run = "script/console"
# Convenience tasks for day-to-day development[tasks.install]description = "Install dependencies"run = "pnpm install"
[tasks.build]description = "Build for production"run = "pnpm run build"depends = ["install"]
[tasks.lint]description = "Run ESLint"run = "pnpm run lint"depends = ["install"]
[tasks."lint:fix"]description = "Run ESLint with auto-fix"run = "pnpm exec eslint . --fix"depends = ["install"]
[tasks.format]description = "Format code with Prettier"run = "pnpm exec prettier --write ."depends = ["install"]
[tasks."format:check"]description = "Check formatting"run = "pnpm run format:check"depends = ["install"]
[tasks.typecheck]description = "Run TypeScript type checking"run = "pnpm run typecheck"depends = ["install"]
[tasks.check]description = "Run all quality checks"depends = ["lint", "format:check", "typecheck"]