hack.foo
Reference

Command and output contracts

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.

Pinned source: 28de2f8902d3776c3da9326e7ae6c6aa6e7f69bc. This supplements the generated command reference. Command registration and document shape do not establish backend admission.

Scope and coverage

The pinned source inventory has 92 leaves, 335 leaf-owned option occurrences, and 611 effective option occurrences. The recommended v5 publication selection retains 84 leaves, 288 own option occurrences and 540 effective occurrences (three global/built-in flags per leaf). Eight retiring agent-setup leaves and init's optional handoff flag are intentionally excluded; they remain available in the released source. The six additional leaf sections below complete the pinned generated reference within the retained command scope. No declared effective flags or short aliases are missing from matching sections; generic value placeholders explain initial spelling-only differences. Counts are occurrences, not unique names. Parent namespaces are not leaves.

Retired gateway/node/remote/dispatch, hosted account/team/Tickets, internal helpers, extension dispatch and fun commands are excluded. SSH remote access is excluded. Retained fields within local commands do not establish support for retired backends.

The retired agent instruction-management commands (hack setup sync, standalone hack setup exports and hack agent prime) are omitted; in v5 they refuse with a retirement notice. See Agent integrations.

Global flags and parsing

Every leaf accepts --no-interactive, --help, -h, and --version, -v. The first also has HACK_NO_INTERACTIVE=1; it applies documented defaults or refuses required interaction. Help/version return early with status 0. These are the only inherited flags: parent options are not inherited. Omitted booleans parse false; omitted strings/numbers parse undefined. Handler/config fallbacks are separate. A nonboolean OptionSpec defaultValue supplies a value when the flag is present without its value; it is not an unconditional omitted-flag default.

Additional command details

hack global dns preview

Preview a scoped native custom-domain DNS claim or the hack.local relay repair without changing the host.

Arguments: none.

OptionTypeMeaning / declared fallback
--jsonbooleanOutput JSON (machine-readable)
--domain v5.hack.gystringSuffix to inspect: a custom suffix, or hack.local for the native relay repair (default: a custom global default_domain)
--no-interactivebooleanNever prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1)
--help, -hbooleanShow help
--version, -vbooleanShow version

Source: src/commands/global.ts:232 (globalDnsPreviewSpec). No command alias is declared.

hack global dns activate

Activate only the selected native custom-domain DNS suffix.

Arguments: none.

OptionTypeMeaning / declared fallback
--domain v5.hack.gystringCustom suffix to activate (default: a custom global default_domain)
--no-interactivebooleanNever prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1)
--help, -hbooleanShow help
--version, -vbooleanShow version

Source: src/commands/global.ts:252 (globalDnsActivateSpec). No command alias is declared.

hack global dns deactivate

Remove an owned native custom-domain DNS suffix, or undo the hack.local relay repair.

Arguments: none.

OptionTypeMeaning / declared fallback
--domain v5.hack.gystringCustom suffix to deactivate, or hack.local to undo the native relay repair (default: a custom global default_domain)
--no-interactivebooleanNever prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1)
--help, -hbooleanShow help
--version, -vbooleanShow version

Source: src/commands/global.ts:270 (globalDnsDeactivateSpec). No command alias is declared.

hack project owner show

Show the local ownership metadata for the current project.

Arguments: none.

OptionTypeMeaning / declared fallback
--path, -p <dir>stringRun a project command against a repo path (overrides cwd search)
--project <name>stringTarget a registered project by name (from ~/.hack/projects.json)
--jsonbooleanOutput JSON (machine-readable)
--no-interactivebooleanNever prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1)
--help, -hbooleanShow help
--version, -vbooleanShow version

Source: src/commands/project-admin.ts:16 (ownerShowSpec). No command alias is declared.

hack env backend status

Show configured env/secret backend strategy.

Arguments: none.

OptionTypeMeaning / declared fallback
--jsonbooleanOutput JSON (machine-readable)
--no-interactivebooleanNever prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1)
--help, -hbooleanShow help
--version, -vbooleanShow version

Source: src/commands/env.ts:428 (backendStatusSpec). No command alias is declared.

hack env backend use <backend>

Select env/secret backend strategy.

Arguments: backend — required.

OptionTypeMeaning / declared fallback
--provider <aws|gcp|azure|vault>stringCloud secret provider when backend is cloud
--store-path <path>stringEncrypted file path when backend is encrypted_file
--key-path <path>stringStable key file path when backend is encrypted_file
--provision-keybooleanProvision a stable key file for encrypted_file backend
--secret-project <id>stringOptional cloud project/account identifier
--secret-prefix <prefix>stringOptional cloud secret name prefix
--jsonbooleanOutput JSON (machine-readable)
--no-interactivebooleanNever prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1)
--help, -hbooleanShow help
--version, -vbooleanShow version

Source: src/commands/env.ts:437 (backendUseSpec). No command alias is declared.

Complete public leaf and flag inventory

“Present” means a matching usage section; flags were compared separately. It does not prove every handler default is described. All rows also accept the three global/built-in flags above. Arguments are exact spec names.

Leaf usageOwn flags (aliases and value hints)Pinned generated section
hack global installnonePresent
hack global dns preview--json; --domain v5.hack.gyMissing; drafted above
hack global dns activate--domain v5.hack.gyMissing; drafted above
hack global dns deactivate--domain v5.hack.gyMissing; drafted above
hack global upnonePresent
hack global downnonePresent
hack global status--jsonPresent
hack global logs [service]--follow, -f; --no-follow; --tail <n>; --prettyPresent
hack global ca--printPresent
hack global cert <hosts...>--install; --out <dir>Present
hack global trustnonePresent
hack global logs-resetnonePresent
hack global authorizenonePresent
hack status--project <name>; --include-global; --all; --meta; --jsonPresent
hack usage--project <name>; --details; --include-global; --watch; --interval <value>; --no-host; --jsonPresent
hack projects prune--project <name>; --include-global; --dry-run; --jsonPresent
hack project owner show--path, -p <dir>; --project <name>; --jsonMissing; drafted above
hack init--path, -p <dir>; --manual; --auto; --name <slug>; --dev-host <host>; --oauth; --oauth-tld <tld>; --no-discoveryPresent
hack up [services...]--path, -p <dir>; --project <name>; --env <name|base|default>; --branch <name>; --detach, -d; --profile <name[,name...]>; --target <auto|local|remote>; --jsonPresent
hack down--path, -p <dir>; --project <name>; --env <name|base|default>; --branch <name>; --profile <name[,name...]>; --target <auto|local|remote>; --prune-caches; --yes; --json; --recoverPresent
hack restart [services...]--path, -p <dir>; --project <name>; --env <name|base|default>; --branch <name>; --profile <name[,name...]>; --target <auto|local|remote>; --json; --recover-frontend; --expect-finalization-attempt <32-hex>; --expect-frontend-pid <pid>Present
hack ps--path, -p <dir>; --project <name>; --branch <name>; --profile <name[,name...]>; --jsonPresent
hack tui--path, -p <dir>; --project <name>Present
hack run <service> [cmd...]--path, -p <dir>; --project <name>; --env <name|base|default>; --branch <name>; --workdir <path>; --profile <name[,name...]>Present
hack exec <service> [cmd...]--path, -p <dir>; --project <name>; --env <name|base|default>; --branch <name>; --workdir <path>; --profile <name[,name...]>Present
hack logs [service]--path, -p <dir>; --project <name>; --branch <name>; --follow, -f; --no-follow; --tail <n>; --pretty; --json; --profile <name[,name...]>; --compose; --loki; --services <csv>; --query <logql>; --since <time>; --until <time>Present
hack open [target]--path, -p <dir>; --project <name>; --branch <name>; --prefer <auto|alias|dev>; --jsonPresent
hack branch add <name>--path, -p <dir>; --project <name>; --note <text>Present
hack branch list--path, -p <dir>; --project <name>Present
hack branch remove <name>--path, -p <dir>; --project <name>Present
hack branch open <name>--path, -p <dir>; --project <name>; --prefer <auto|alias|dev>Present
hack log-pipe--format <auto|docker-compose|plain>; --stream <stdout|stderr>Present
hack doctor--path, -p <dir>; --fix; --migrate-env-config; --domain-migration preview|apply|rollback; --json; --browser-url https://app.hack; --browser-result unknown|works|fails|permission-denied; --branch <name>; --native-cleanup inspect; --native-run-mapping inspect|repair; --expect-selection <64-hex>; --accept-legacy-device-rebindPresent
hack crash-capture--path, -p <dir>; --since <duration>Present
hack daemon start--foregroundPresent
hack daemon stopnonePresent
hack daemon restartnonePresent
hack daemon status--jsonPresent
hack daemon metricsnonePresent
hack daemon logs--tail <n>Present
hack daemon clearnonePresent
hack daemon install--run-at-load; --no-run-at-load; --gui-only; --no-gui-onlyPresent
hack daemon uninstallnonePresent
hack secrets set [name]--service <service>Present
hack secrets get [name]--service <service>Present
hack secrets delete [name]--service <service>Present
hack env list--path, -p <dir>; --project <name>; --env <name|base|default>; --json; --show-secrets; --service <global|service>Present
hack env get <key>--path, -p <dir>; --project <name>; --env <name|base|default>; --service <global|service>Present
hack env explain <key>--path, -p <dir>; --project <name>; --env <name|base|default>; --json; --service <global|service>; --target <host|compose>Present
hack env apply--path, -p <dir>; --project <name>; --env <name|base|default>; --json; --service <global|service>Present
hack env add [key] [value]--path, -p <dir>; --project <name>; --env <name|base|default>; --secret; --value-stdin; --local; --service <global|service>Present
hack env set [key] [value]--path, -p <dir>; --project <name>; --env <name|base|default>; --secret; --value-stdin; --local; --service <global|service>Present
hack env materialize--path, -p <dir>; --project <name>; --env <name|base|default>; --service <global|service>Present
hack env exec [command...]--path, -p <dir>; --project <name>; --env <name|base|default>; --service <global|service>; --target <host|compose>; --shell <command>; --timeout <seconds>; --lifetime <command|persistent>Present
hack env shell--path, -p <dir>; --project <name>; --env <name|base|default>; --service <global|service>; --target <host|compose>Present
hack env unset [key]--path, -p <dir>; --project <name>; --env <name|base|default>; --local; --service <global|service>Present
hack env backend status--jsonMissing; drafted above
hack env backend use <backend>--provider <aws|gcp|azure|vault>; --store-path <path>; --key-path <path>; --provision-key; --secret-project <id>; --secret-prefix <prefix>; --jsonMissing; drafted above
hack host ps--project <name>; --jsonPresent
hack host exec [command...]--path, -p <dir>; --project <name>; --env <name|base|default>; --scope <global|service>; --target <host|compose>; --shell <command>; --timeout <seconds>; --lifetime <command|persistent>Present
hack host shell--path, -p <dir>; --project <name>; --env <name|base|default>; --scope <global|service>; --target <host|compose>Present
hack config get <key>--path, -p <dir>; --project <name>; --globalPresent
hack config set <key> <value>--path, -p <dir>; --project <name>; --globalPresent
hack config validate--file <path>; --profile <names>; --domain <suffix>; --path, -p <dir>; --env <name|base|default>; --jsonPresent
hack config plan--profile <names>; --domain <suffix>; --path, -p <dir>; --env <name|base|default>; --jsonPresent
hack config import--dry-run; --path, -p <dir>; --jsonPresent
hack config adopt--stop; --dry-run; --rollback; --recover; --branch <value>; --path, -p <dir>; --jsonPresent
hack mcp servenonePresent
hack mcp print--bundle <directory>; --cli <executable>; --runtime-directory <directory>; --scope <user|project>; --path, -p <dir>; --all; --cursor; --claude; --codexPresent
hack setup tmux--check; --removePresent
hack session listnonePresent
hack session start [project]--up; --new; --name <value>; --detach, -d; --env <name|base|default>; --service <global|service>Present
hack session stop <workspace>nonePresent
hack session attach <workspace>nonePresent
hack session exec <workspace> <command>--env <name|base|default>; --service <global|service>Present
hack session panes <workspace>--json; --prettyPresent
hack session capture <workspace>--target <target>; --lines <n>; --json; --prettyPresent
hack session tail <workspace>--target <target>; --lines <n>; --interval-ms <ms>; --max-ms <ms>; --json; --prettyPresent
hack agent patternsnonePresent
hack agent init--path, -p <dir>; --client, -c <cursor|claude|codex|print>Present
hack agent onboard--path, -p <dir>Present
hack update--check; --yes; --tag <tag>; --jsonPresent
hack versionnonePresent
hack help [path...]--allPresent

Declared defaults and option semantics

This table preserves declarations/descriptions that state defaults. Other handler/backend defaults are not implied by absence here.

Leaf / optionSource declaration
hack global dns preview / --domain v5.hack.gySuffix to inspect: a custom suffix, or hack.local for the native relay repair (default: a custom global default_domain)
hack global dns activate / --domain v5.hack.gyCustom suffix to activate (default: a custom global default_domain)
hack global dns deactivate / --domain v5.hack.gyCustom suffix to deactivate, or hack.local to undo the native relay repair (default: a custom global default_domain)
hack global logs [service] / --follow, -fFollow logs (default for hack logs)
hack global logs [service] / --tail <n>Tail last N log lines Flag-present fallback: 200.
hack global cert <hosts...> / --out <dir>Directory for generated cert/key (default: ~/.hack/certs)
hack init / --autoRun non-interactive init with sensible defaults
hack init / --name <slug>Project slug (default: repo name)
hack init / --dev-host <host>DEV_HOST override (new projects use global default_domain, or hack.local)
hack init / --oauth-tld <tld>OAuth alias TLD override (default: gy)
hack up [services...] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack down / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack restart [services...] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack run <service> [cmd...] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack exec <service> [cmd...] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack logs [service] / --follow, -fFollow logs (default for hack logs)
hack logs [service] / --tail <n>Tail last N log lines Flag-present fallback: 200.
hack log-pipe / --format <auto|docker-compose|plain>How to parse incoming lines from stdin Flag-present fallback: auto.
hack log-pipe / --stream <stdout|stderr>Treat stdin as stdout or stderr (stderr forces ERROR level + writes to stderr) Flag-present fallback: stdout.
hack doctor / --browser-result unknown|works|fails|permission-deniedYour manual browser observation for --browser-url (default: unknown)
hack daemon logs / --tail <n>Tail last N log lines Flag-present fallback: 200.
hack daemon install / --gui-onlyOnly run in GUI sessions (default)
hack secrets set [name] / --service <service>Override Bun.secrets service name Flag-present fallback: hack-cli.
hack secrets get [name] / --service <service>Override Bun.secrets service name Flag-present fallback: hack-cli.
hack secrets delete [name] / --service <service>Override Bun.secrets service name Flag-present fallback: hack-cli.
hack env list / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack env get <key> / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack env explain <key> / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack env explain <key> / --target <host|compose>Env view for host commands (default: host rewrites container-oriented addresses for local host execution)
hack env apply / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack env add [key] [value] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack env set [key] [value] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack env materialize / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack env exec [command...] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack env exec [command...] / --target <host|compose>Env view for host commands (default: host rewrites container-oriented addresses for local host execution)
hack env exec [command...] / --lifetime <command|persistent>Declare intended lifetime for diagnostics (default: command; does not detach)
hack env shell / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack env shell / --target <host|compose>Env view for host commands (default: host rewrites container-oriented addresses for local host execution)
hack env unset [key] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack host exec [command...] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack host exec [command...] / --target <host|compose>Env view for host commands (default: host rewrites container-oriented addresses for local host execution)
hack host exec [command...] / --lifetime <command|persistent>Declare intended lifetime for diagnostics (default: command; does not detach)
hack host shell / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack host shell / --target <host|compose>Env view for host commands (default: host rewrites container-oriented addresses for local host execution)
hack config validate / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack config plan / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack mcp print / --scope <user|project>Write MCP config to user or project scope Flag-present fallback: user.
hack session start [project] / --newCreate an isolated workspace instead of reusing the default project workspace
hack session start [project] / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack session exec <workspace> <command> / --env <name|base|default>Select an env overlay by name; omit for the configured default overlay, or use 'base' or 'default' for base layers only
hack session capture <workspace> / --target <target>Tmux pane target (default: active pane)
hack session capture <workspace> / --lines <n>Number of lines to capture Flag-present fallback: 200.
hack session tail <workspace> / --target <target>Tmux pane target (default: active pane)
hack session tail <workspace> / --lines <n>Number of lines to capture Flag-present fallback: 200.
hack session tail <workspace> / --interval-ms <ms>Polling interval in milliseconds Flag-present fallback: 500.
hack session tail <workspace> / --max-ms <ms>Stop tailing after N milliseconds Flag-present fallback: 5000.

Ownership inspection

project owner show searches from cwd or --path, or selects a registered --project; do not combine path/project. Missing project and config parse failures refuse. JSON success is a bare object and exits 0:

FieldType and meaning
project_rootstring; resolved root
project_slugstring or null; sanitized configured name, null if blank
ownership.modelocal/shared
ownership.owner_typeuser/team/organization
ownership.owner_idstring or null
ownership.managed_bylocal/broker

Defaults are local/user/null/local. These are retained local metadata, not hosted team/broker support. No owner mutation leaf exists here.

Env backend strategy

Status reads effective settings for cwd's project when found, global settings otherwise. It takes no project/path/env selectors. Use writes global settings and rereads global settings. It does not migrate YAML project-key values or establish cloud-provider qualification.

Backend is required: exactly keychain, encrypted_file or cloud. Provider accepts exactly aws|gcp|azure|vault and is required for cloud even if a provider was previously configured. Invalid nonempty backend/provider is a usage error. Inputs are trimmed; empty optional paths/project/prefix are omitted. Store/key paths apply only to encrypted_file; cloud project/prefix apply only with cloud/provider. Omitted settings are retained. Provision-key defaults false and applies only to encrypted_file.

Fresh schema defaults: keychain, allow_env_auth_refs true, store_plaintext_in_backend false; file path ~/.hack/secrets.enc.json, key path ~/.hack/secrets-file.key; cloud prefix hack, provider/project unspecified. These are config defaults, not flag defaults reapplied on every use. The key environment variable name is HACK_SECRETS_FILE_KEY. Providers describe retained compatibility strategies, not qualified cloud onboarding.

Both JSON successes are bare objects and return 0:

Fieldstatususe
backendselected enumselected enum
allow_env_auth_refsbooleanboolean
store_plaintext_in_backendbooleanboolean
encrypted_fileobject: string path/keyPathsame
encrypted_file_key_envstring variable namesame
cloudobject: optional provider/project strings, string secretPrefix; undefined properties omittedsame
statusobject belowabsent
encrypted_file_key_provisionedabsentnull or {keyPath:string, source:env/file/keychain/generated}

Status has string storage_mode/trust_model/portability/plaintext_compatibility and classification. Classification has string trust_model/custody/portability and shared_state (local_only/plaintext_compatible/portable_bundle/broker_managed). These descriptive names do not grant remote/team features.

JSON results and exits

The generated page's universal envelope claim is too broad. Decode by command and backend. The shared helper emits {ok:true,data:T} or {ok:false,error:{code,message,detail?}}; detail is unknown. Its mapper returns 0/1. Handlers can instead return child exit codes, bare objects, reports or JSON-lines.

Thrown usage errors with an explicit --json token become E_USAGE; other thrown errors preserve HackCliError codes or become E_UNEXPECTED, with exit 1. Returning 1 directly does not automatically create an error envelope. Unknown command or namespace paths may print help and exit 1. Help/version return early with status 0, including when JSON was requested. Valid JSON alone proves neither success nor readiness.

CommandOutput contractExit / open shape
up/down/restart, retained Compose ownershared envelope; data action (up/down/restart), project:string, branch:string/null, composeProject:string, services.{started,completed,stopped,failed}:sorted string arrays, durationMs:number; optional cacheVolumesRemoved:string[]JSON up implies detach. Structured startup/lifecycle failures use error envelope.
ps, Composebare {project,branch,composeProject,items}; branch nullable; items parsed engine recordsdaemon-assisted JSON may be forwarded; engine rows are open. Compose failure can return child nonzero with stderr and no success object.
openbare {url:string}JSON reports URL; does not launch browser
projects/statusbare listing belowruntime_ok false is report data, not necessarily command failure
projects pruneshared envelope, preview/apply variants belowdry-run reports candidates; apply reports removals
project owner showbare ownership object abovesuccess 0
env backend status/usebare strategy objects abovesuccess 0
env listbare modern-YAML or legacy report belowraw report may include values
env applyforwards restart service --path repo with selected env/JSON flagsreturns child restart output and exit code, not an env-list report; native subset/JSON limits still apply
env explainbare value-free explanation belowinspect available/scope; no value
doctorshared envelope with checks[], summary:string[], counts.{ok,warn,error}:numberscan emit ok:true and exit 1 when checks contain errors
usagebare projects[], total nullable, host[], host_total nullable, runtime_ok:boolean, runtime_error nullable; details adds containers[]failures exit 1; optional error string. No samples exits 0 with warning:no_usage_samples. Watch uses the interactive redraw path even with JSON selected; do not treat watch as a JSON report stream.
global statusbare generated_at/caddy/logging/networks/gateway/summaryexits 0 even if summary health false; gateway is retained unsupported data, excluded from public contract
daemon statusbare report belowrunning returns 0; starting/stale/unavailable may return 1
host psbare {generatedAt,snapshotAvailable,commands,lifecycle}timestamp string, availability boolean; nested telemetry remains specialized
session panes/capture/tailJSON-lines events belowno shared envelope
updatecommand-owned object with ok:boolean, string error on failureerror is not shared error.{code,message}; success varies by check/install outcome; exit follows ok

Config get has no JSON flag: non-string values serialize as JSON, strings print plainly. Daemon metrics prints retained metrics JSON without a JSON flag; nested internal transport data is not a supported general API. MCP serve speaks MCP; log-pipe formats a stream. Other leaves without JSON do not inherit it.

Report details

Direct projects/status fields: generated_at, filter, include_global, include_unregistered, include_meta, runtime_ok, runtime_error, runtime_checked_at, runtime_last_ok_at, runtime_reset_at, runtime_reset_count, runtime_reset_summary, runtime_reset_changes, runtime_last_repair_at, runtime_repair_action, runtime_repair_outcome, runtime_next_step, projects[]. Optional detail_level:summary selects summary projection. Project records use summary/full projections with optional meta. Nullable recovery metadata is not liveness proof; nested engine/meta variants remain open.

Prune preview and apply are separate shapes. Apply includes runtimeOk/runtimeError, removedRegistryEntries[] (id/name/repoRoot/projectDir/reason), removedOrphanedProjects[] (project/workingDir/reason/containerCount), removedContainerCount. Preview includes dryRun:true, runtimeOk, registryCandidates[] (name/projectDir/reason), orphanedProjects[] and candidateContainerCount. It does not add runtimeError merely because apply has it. Orphan records are typed in the table below.

Doctor checks contain id/status/detail/durationMs; status is ok/warn/error. summary is string[]; counts are numbers. Additional diagnostics depend on version/check and remain specialized shapes.

Daemon status fields: status, running, api_ok, api_reachable, api_compatible, process_running, stale, stale_reason, issue, next_step, pid, socket_path, socket_exists, log_path, log_exists, launchd. Launchd is null or {installed,loaded,running,pid,exit_status,plist_path}. Unavailable/nullable observations must not be treated as proof of process absence or authority to signal a PID.

Env explain: key:string, available/secret:boolean, format:project_env_config_v1/legacy_env_contract; environment/effective_scope/source:string|null; requested_scope:string, target:host/compose, delivered_to/precedence:string[]. It emits no value.

Env list: project and env_selection (requested/default/effective selections, overlay_path, overlay_exists). Modern YAML adds format:project_env_config_v1, selected_scope, scopes, files, unknown_scopes, status/storage descriptions, vars[], missing_required. Legacy reports have storage/status, materialization and key projections. Rows in vars[] contain key/required/source/services/resolved_from/storage/value. Secret values are masked unless show-secrets is explicitly selected; ordinary plaintext is not thereby hidden. Modern reports include materialized when show-secrets is selected, otherwise materialized_keys. Legacy reports additionally contain warnings[] (kind/key/overlay_path/services/message). CLI reports differ from MCP's narrower value-free keys projection. Nested modern/legacy variants remain versioned report shapes; application values are not new stable reference keys.

Compose/Loki log records

Logs JSON is newline-delimited events, not an array or envelope. Finite snapshots and follow share vocabulary. Follow is default; no-follow requests finite output. Omitted tail falls back to 200. JSON conflicts with pretty; compose conflicts with explicit Loki selection (loki/services/query/since/until); follow with until refuses.

Event fieldPresence / type
typerequired start/log/heartbeat/error/end
tsrequired string; ISO generation time or log entry timestamp
backendoptional in declared type; builders include compose/loki
project/branchoptional strings, omitted without context
servicesoptional string[], start context when supplied
followoptional boolean; start builder includes it
since/untiloptional strings, start context when supplied
entryoptional LogJsonEntry; log includes it
messageoptional string; error includes it
reasonoptional string; end includes nonempty reason

Compose ends with eof or exit:. Loki finite snapshots can end without reason; handled query failure emits error/end(error), follow ends closed/error. Error can precede start. Heartbeat has a builder, but these emitters do not establish periodic delivery. End settles a stream, not a workload.

Entry fieldType / meaning
sourcerequired compose/loki
message/rawrequired strings: parsed message/original line
streamoptional stdout/stderr, Compose
project/service/instanceoptional strings from context/prefix/labels
labelsoptional string-to-string map, Loki
timestampoptional ISO string
timestamp_nsoptional nanosecond timestamp string, not number
leveloptional debug/info/warn/error after normalization
fieldsoptional string-to-string map of application fields

Optional fields are omitted, not declared nullable. Map keys are open application data. The TypeScript declaration is not a runtime-validated closed JSON schema. Global logs has no JSON option.

Session JSON-lines

Panes/capture/tail are tmux inspection surfaces and default to JSON unless pretty is selected. Capture/tail default to active target and 200 lines. Tail defaults interval-ms to 500 and max-ms to 5000. JSON and pretty together refuse. Panes snapshots emit start, log per pane, end(snapshot); capture emits log per captured line and end(snapshot). Tail emits changes and a finite budget ends with timeout. Refusals can precede event creation.

All events have type start/log/error/end, ts:string (ISO), session:string. Pane logs add pane:{target:string,active:boolean,windowIndex:number,windowName:string,paneIndex:number,command:string,path:string|null}. Capture/tail events also have target:string, lines:number, follow:boolean, optional intervalMs/maxMs:number. Log adds line:string; error adds message:string; end may add reason:string. These are separate from project log entry/backend events.

Remaining limits

Leaf/flag presence is reconciled. Handler defaults outside the reviewed tables are not an exhaustive semantic audit. Engine rows, optional diagnostic subtypes, listing metadata, update success variants, nested env variants and candidate reports remain bounded open/specialized shapes. No closed schema, backend parity, client-loading proof or installed runtime acceptance is claimed. Config-file/MCP field work remains in the separate audit. Private compiler/daemon/guest/provider protocols and retired APIs are excluded.

v5 native support limits

The inventory preserves retained Compose contracts. A listed flag is not proof of native admission. next.5 has no project task leaves; no newer task/target contract is backported.

Authored native projects require explicit native backend selection on macOS, separately prepared matching provider/runtime, absolute native binary and private native home. The pinned TypeScript authored frontend admits whole-project foreground up/restart, owner-mediated down and explicit bounded recovery, saved-run ps, finite service logs with no-follow, noninteractive service exec and one-off run at source level. Up/restart refuse detach/JSON and service subsets. Source/storage/routing/network/lifecycle admission remains bounded by the pinned authored-command guide. This is experimental support, not Compose parity.

Authored native ps JSON uses the shared envelope: data.backend:native, status:not_started/pending/runtime_not_running/observed, run/phase:string|null, items[]. Authored items have service/container/state:string, health:string|null, exitCode:number|null. The separate legacy native projection has statuses not_started/runtime_not_running/observed/owner_unconfirmed/runtime_degraded and item fields service:string, container:string|null, phase/state:string, health:string|null, exitCode:number|null. Fresh observations supply health/state; saved readiness/phase is historical. Ownership uncertainty can refuse.

The legacy native graph logs path returns bare {backend:native,run,service,container,stdout,stderr,truncated}; strings except truncated:boolean (container reflects selected owned row). Authored finite logs uses the same top-level names with container:string; neither should be parsed as Compose/Loki events. Authored service grammar is [A-Za-z0-9_.-]{1,128}, and tail is an integer 1–1000, default 200. Only bounded service/no-follow/tail/JSON selection is admitted; profiles, explicit backend overrides, service lists, query/time filters and pretty refuse. The retained legacy native Compose frontend has narrower admissions than authored native: do not borrow authored run/restart support.

Candidate-only DNS

The source hint v5.hack.gy is an example suffix, not a fixed literal. Omission uses configured custom global default_domain; an unset/built-in default does not silently claim hack.local/hack/hack.gy.

All three leaves require explicit macOS native candidate selection. Preview performs inspection, not host writes. Custom preview JSON: {ok:true,data:{domain,status,dnsmasqPath,resolverPath,receiptPath,address,activation}}. Fields are strings except activation:string[]; status available/active describes disk/receipt state, not live DNS proof.

Explicit hack.local preview returns a route report with dnsmasqPath/resolverPath/receiptPath:string, receiptState nullable, status current/repairable/refused. Current adds relayPort and optional command; repairable adds oldLine/newLine/resolverAction/relayPort/command; refused adds reason/detail and optional command. Preview can exit 0 with refused data.status.

Activate has no JSON and refuses hack.local, which uses doctor repair. Making a new custom claim requires interactive confirmation/admin authorization and unchanged inspected inputs; an already active claim is verified. Deactivate has no JSON: it removes only an owned custom claim and verifies fallback resolution, or explicitly rolls back hack.local repair. Changed/unproven inputs refuse. There is no yes/force bypass flag.

Other v5 report differences

Config validate/plan print candidate reports directly, with transport_version/ok and diagnostics or success projections. Transport failure is {transport_version:1,ok:false,error:{code,message}}. Import dry-run and adopt preview print complete/fields reports; completed adoption has its own operation report. These evolving CLI projections do not publish internal compiler transport, plan, journal or guest DTOs.

Listing can add filter_redacted:true; v4 lacks this. Doctor adds check-dependent supersededRoots/hackLocalRoute/envKey diagnostics; nested variants remain specialized.

Sensitive env-get failures use fixed stderr-only text and status 1, even if unsupported JSON was supplied. This does not add a JSON option.

Parent command sections

These sections are also present in the pinned reference. Some parents handle direct invocation (for example projects/session); namespace options do not pass to children. Counts above count terminal leaves only.

SectionOwn options; all also have global/built-ins
hack project
hack project owner
hack branch
hack config
hack session
hack global
hack global dns
hack projects--project <name>; --details; --summary; --timings; --no-daemon; --meta; --include-global; --all; --json
hack daemon
hack mcp
hack setup
hack agent
hack secrets--service <service>
hack env
hack env backend
hack host

Stable shared error codes

E_DOCKER_UNAVAILABLE, E_GLOBAL_INFRA_DOWN, E_CONFIG_PARSE, E_CONFIG_INVALID, E_PROJECT_NOT_FOUND, E_NATIVE_PROJECT_CONFLICT, E_NATIVE_PROJECT_UNSUPPORTED, E_NATIVE_COMPOSE_PROXY_ACCESS, E_SERVICE_NOT_FOUND, E_COMPOSE_FAILED, E_STARTUP_INCOMPLETE, E_DEPENDENCY_BOOTSTRAP_FAILED, E_STARTUP_TIMEOUT, E_LIFECYCLE_FAILED, E_ENV_KEY_MISSING, E_PERMISSION, E_INTERACTIVE_REQUIRED, E_USAGE, E_UNEXPECTED. Optional error.detail is unknown; direct-return failures need not use this envelope.

Update success fields: ok:true, current/latest:string, updateAvailable/installed:boolean, target:{platform:string,arch:string}, binaryPath/assetsDir:string, optional mutagen provisioning report. Handled failure is {ok:false,error:string}.

DNS relay-report fields: relayPort:number; oldLine/newLine/command/detail:string; resolverAction:keep/create; receiptState is null or the retained repair receipt state. Custom address is a string. Report paths/lines are descriptive and do not grant ownership or repair authority.

Typed corrections for generated value placeholders

These were display-only mismatches, not missing flags. The generated <value> placeholder means a value is required when the flag is used; none of these options has a short alias or an OptionSpec defaultValue.

Command / exact spellingTypeOmission / handler behavior
hack usage --interval <value>number, millisecondsOmitted: configured usage.watchIntervalMs. Finite positive input is floored and clamped to at least 250 ms; nonpositive/invalid resolved interval falls back to 2000 ms. Watch uses human redraw output.
hack session start [project] --name <value>string; workspace suffixOmitted: reuse base workspace unless --new requests the next numeric suffix. A truthy supplied suffix is passed to the session-name builder; it is not a project selector.
hack config adopt --branch <value>string; exact existing branch instanceOmitted: no explicit branch option. This selects existing adoption identity; it does not create a branch or inherit to other config leaves.

Prune preview field types

The preview uses the shared success envelope. Its data object is:

FieldType / meaning
dryRunliteral true
runtimeOkboolean; whether runtime inventory succeeded
registryCandidatesarray of {name:string, projectDir:string, reason:string}
orphanedProjectsarray of {project:string, workingDir:string
candidateContainerCountnumber; sum of orphan container IDs

Preview omits runtimeError. A successful envelope describes a completed preview, not a guarantee that the runtime is healthy. Apply has the distinct removal fields already listed above. Neither form is permission to delete resources.

Exact native admission and launcher boundary

All claims here are source admission, not runtime-verified or installed-release support.

Path at next.5Exact evidence and boundary
Authored TypeScript frontendsrc/lib/native-compose-command.ts:2380 dispatches selected authored input to tryNativeAuthoredCommand. src/lib/native-authored-command.ts:273 commandMode explicitly admits run through assertCommandOptions; :182 assertForegroundOptions admits restart. RUNNERS at :602 and :621 call the separate authored one-off and restart implementations.
Authored runsrc/lib/native-authored-command.ts:765 assertCommandOptions requires macOS, a single service, nonempty literal argv and optional absolute workdir; rejects JSON, profiles/env overrides, service lists, recover/detach/log options and unsupported options. src/backends/native-authored-exec-options.ts:3 caps argv at 256, each argument at 16 KiB, total at 64 KiB, forbids NUL; workdir at most 4096 bytes. Command execution also requires closed stdin/no TTY and a proven live authored owner; no generic execution fallback is promised.
Authored restartsrc/lib/native-authored-command.ts:527 runRestart uses restartNativeAuthoredProject, sequencing proven owned stop before fresh foreground startup. :182 refuses detach/JSON/recover/subsets/command/workdir/log options and non-macOS. Failure can leave the project stopped; no automatic replay or cross-backend restart guarantee.
Legacy native graphA separate backend/source path, not evidence for authored one-off run/restart. Its retained public frontend refusal boundary must remain separate; graph-internal operation names are not public project-command support.
Relocatable candidate launcherscripts/hack-v5.sh:4–15 requires absolute HACK_NATIVE_HOME and adjacent executable hack-cli/hack-native; sets native backend/binary and forwards argv to adjacent hack-cli. It has no independent command-admission matrix. This establishes source forwarding only, not that every published/installed bundle contains a matching capable frontend/executor/provider.
Checkout launcherhack-local:1–23 is a separate checkout-bound entry point into hack-runtime-candidate, not the relocatable public frontend or an installed-artifact qualification.

The pinned comparison table and authored dispatch describe different admission boundaries. Use the source-specific distinctions above; source admission does not qualify a provider or application. Installed matching-bundle acceptance and live provider behavior remain unverified. Task leaves absent at next.5 remain excluded.


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

On this page