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.
| Option | Type | Meaning / declared fallback |
|---|---|---|
--json | boolean | Output JSON (machine-readable) |
--domain v5.hack.gy | string | Suffix to inspect: a custom suffix, or hack.local for the native relay repair (default: a custom global default_domain) |
--no-interactive | boolean | Never prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1) |
--help, -h | boolean | Show help |
--version, -v | boolean | Show 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.
| Option | Type | Meaning / declared fallback |
|---|---|---|
--domain v5.hack.gy | string | Custom suffix to activate (default: a custom global default_domain) |
--no-interactive | boolean | Never prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1) |
--help, -h | boolean | Show help |
--version, -v | boolean | Show 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.
| Option | Type | Meaning / declared fallback |
|---|---|---|
--domain v5.hack.gy | string | Custom suffix to deactivate, or hack.local to undo the native relay repair (default: a custom global default_domain) |
--no-interactive | boolean | Never prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1) |
--help, -h | boolean | Show help |
--version, -v | boolean | Show 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.
| Option | Type | Meaning / declared fallback |
|---|---|---|
--path, -p <dir> | string | Run a project command against a repo path (overrides cwd search) |
--project <name> | string | Target a registered project by name (from ~/.hack/projects.json) |
--json | boolean | Output JSON (machine-readable) |
--no-interactive | boolean | Never prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1) |
--help, -h | boolean | Show help |
--version, -v | boolean | Show 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.
| Option | Type | Meaning / declared fallback |
|---|---|---|
--json | boolean | Output JSON (machine-readable) |
--no-interactive | boolean | Never prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1) |
--help, -h | boolean | Show help |
--version, -v | boolean | Show 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.
| Option | Type | Meaning / declared fallback |
|---|---|---|
--provider <aws|gcp|azure|vault> | string | Cloud secret provider when backend is cloud |
--store-path <path> | string | Encrypted file path when backend is encrypted_file |
--key-path <path> | string | Stable key file path when backend is encrypted_file |
--provision-key | boolean | Provision a stable key file for encrypted_file backend |
--secret-project <id> | string | Optional cloud project/account identifier |
--secret-prefix <prefix> | string | Optional cloud secret name prefix |
--json | boolean | Output JSON (machine-readable) |
--no-interactive | boolean | Never prompt: apply documented defaults or fail with E_INTERACTIVE_REQUIRED (also via HACK_NO_INTERACTIVE=1) |
--help, -h | boolean | Show help |
--version, -v | boolean | Show 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 usage | Own flags (aliases and value hints) | Pinned generated section |
|---|---|---|
hack global install | none | Present |
hack global dns preview | --json; --domain v5.hack.gy | Missing; drafted above |
hack global dns activate | --domain v5.hack.gy | Missing; drafted above |
hack global dns deactivate | --domain v5.hack.gy | Missing; drafted above |
hack global up | none | Present |
hack global down | none | Present |
hack global status | --json | Present |
hack global logs [service] | --follow, -f; --no-follow; --tail <n>; --pretty | Present |
hack global ca | --print | Present |
hack global cert <hosts...> | --install; --out <dir> | Present |
hack global trust | none | Present |
hack global logs-reset | none | Present |
hack global authorize | none | Present |
hack status | --project <name>; --include-global; --all; --meta; --json | Present |
hack usage | --project <name>; --details; --include-global; --watch; --interval <value>; --no-host; --json | Present |
hack projects prune | --project <name>; --include-global; --dry-run; --json | Present |
hack project owner show | --path, -p <dir>; --project <name>; --json | Missing; drafted above |
hack init | --path, -p <dir>; --manual; --auto; --name <slug>; --dev-host <host>; --oauth; --oauth-tld <tld>; --no-discovery | Present |
hack up [services...] | --path, -p <dir>; --project <name>; --env <name|base|default>; --branch <name>; --detach, -d; --profile <name[,name...]>; --target <auto|local|remote>; --json | Present |
hack down | --path, -p <dir>; --project <name>; --env <name|base|default>; --branch <name>; --profile <name[,name...]>; --target <auto|local|remote>; --prune-caches; --yes; --json; --recover | Present |
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...]>; --json | Present |
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>; --json | Present |
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-rebind | Present |
hack crash-capture | --path, -p <dir>; --since <duration> | Present |
hack daemon start | --foreground | Present |
hack daemon stop | none | Present |
hack daemon restart | none | Present |
hack daemon status | --json | Present |
hack daemon metrics | none | Present |
hack daemon logs | --tail <n> | Present |
hack daemon clear | none | Present |
hack daemon install | --run-at-load; --no-run-at-load; --gui-only; --no-gui-only | Present |
hack daemon uninstall | none | Present |
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 | --json | Missing; 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>; --json | Missing; drafted above |
hack host ps | --project <name>; --json | Present |
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>; --global | Present |
hack config set <key> <value> | --path, -p <dir>; --project <name>; --global | Present |
hack config validate | --file <path>; --profile <names>; --domain <suffix>; --path, -p <dir>; --env <name|base|default>; --json | Present |
hack config plan | --profile <names>; --domain <suffix>; --path, -p <dir>; --env <name|base|default>; --json | Present |
hack config import | --dry-run; --path, -p <dir>; --json | Present |
hack config adopt | --stop; --dry-run; --rollback; --recover; --branch <value>; --path, -p <dir>; --json | Present |
hack mcp serve | none | Present |
hack mcp print | --bundle <directory>; --cli <executable>; --runtime-directory <directory>; --scope <user|project>; --path, -p <dir>; --all; --cursor; --claude; --codex | Present |
hack setup tmux | --check; --remove | Present |
hack session list | none | Present |
hack session start [project] | --up; --new; --name <value>; --detach, -d; --env <name|base|default>; --service <global|service> | Present |
hack session stop <workspace> | none | Present |
hack session attach <workspace> | none | Present |
hack session exec <workspace> <command> | --env <name|base|default>; --service <global|service> | Present |
hack session panes <workspace> | --json; --pretty | Present |
hack session capture <workspace> | --target <target>; --lines <n>; --json; --pretty | Present |
hack session tail <workspace> | --target <target>; --lines <n>; --interval-ms <ms>; --max-ms <ms>; --json; --pretty | Present |
hack agent patterns | none | Present |
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>; --json | Present |
hack version | none | Present |
hack help [path...] | --all | Present |
Declared defaults and option semantics
This table preserves declarations/descriptions that state defaults. Other handler/backend defaults are not implied by absence here.
| Leaf / option | Source declaration |
|---|---|
hack global dns preview / --domain v5.hack.gy | Suffix 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.gy | Custom suffix to activate (default: a custom global default_domain) |
hack global dns deactivate / --domain v5.hack.gy | Custom suffix to deactivate, or hack.local to undo the native relay repair (default: a custom global default_domain) |
hack global logs [service] / --follow, -f | Follow 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 / --auto | Run 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, -f | Follow 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-denied | Your 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-only | Only 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] / --new | Create 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:
| Field | Type and meaning |
|---|---|
project_root | string; resolved root |
project_slug | string or null; sanitized configured name, null if blank |
ownership.mode | local/shared |
ownership.owner_type | user/team/organization |
ownership.owner_id | string or null |
ownership.managed_by | local/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:
| Field | status | use |
|---|---|---|
backend | selected enum | selected enum |
allow_env_auth_refs | boolean | boolean |
store_plaintext_in_backend | boolean | boolean |
encrypted_file | object: string path/keyPath | same |
encrypted_file_key_env | string variable name | same |
cloud | object: optional provider/project strings, string secretPrefix; undefined properties omitted | same |
status | object below | absent |
encrypted_file_key_provisioned | absent | null 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.
| Command | Output contract | Exit / open shape |
|---|---|---|
| up/down/restart, retained Compose owner | shared 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, Compose | bare {project,branch,composeProject,items}; branch nullable; items parsed engine records | daemon-assisted JSON may be forwarded; engine rows are open. Compose failure can return child nonzero with stderr and no success object. |
| open | bare {url:string} | JSON reports URL; does not launch browser |
| projects/status | bare listing below | runtime_ok false is report data, not necessarily command failure |
| projects prune | shared envelope, preview/apply variants below | dry-run reports candidates; apply reports removals |
| project owner show | bare ownership object above | success 0 |
| env backend status/use | bare strategy objects above | success 0 |
| env list | bare modern-YAML or legacy report below | raw report may include values |
| env apply | forwards restart service --path repo with selected env/JSON flags | returns child restart output and exit code, not an env-list report; native subset/JSON limits still apply |
| env explain | bare value-free explanation below | inspect available/scope; no value |
| doctor | shared envelope with checks[], summary:string[], counts.{ok,warn,error}:numbers | can emit ok:true and exit 1 when checks contain errors |
| usage | bare 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 status | bare generated_at/caddy/logging/networks/gateway/summary | exits 0 even if summary health false; gateway is retained unsupported data, excluded from public contract |
| daemon status | bare report below | running returns 0; starting/stale/unavailable may return 1 |
| host ps | bare {generatedAt,snapshotAvailable,commands,lifecycle} | timestamp string, availability boolean; nested telemetry remains specialized |
| session panes/capture/tail | JSON-lines events below | no shared envelope |
| update | command-owned object with ok:boolean, string error on failure | error 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 field | Presence / type |
|---|---|
| type | required start/log/heartbeat/error/end |
| ts | required string; ISO generation time or log entry timestamp |
| backend | optional in declared type; builders include compose/loki |
| project/branch | optional strings, omitted without context |
| services | optional string[], start context when supplied |
| follow | optional boolean; start builder includes it |
| since/until | optional strings, start context when supplied |
| entry | optional LogJsonEntry; log includes it |
| message | optional string; error includes it |
| reason | optional 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 field | Type / meaning |
|---|---|
| source | required compose/loki |
| message/raw | required strings: parsed message/original line |
| stream | optional stdout/stderr, Compose |
| project/service/instance | optional strings from context/prefix/labels |
| labels | optional string-to-string map, Loki |
| timestamp | optional ISO string |
| timestamp_ns | optional nanosecond timestamp string, not number |
| level | optional debug/info/warn/error after normalization |
| fields | optional 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.
| Section | Own 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 spelling | Type | Omission / handler behavior |
|---|---|---|
hack usage --interval <value> | number, milliseconds | Omitted: 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 suffix | Omitted: 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 instance | Omitted: 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:
| Field | Type / meaning |
|---|---|
| dryRun | literal true |
| runtimeOk | boolean; whether runtime inventory succeeded |
| registryCandidates | array of {name:string, projectDir:string, reason:string} |
| orphanedProjects | array of {project:string, workingDir:string |
| candidateContainerCount | number; 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.5 | Exact evidence and boundary |
|---|---|
| Authored TypeScript frontend | src/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 run | src/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 restart | src/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 graph | A 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 launcher | scripts/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 launcher | hack-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.