hack.foo
Reference

Configuration fields

This field inventory was audited against the 5.0.0-next.5 source and has not been requalified against later prereleases. The generated command reference and the pinned runtime guides take precedence where they differ.

This reference describes v5 (next.5). Use Environment and secrets and Lifecycle for workflows. Fields below come from the version-pinned schema and readers, not a newer checkout.

The published native launcher accepts a narrower authored project model. This legacy JSON/Compose reference does not establish native feature support. Start with Native configuration import and the authored schemas linked from Reference.

Project JSON

The legacy project file is .hack/hack.config.json. Requiredness below is relative to the containing schema object or union variant. An optional parent does not become required because a child is required. Repeated paths describe different variants. The schema requires name and dev_host; the reader has compatibility fallbacks. A schema constraint is not proof the reader validates it. No schema default is declared for these fields.

FieldTypeWithin this variantConstraintsSchema locationEvidence
$schemastringOptional—#/properties/$schemasource
namestringRequired—#/properties/namesource
dev_hoststringRequired—#/properties/dev_hostsource
defaultEnvConfigstringOptional—#/properties/defaultEnvConfigsource
default_env_configstringOptional—#/properties/default_env_configsource
logsobjectOptional{"additionalProperties":true}#/properties/logssource
logs.follow_backendstringOptional{"enum":["compose","loki"]}#/properties/logs/properties/follow_backendsource
logs.snapshot_backendstringOptional{"enum":["compose","loki"]}#/properties/logs/properties/snapshot_backendsource
logs.clear_on_downbooleanOptional—#/properties/logs/properties/clear_on_downsource
logs.retention_periodstringOptional—#/properties/logs/properties/retention_periodsource
internalobjectOptional{"additionalProperties":true}#/properties/internalsource
internal.dnsbooleanOptional—#/properties/internal/properties/dnssource
internal.tlsbooleanOptional—#/properties/internal/properties/tlssource
internal.extra_hostsobjectOptional{"additionalProperties":{"type":"string"}}#/properties/internal/properties/extra_hostssource
oauthobjectOptional{"additionalProperties":true}#/properties/oauthsource
oauth.enabledbooleanOptional—#/properties/oauth/properties/enabledsource
oauth.tldstringOptional—#/properties/oauth/properties/tldsource
openobjectOptional{"additionalProperties":true}#/properties/opensource
open.preferstringOptional{"enum":["auto","alias","dev"]}#/properties/open/properties/prefersource
worktreeobjectOptional{"additionalProperties":true}#/properties/worktreesource
worktree.auto_branchbooleanOptional—#/properties/worktree/properties/auto_branchsource
worktree.inherit_localbooleanOptional—#/properties/worktree/properties/inherit_localsource
sessionsobjectOptional{"additionalProperties":true}#/properties/sessionssource
sessions.muxstringOptional{"enum":["auto","tmux","zellij","none"]}#/properties/sessions/properties/muxsource
startuparrayOptional—#/properties/startupsource
startup[].namestringOptional—#/properties/startup/items/anyOf/1/properties/namesource
startup[].runstringOptional—#/properties/startup/items/anyOf/1/properties/runsource
startup[].commandstringOptional—#/properties/startup/items/anyOf/1/properties/commandsource
startup[].cwdstringOptional—#/properties/startup/items/anyOf/1/properties/cwdsource
startup[].persistentbooleanOptional—#/properties/startup/items/anyOf/1/properties/persistentsource
startup[].singletonobjectOptional{"additionalProperties":false}#/properties/startup/items/anyOf/1/properties/singletonsource
startup[].singleton.portsarrayRequired{"minItems":1,"uniqueItems":true}#/properties/startup/items/anyOf/1/properties/singleton/properties/portssource
startup[].singleton.onConflictstringOptional{"enum":["adopt","fail"]}#/properties/startup/items/anyOf/1/properties/singleton/properties/onConflictsource
lifecycleobjectOptional{"additionalProperties":false}#/properties/lifecyclesource
lifecycle.upobjectOptional{"additionalProperties":false}#/properties/lifecycle/properties/upsource
lifecycle.up.beforearrayOptional—#/properties/lifecycle/properties/up/properties/beforesource
lifecycle.up.before[].namestringOptional—#/properties/lifecycle/properties/up/properties/before/items/anyOf/1/properties/namesource
lifecycle.up.before[].commandstringRequired—#/properties/lifecycle/properties/up/properties/before/items/anyOf/1/properties/commandsource
lifecycle.up.before[].cwdstringOptional—#/properties/lifecycle/properties/up/properties/before/items/anyOf/1/properties/cwdsource
lifecycle.up.before[].persistentbooleanOptional—#/properties/lifecycle/properties/up/properties/before/items/anyOf/1/properties/persistentsource
lifecycle.up.before[].singletonobjectOptional{"additionalProperties":false}#/properties/lifecycle/properties/up/properties/before/items/anyOf/1/properties/singletonsource
lifecycle.up.before[].singleton.portsarrayRequired{"minItems":1,"uniqueItems":true}#/properties/lifecycle/properties/up/properties/before/items/anyOf/1/properties/singleton/properties/portssource
lifecycle.up.before[].singleton.onConflictstringOptional{"enum":["adopt","fail"]}#/properties/lifecycle/properties/up/properties/before/items/anyOf/1/properties/singleton/properties/onConflictsource
lifecycle.up.afterarrayOptional—#/properties/lifecycle/properties/up/properties/aftersource
lifecycle.up.after[].namestringOptional—#/properties/lifecycle/properties/up/properties/after/items/anyOf/1/properties/namesource
lifecycle.up.after[].commandstringRequired—#/properties/lifecycle/properties/up/properties/after/items/anyOf/1/properties/commandsource
lifecycle.up.after[].cwdstringOptional—#/properties/lifecycle/properties/up/properties/after/items/anyOf/1/properties/cwdsource
lifecycle.up.after[].persistentbooleanOptional—#/properties/lifecycle/properties/up/properties/after/items/anyOf/1/properties/persistentsource
lifecycle.up.after[].singletonobjectOptional{"additionalProperties":false}#/properties/lifecycle/properties/up/properties/after/items/anyOf/1/properties/singletonsource
lifecycle.up.after[].singleton.portsarrayRequired{"minItems":1,"uniqueItems":true}#/properties/lifecycle/properties/up/properties/after/items/anyOf/1/properties/singleton/properties/portssource
lifecycle.up.after[].singleton.onConflictstringOptional{"enum":["adopt","fail"]}#/properties/lifecycle/properties/up/properties/after/items/anyOf/1/properties/singleton/properties/onConflictsource
lifecycle.downobjectOptional{"additionalProperties":false}#/properties/lifecycle/properties/downsource
lifecycle.down.beforearrayOptional—#/properties/lifecycle/properties/down/properties/beforesource
lifecycle.down.before[].namestringOptional—#/properties/lifecycle/properties/down/properties/before/items/anyOf/1/properties/namesource
lifecycle.down.before[].commandstringRequired—#/properties/lifecycle/properties/down/properties/before/items/anyOf/1/properties/commandsource
lifecycle.down.before[].cwdstringOptional—#/properties/lifecycle/properties/down/properties/before/items/anyOf/1/properties/cwdsource
lifecycle.down.before[].persistentbooleanOptional—#/properties/lifecycle/properties/down/properties/before/items/anyOf/1/properties/persistentsource
lifecycle.down.before[].singletonobjectOptional{"additionalProperties":false}#/properties/lifecycle/properties/down/properties/before/items/anyOf/1/properties/singletonsource
lifecycle.down.before[].singleton.portsarrayRequired{"minItems":1,"uniqueItems":true}#/properties/lifecycle/properties/down/properties/before/items/anyOf/1/properties/singleton/properties/portssource
lifecycle.down.before[].singleton.onConflictstringOptional{"enum":["adopt","fail"]}#/properties/lifecycle/properties/down/properties/before/items/anyOf/1/properties/singleton/properties/onConflictsource
lifecycle.down.afterarrayOptional—#/properties/lifecycle/properties/down/properties/aftersource
lifecycle.down.after[].namestringOptional—#/properties/lifecycle/properties/down/properties/after/items/anyOf/1/properties/namesource
lifecycle.down.after[].commandstringRequired—#/properties/lifecycle/properties/down/properties/after/items/anyOf/1/properties/commandsource
lifecycle.down.after[].cwdstringOptional—#/properties/lifecycle/properties/down/properties/after/items/anyOf/1/properties/cwdsource
lifecycle.down.after[].persistentbooleanOptional—#/properties/lifecycle/properties/down/properties/after/items/anyOf/1/properties/persistentsource
lifecycle.down.after[].singletonobjectOptional{"additionalProperties":false}#/properties/lifecycle/properties/down/properties/after/items/anyOf/1/properties/singletonsource
lifecycle.down.after[].singleton.portsarrayRequired{"minItems":1,"uniqueItems":true}#/properties/lifecycle/properties/down/properties/after/items/anyOf/1/properties/singleton/properties/portssource
lifecycle.down.after[].singleton.onConflictstringOptional{"enum":["adopt","fail"]}#/properties/lifecycle/properties/down/properties/after/items/anyOf/1/properties/singleton/properties/onConflictsource
lifecycle.processesarrayOptional—#/properties/lifecycle/properties/processessource
lifecycle.processes[].namestringRequired—#/properties/lifecycle/properties/processes/items/properties/namesource
lifecycle.processes[].commandstringRequired—#/properties/lifecycle/properties/processes/items/properties/commandsource
lifecycle.processes[].cwdstringOptional—#/properties/lifecycle/properties/processes/items/properties/cwdsource
lifecycle.processes[].singletonobjectOptional{"additionalProperties":false}#/properties/lifecycle/properties/processes/items/properties/singletonsource
lifecycle.processes[].singleton.portsarrayRequired{"minItems":1,"uniqueItems":true}#/properties/lifecycle/properties/processes/items/properties/singleton/properties/portssource
lifecycle.processes[].singleton.onConflictstringOptional{"enum":["adopt","fail"]}#/properties/lifecycle/properties/processes/items/properties/singleton/properties/onConflictsource
controlPlaneobjectOptional{"additionalProperties":true}#/properties/controlPlanesource
controlPlane.tuiobjectOptional{"additionalProperties":true}#/properties/controlPlane/properties/tuisource
controlPlane.tui.logsobjectOptional{"additionalProperties":true}#/properties/controlPlane/properties/tui/properties/logssource
controlPlane.tui.logs.maxEntriesnumberOptional—#/properties/controlPlane/properties/tui/properties/logs/properties/maxEntriessource
controlPlane.tui.logs.maxLinesnumberOptional—#/properties/controlPlane/properties/tui/properties/logs/properties/maxLinessource
controlPlane.tui.logs.historyTailStepnumberOptional—#/properties/controlPlane/properties/tui/properties/logs/properties/historyTailStepsource
controlPlane.usageobjectOptional{"additionalProperties":true}#/properties/controlPlane/properties/usagesource
controlPlane.usage.watchIntervalMsnumberOptional—#/properties/controlPlane/properties/usage/properties/watchIntervalMssource
controlPlane.usage.historySizenumberOptional—#/properties/controlPlane/properties/usage/properties/historySizesource
controlPlane.daemonobjectOptional{"additionalProperties":true}#/properties/controlPlane/properties/daemonsource
controlPlane.daemon.autoStartbooleanOptional—#/properties/controlPlane/properties/daemon/properties/autoStartsource

Aliases and selection

Prefer env.defaultOverlay for the default overlay. The reader checks env.defaultOverlay before env.default_overlay; nested env selection precedes legacy defaultEnvConfig, which in turn precedes default_env_config. These nested fields are read even though the legacy generated schema does not enumerate the env object. worktree.autoBranch is an alias of worktree.auto_branch; a non-null snake_case value is selected before the camelCase alias, then parsed as a boolean. Use one spelling rather than conflicting aliases.

worktree.inheritLocal is also read as an alias of worktree.inherit_local in this version; the same non-null snake_case precedence applies. It controls eligible local configuration inheritance in the legacy linked-worktree path; it does not make every ignored file or native state inheritable.

Effective fallbacks

FieldFallbackScope
logs.follow_backend"compose"consumer fallback, not schema default
logs.snapshot_backend"loki"consumer fallback, can fall back or be explicitly forced
startup[].persistentfalsereader/workflow default documented in lifecycle
worktree.auto_branchtruereader/caller default; linked checkouts only
values.global{}parser normalization
environmentnullselected layer environment fallback, not a fixed literal
branchRegistry.branches[]missing-file writer default, not proof invalid files are rewritten

Log preferences are not forced backend selection. Follow mode prefers Compose; snapshots prefer Loki, with consumer-specific fallback. startup[].persistent defaults false. Linked-worktree auto-branch selection defaults on in the legacy Compose path; an ordinary checkout remains the base instance. Follow the runtime-specific command guide.

Hooks and processes

startup accepts string shorthand or objects. Startup objects require at least one of run or command. The reader prefers run and drops entries whose selected command is empty. They accept optional name/cwd, and persistent (false by default). lifecycle.up.before/after and lifecycle.down.before/after are hook arrays; their command-object variants require command. Do not transfer the startup-only run spelling to every hook. lifecycle.processes names long-lived processes and requires name and command. singleton.ports contains unique positive ports; singleton.onConflict selects adopt or fail. Read Lifecycle for working-directory origins, ordering, ownership and failure behavior.

Scope exclusions

Retained gateway, cluster, supervisor, shared/broker ownership and extension-manager fields are not a supported hosted product API. Legacy secret-backend strategy fields are separate from the managed YAML format below. Neither permissive unknown keys nor a retained schema field makes a backend qualified. Internal daemon, guest and compiler transport types are not public API specifications.

Managed environment YAML

Files such as .hack/hack.env.default.yaml use values, not the older JSON vars format. Use hack env to manage values and Share environment and secrets for key handling. Examples must use placeholders, never real secret values.

FieldType / requirement
versionliteral 1; required
environmentstring; optional; reader falls back to selected file/layer environment
secretsproviderliteral project_key; required
valuesscope-to-entry map; required object
values.{scope}key-to-value map; each scope must be an object; omitted global normalized to {}
values.{scope}.{KEY}string | number | boolean | null | secure object; null accepted by parser and removal during later merge; scalar/secure accepted
values.{scope}.{KEY}.securenonempty string; required for object-valued stored entry; ciphertext format is interpreted elsewhere

version: 1, secretsprovider: project_key, and an object values are required. Each scope is an object. Scope names match ^[a-z0-9][a-z0-9._-]*$; keys match ^[A-Z_][A-Z0-9_]*$. Missing values.global becomes an empty object. The environment falls back to the selected layer; an example containing environment: default does not establish a universal default. Secure values require a nonempty secure string; valid shape alone does not prove decryption or key availability.

This version accepts YAML null as a removal marker.

The parser selects recognized fields; this is not a closed JSON-schema promise. The legacy hack.env.json schema describes a different file format.

Branch registry

.hack/hack.branches.json records CLI-managed branch metadata, not live container ownership. Use branch commands rather than hand-editing runtime directories.

FieldTypeSchema requirementConstraints
$schemastringOptional{}
versionintegerRequired{"const":1}
branchesarrayRequired{}
branches[].namestringRequired{"minLength":1}
branches[].slugstringRequired{"pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1}
branches[].notestringOptional{}
branches[].created_atstringOptional{"format":"date-time"}
branches[].last_used_atstringOptional{"format":"date-time"}

name is the human/Git branch name; slug is its runtime-safe identifier. note is an annotation. Usage updates fill a missing created_at and refresh last_used_at; neither timestamp proves a running instance or permits deleting data. A missing registry starts empty. Invalid JSON is reported. The parser drops invalid entries and narrows recognized fields, so it does not enforce every schema pattern/date format/unknown-key constraint.


Source: next.5 field audit · docs/reference/cli.md.

On this page