Configuration Reference
Exhaustive hako.yml configuration reference.
hako.yml lives in the repository root. It's auto-generated by hako new if not present. You can manually create or edit it.
Full example
# Mode: auto-detected from services vs compose file
# mode: bare # explicit override (bare or docker)
auto_start: false
# Docker mode: port variables to allocate
ports:
- PORT
- API_PORT
- DB_PORT
# Bare mode: services to manage
services:
dev:
cmd: "npm run dev"
port_var: PORT
ready: "curl -sf http://localhost:$PORT/health"
worker:
cmd: "node worker.js"
port_var: WORKER_PORT
# Custom environment variables for .env.hako
env:
DATABASE_URL: "postgres://localhost:${HAKO_PORT_BASE}+1/mydb"
REDIS_URL: "redis://localhost:${HAKO_PORT_BASE}+2"
APP_NAME: "my-app"
# Secrets handling (replaces default auto-copy when present)
secrets:
copy:
- .env.local
- config/credentials.json
template:
- source: .env.template
target: .env.local
symlink:
- .npmrc
# Portless URL registration
portless: true
# Custom worktree directory
worktree_dir: ~/projects/worktrees
# Lifecycle and custom hooks
hooks:
post_create:
- npm install
- cp .env.example .env.local
post_start:
- echo "Started {{branch}} on port {{port_base}}"
post_stop:
- echo "Stopped {{branch}}"
pre_remove:
- echo "Removing {{worktree_path}}"
seed_db:
- ./scripts/seed.shKey reference
mode
- Type: string (
bare|docker) - Default: auto-detected
If services: is present, it defaults to bare. If a compose file is present, it defaults to docker. If both are present, it results in an error. If neither is present, it defaults to docker. Explicit mode: overrides auto-detection.
auto_start
- Type: boolean
- Default:
false
When true, hako new automatically starts services or containers after creation. This is equivalent to running hako new --start.
ports
- Type: array of strings
- Default:
[PORT](auto-generated when compose ports are detected)
Docker mode only. Lists environment variable names for port allocation. Each variable gets a sequential offset from the base port (e.g., PORT=base, API_PORT=base+1).
services
- Type: object
- Default: none
Bare mode only. Each key is a service name.
cmd(string, required): command to execute.port_var(string, optional): port environment variable name. Written to.env.hakoand exported to the process.ready(string, optional): health check command.
env
- Type: object (key-value pairs)
- Default: none
Extra variables written to .env.hako. Values support:
- Literal strings:
APP_NAME: "my-app" - Port base substitution:
DATABASE_URL: "postgres://localhost:${HAKO_PORT_BASE}/db" - Arithmetic:
REDIS_PORT: "${HAKO_PORT_BASE}+2"(evaluated to the actual number)
secrets
- Type: object
- Default: none
The presence of this section disables the default auto-copy of .env* and tooling files like .npmrc or .nvmrc.
copy(array of strings): files to copy from the repository root to the worktree.template(array of objects withsourceandtarget): files to render with template variables.symlink(array of strings): files to symlink from the repository root.
portless
- Type: boolean
- Default:
false
Registers local .localhost URLs via portless. Hako auto-installs portless and starts its proxy daemon on first use (requires Node.js 20+). Single service: {slug}.localhost. Multi-service: {slug}-{svc}.localhost.
worktree_dir
- Type: string (path)
- Default:
~/.hako/worktrees/{repo}
Overrides where worktrees are created. Supports ~ expansion. Precedence: HAKO_DIR environment variable > hako.yml worktree_dir > default.
hooks
- Type: object
- Default: none
Keys are hook names. Values are arrays of commands.
Auto-run hooks: post_create, post_start, post_stop, pre_remove.
Any other key is a custom hook, run via hako hook run <name>.
Template variables
Expanded in hook command strings: {{repo}}, {{branch}}, {{branch_slug}}, {{worktree_path}}, {{port_base}}.
Environment variables
Exported to the hook process: HAKO_REPO, HAKO_BRANCH, HAKO_BRANCH_SLUG, HAKO_WORKTREE_PATH, HAKO_PORT_BASE.
Execution
Hooks run in the worktree directory. Each command executes via eval in a subshell. Hook failures are non-fatal: hako logs a warning and continues. Logs are stored at <git-common-dir>/hako/logs/{branch_slug}-{hook_name}.log.
Set HAKO_HOOK_SILENT=1 to suppress hook output to the terminal (still logged to file).
Bare mode process lifecycle
- Start: command runs in background via subshell. stdout/stderr redirected to
.hako/logs/{service}.log. PID written to.hako/pids/{service}.pid. - Stop: SIGTERM, wait up to 5 seconds (10 attempts x 0.5s), then SIGKILL. PID file cleaned up.
- Idempotent: starting an already-running service is a no-op. Stopping an already-stopped service is a no-op.
- Stale PID recovery: if PID file exists but process is dead, the stale file is cleaned up and the service restarts.
- Immediate exit detection: if process exits within 0.5s of starting, hako reports failure.
Health states
Bare mode health (shown in hako status):
healthy: manifest exists and all services from manifest are running.degraded: manifest exists and some (but not all) services are running.stopped: manifest missing or no services running.
CLI Reference
Exhaustive reference for the hako command-line interface.
Global Configuration
Global configuration, environment variables, and file locations.
ops.origin: Masakiro Corp.