Skip to content

Configuration reference

Every field of the native kranz.yaml format, with its type, default, and a usable example. For one complete file with all of it in context, see the annotated configuration.

Durations are Go duration strings: 500ms, 5s, 2m, 1h30m. A bare number is not a valid duration.

Root

yaml
project: Northstar
version: "1.0"
defaults: {}
services: {}
action_groups: {}
ui: {}
FieldTypeDefaultDescription
projectstringRequired. Project name shown in the header
versionstringFree-form version label for your own use
defaultsmap{}Execution context inherited by every service
servicesmap{}Long-running processes and detached resources
action_groupsmap{}Project-level one-shot commands
uimap{}Appearance for this project

A configuration needs at least one service or one action group.

project

Type: string · Required

Displayed in the header and used to identify the project.

yaml
project: Northstar

version

Type: string · Default: none

A label for your own bookkeeping. Kranz neither validates nor interprets it. Quote it, or YAML reads 1.0 as a number.

yaml
version: "1.0"

defaults

Type: map · Default: {}

Execution context inherited by every service that does not set its own value. Only these four fields exist; defaults cannot set commands, probes, or ports.

FieldTypeDefaultDescription
dirstringconfig file directoryWorking directory for commands
shellstring/bin/bashShell used to run commands
envmap{}Environment variables
env_filesstring list[]Dotenv files, applied in order
yaml
defaults:
  dir: .
  shell: /bin/sh
  env:
    NODE_ENV: development
  env_files: [.env.shared]

Relative dir values resolve against the directory of the configuration file, not the directory you started Kranz in.

Services

Each key under services is a service name. Names are shown verbatim in the list, so keep them short and stable.

FieldTypeDefaultDescription
commandstringShorthand for lifecycle.start.command
descriptionstringOne line shown in Details
supervisionenumprocessprocess or detached
lifecyclemap{}Explicit start, stop, status, and logs
stop_on_exitbooltrue / falseWhether quitting Kranz stops this service
dirstringdefaults.dirWorking directory
shellstringdefaults.shellShell for commands
envmap{}Environment variables
env_filesstring list[]Dotenv files, applied in order
portsint list[]Declared ports, checked before start
detect_portsboolsee belowDiscover listeners at runtime
tagsstring list[]Grouping and selection labels
depends_onstring list[]Services that must start first
dependency_conditionsmap{}What "ready" means per dependency
healthcheckmapnoneReadiness and liveness probes
ready_log_lineregexReadiness from a log line
availabilitymap{}Restart policy and project exit
shutdownmap{}How this service is stopped
actionsmap{}One-shot commands owned by this service
before_startlist[]Actions that must succeed before start
success_exit_codesint list[0]Additional successful exit codes
disabledboolfalseExclude from batch start

command

Type: string · Required for process supervision

The command that runs the service. It is executed by shell, so pipes, &&, and variable expansion work.

yaml
services:
  api:
    command: npm run dev

command is exactly equivalent to lifecycle.start.command, and is normalized into it before configuration layers merge. Use the explicit form when the start needs its own timeout or confirmation:

yaml
services:
  api:
    lifecycle:
      start:
        command: npm run dev
        confirm: true

A single file must use one form or the other, never both.

description

Type: string · Default: none

One line explaining what the service is, shown in Details.

yaml
description: Messenger API and WebSocket backend

supervision

Type: process | detached · Default: process

Declares where lifecycle truth comes from.

  • process — Kranz starts the command, owns its process group, and knows the service stopped when the process exits.
  • detached — the start command finishes while the resource it created keeps running. There is no PID to supervise, so stop and status must be described explicitly.
yaml
services:
  remote-stack:
    supervision: detached

See the lifecycle guide for the full model.

lifecycle

Type: map · Default: {}

FieldTypeApplies toDescription
startaction shapebothHow to start
stopaction shapedetachedHow to stop
statusstatus shapedetachedWhether the resource exists
logsaction shapedetachedA command that streams logs

A process-supervised service may only declare lifecycle.start; Kranz already knows how to stop, observe, and read the logs of a process it owns. A detached service may declare any subset: one with only status is observe-only, and its start and stop controls stay unavailable rather than pretending to work.

Lifecycle action shape

start, stop, and logs share this shape:

FieldTypeDefaultDescription
commandstringRequired
descriptionstringHuman-readable intent
dirstringservice dirWorking directory
shellstringservice shellShell
envmapservice envAdded and overriding variables
env_filesstring listservice env_filesDotenv sources
timeoutdurationnoneDeadline for the whole command
confirmboolfalseAsk before running (start only)

Lifecycle commands cannot be interactive. Stopping from the TUI always asks for confirmation regardless of confirm.

yaml
lifecycle:
  start:
    command: ssh host 'cd app && docker compose up -d'
    timeout: 2m
  stop:
    command: ssh host 'cd app && docker compose down'
    timeout: 2m

timeout covers the entire command including the remote side of an SSH call.

Lifecycle status

A status probe answers one question: does the external resource exist and run? It is not a health check and never restarts anything.

FieldTypeDefaultDescription
typeenumRequired. Currently only command
commandstringRequired. Observation command
initial_delayduration0sWait before the first probe
intervalduration5sPoll period while running
stopped_intervalduration30sPoll period while stopped or unknown
timeoutduration2sDeadline for one probe
failure_thresholdint3Unclassified probes before unknown
running_exit_codesint list[0]Codes meaning running
stopped_exit_codesint listunsetCodes meaning stopped

Exit code contract. By default, exit 0 means running and every other exit code means stopped — the same convention every shell command already follows:

yaml
status:
  type: command
  command: docker compose ps --status running --quiet api | grep -q .

Declaring stopped_exit_codes opts into a three-way contract, for probes that can also report "I could not tell". Codes in neither set are unclassified, and after failure_threshold consecutive unclassified results the service is shown as unknown:

yaml
status:
  type: command
  # 0 = running, 3 = stopped, 4 = the host is unreachable
  command: ssh host ./stack-status.sh
  running_exit_codes: [0]
  stopped_exit_codes: [3]
  failure_threshold: 2

A probe that never produced an exit code at all — it could not start, timed out, or was killed — is always unclassified, never "stopped". Running and stopped sets must not overlap, and each code must be between 0 and 255.

stop_on_exit

Type: bool · Default: true for process, false for detached

Whether quitting Kranz stops this service.

yaml
services:
  remote-stack:
    supervision: detached
    stop_on_exit: false

Process-supervised services always stop with Kranz and cannot set false; Kranz does not leave orphaned child processes behind. A detached resource defaults to surviving the session, which is usually what you want for a Docker stack shared with other tools. The quit dialog lists exactly what will stop and what will be left running.

dir, shell

Type: string · Default: defaults.dir (config file directory), defaults.shell (/bin/bash)

yaml
services:
  api:
    dir: apps/api
    shell: /bin/bash

Relative directories resolve against the configuration file. Details shows the path relative to where Kranz is running.

env, env_files

Type: map, string list · Default: {}, []

yaml
services:
  api:
    env_files: [.env, .env.local]
    env:
      PORT: "3001"

Precedence, lowest to highest:

  1. .env beside the first configuration file
  2. defaults.env
  3. defaults.env_files, in order
  4. service env_files, in order
  5. service env

A value already present in your shell environment wins over the adjacent .env, but explicit configuration values always win. $HOME-style references expand after all layers merge. Every referenced dotenv file is watched, so editing one reloads the configuration.

ports

Type: int list · Default: []

Ports this service is expected to listen on.

yaml
services:
  api:
    ports: [3001]

Declared ports are checked before start. If another process holds one, Kranz names the owner and asks what to do instead of failing obscurely. They are also valid documentation for a detached resource whose ports live elsewhere.

detect_ports

Type: bool · Default: true when ports is empty, otherwise false

Discover TCP listeners actually opened by the service and its children.

yaml
services:
  vite:
    detect_ports: true

Useful when a dev server picks its own port. Details separates declared ports from detected ones. Not available for detached services, which have no local process group to inspect; setting true there is rejected. See logs and ports.

tags

Type: string list · Default: []

yaml
tags: [backend, messenger]

Tags appear as expandable groups with their own summary Details. Selecting a tag selects every service in it.

depends_on

Type: string list · Default: []

yaml
services:
  web:
    depends_on: [api]

Starting a service starts its dependencies first. Stopping it stops its dependents first, in reverse order. Shift+S overrides both and acts only on the selection.

dependency_conditions

Type: map · Default: process_healthy per dependency

What counts as "ready" for each dependency.

ConditionMeaning
process_startedThe process exists
process_healthyIts readiness probe passes (default)
process_completedIt finished, with any exit code
process_completed_successfullyIt finished successfully
process_log_readyIts ready_log_line matched
yaml
services:
  web:
    depends_on: [api, seed]
    dependency_conditions:
      api: {condition: process_healthy}
      seed: {condition: process_completed_successfully}

process_log_ready requires the dependency to define ready_log_line.

healthcheck

Type: map · Default: none

Two independent probes:

  • readiness — may dependents start? Gates the dependency graph.
  • liveness — is this running service still healthy? Surfaces unhealthy.
yaml
healthcheck:
  readiness:
    type: http
    url: http://127.0.0.1:3001/ready
    interval: 2s
  liveness:
    type: tcp
    port: 3001
    initial_delay: 10s
    interval: 15s

Each probe accepts:

FieldTypeDefaultApplies to
typehttp | tcp | commandRequired
urlstringhttp
headersmap{}http
status_codeintany 2xxhttp
portinttcp
commandstringcommand
port_fromdetectedhttp, tcp
detected_port_indexint0http, tcp
initial_delayduration0sall
intervalduration5sall
timeoutduration2sall
failure_thresholdint3all

An empty healthcheck block is invalid — a probe with no type cannot be run, and silently ignoring it would misreport the service as healthy.

To probe a port discovered at runtime instead of a fixed one, take the port from discovery. A tcp probe with no port, or an http probe with port_from: detected, targets the first detected listener; detected_port_index selects a later one for a service that opens several. See health and dependencies.

ready_log_line

Type: regular expression · Default: none

Readiness from output, for services with no endpoint to probe.

yaml
services:
  worker:
    command: npm run worker
    ready_log_line: "worker listening"

Cannot be combined with a readiness probe; declare one source of readiness.

availability

Type: map · Default: {}

FieldTypeDefaultDescription
restartno | always | on_failure | exit_on_failurenoRecovery policy
backoffduration0sWait before restarting
max_restartsint0 (unlimited)Restart attempt limit
exit_on_endboolfalseQuit Kranz when this service ends
exit_on_skippedboolfalseQuit Kranz if a dependency gate skips it
yaml
availability:
  restart: on_failure
  backoff: 2s
  max_restarts: 3

Restart policies apply to process-supervised services only. Kranz does not restart a detached resource it does not own.

shutdown

Type: map · Default: {}

FieldTypeDefaultDescription
signalint15 (SIGTERM)Signal sent first
timeoutduration3sGrace period before escalation
commandstringCustom graceful shutdown command
parent_onlyboolfalseSignal only the leader, not the group
yaml
shutdown:
  signal: 15
  timeout: 10s

After timeout expires the process group is killed, so a service that ignores SIGTERM still exits.

By default the whole process group is signaled, so child processes do not survive their parent. Use parent_only: true only when a program manages its own children and must handle shutdown itself.

actions

Type: map · Default: {}

One-shot commands owned by this service. See actions below and the actions guide.

yaml
services:
  api:
    command: npm run dev
    actions:
      migrate:
        command: npm run db:migrate
        confirm: true

before_start

Type: list · Default: []

Actions that must succeed before this service starts. Each entry references an existing action rather than inlining a command, so the same command stays runnable and inspectable on its own.

FieldTypeDefaultDescription
actionstringRequired. Action name
servicestringthe declaring serviceService owning the action
groupstringAction group owning the action
runonce | alwaysonceHow often it runs per session
yaml
services:
  api:
    command: npm run dev
    actions:
      migrate:
        command: npm run db:migrate
    before_start:
      - action: migrate
      - group: infrastructure
        action: up
        run: always

Set either service or group, not both. Prerequisites run in declared order, after dependencies are ready and before the service starts. once means one successful run per Kranz session, including across restarts; always runs before every start. If a prerequisite fails, the service stays stopped and the failure is reported in its logs. Interactive actions cannot be prerequisites.

success_exit_codes

Type: int list · Default: [0]

Additional exit codes treated as success, for commands that report a meaningful non-zero status.

yaml
success_exit_codes: [0, 2]

disabled

Type: bool · Default: false

The service stays visible and startable by hand. Pressing a does not select it, and start-all skips it, so it is excluded from a-style batch starts.

yaml
disabled: true

Action groups

Project-level actions that belong to no single service.

yaml
action_groups:
  infrastructure:
    description: Shared development infrastructure
    dir: infra
    env_files: [.env.infra]
    actions:
      up:
        command: docker compose up -d
      reset:
        command: docker compose down --volumes
        confirm: true
FieldTypeDefaultDescription
descriptionstringShown on the group row
dirstringdefaults.dirInherited working directory
shellstringdefaults.shellInherited shell
envmap{}Inherited environment
env_filesstring list[]Inherited dotenv sources
actionsmapRequired. The group's actions

An action's own values override the group's.

Action fields

The same shape for service actions and group actions:

FieldTypeDefaultDescription
commandstringRequired
descriptionstringWhat it does, shown beside the name
dirstringowner's dirWorking directory
shellstringowner's shellShell
envmapowner's envAdded and overriding variables
env_filesstring listowner's env_filesDotenv sources
timeoutdurationnoneDeadline for the whole process group
confirmboolfalseAsk before running
interactiveboolfalseHand the terminal to the command

The action's key is its name in the list; description explains it. Keep keys short and stable — migrate, not run-the-database-migrations.

UI

Appearance for this project. Personal settings live outside the repository; see appearance.

FieldTypeDefaultDescription
themestringbuilt-in defaultNamed theme
accent#RRGGBBtheme accentAccent color
backgroundterminal | theme | #RRGGBBterminalCanvas source
color_modeauto | dark | lightautoPalette mode
yaml
ui:
  theme: tokyo-night
  accent: "#7AA2F7"
  background: terminal
  color_mode: auto

Ctrl+T opens the live picker, which can write these values back to the project or to your personal settings.

Validation rules

Kranz rejects a configuration rather than starting with an ambiguous one:

  • unknown fields are errors, so a typo never becomes silence;
  • a process-supervised service needs command or lifecycle.start;
  • lifecycle.stop, status, and logs require supervision: detached;
  • detect_ports: true and restart policies are rejected for detached services;
  • running_exit_codes and stopped_exit_codes must not overlap;
  • every probe needs its own type;
  • ready_log_line and a readiness probe are mutually exclusive;
  • dependencies must exist, and the graph must be acyclic;
  • before_start must reference an action that exists and is not interactive.

An invalid change during a live reload leaves the running configuration in place; the error is reported and nothing is disrupted.

Released under the MIT License.