Hako
Reference

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.sh

Key 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.hako and 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 with source and target): 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.

ops.origin: Masakiro Corp.

On this page