Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 62 additions & 3 deletions docs/guides/candidate-install.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,68 @@ Leave `HACK_RUNTIME_BACKEND` unset, or set it to `native`, to return to the nati
default. A shell that exported `HACK_RUNTIME_BACKEND=compose` for other work also
selects Compose for `hack-next`; unset it before native testing.

The bundled `hack-v5` entrypoint follows the same rule for manual bundles:
unset selects native and requires `HACK_NATIVE_HOME`; `compose` needs no native
home and uses your own Hack home.
The bundled `hack-v5` entrypoint follows the same backend rule for manual bundles.
Native defaults to `~/.hack/native-runtime`, or `$HACK_HOME/native-runtime` when
`HACK_HOME` is selected. An absolute `HACK_NATIVE_HOME` overrides that default.
Selecting a home creates nothing; setup creates missing directories privately
after consent. Existing homes must be owned by you, mode 0700, and have no symlink
components. `compose` needs no native home and uses your own Hack home.

### Prepare the native runtime once

Use the candidate frontend for both setup and project commands:

```sh
hack-next native setup
hack-next doctor --native-preflight
hack-next up -d
```

The command is `native setup` because it prepares native provider files without
starting a VM or changing the Compose backend. It lists the pinned downloads,
sizes, SHA-256 hashes, cache and destination, then asks once. Scripts use
`hack-next native setup --accept-downloads --json`; JSON never prompts and passes
the runtime's setup result through unchanged. Completed files are verified and
reused; interrupted downloads resume. The complete offline archive input form is
also available; see [provider setup](native-candidate.md).

Preflight reports runtime installation separately from project review, in text
and in the JSON `runtime_setup` item. A fresh or interrupted home blocks startup
with `hack native setup` as its fix. Noninteractive `up` refuses before starting
an owner; interactive `up` offers the same pinned setup and continues only after
successful setup and a fresh readiness check. Record readiness is a quick check;
startup still verifies prepared content before executing it.

![Native first-use flow](native-first-use.svg)

Diagram [source](native-first-use.mmd); rendered with Pele 1.9.0.

Managed `hack-next` keeps its version's receipt-owned `native-home` so upgrades
can find and stop its runtime. It refuses a differing `HACK_NATIVE_HOME` rather
than silently ignoring it. Use that version's bundle `hack-v5` launcher for a
custom home. To move a manual bundle's home, stop its projects and runtime using
the old home and matching executor, preserve the old home for retained data, then
select a fresh absolute `HACK_NATIVE_HOME` and run `native setup` again. Setup
does not migrate live receipts, disks or project data. The machine home is
distinct from each project's `.hack/native/` adaptation directory.
An explicit `native setup` selects the native home even when the surrounding
shell sets `HACK_RUNTIME_BACKEND=compose`; ordinary Compose commands still remove
native selectors.

The frontend passes only system environment variables to setup; project values,
credentials and proxy variables are excluded. Downloads need direct HTTPS access;
use the offline inputs where a proxy is required. Invalid prepared trees and pin
mismatches are preserved and need their own repair or a fresh home, rather than
an endless setup retry. Setup-only homes permit managed upgrades only after an
existing-lock quiescence check; unexpected or busy state still refuses. As with
the previous empty-home check, a detached process that has not created any state
is outside this observation's proof.

Older candidate executors cannot prove the new setup-only quiescence predicate.
If an older selected version was set up but never started, finish its setup,
start a project with that old version's `hack-next up`, then run `hack-next down`
before upgrading. Its runtime must report `stopped`. An interrupted or unknown
old home still refuses an upgrade; do not remove its receipts to bypass the check.

### Stop stable hackd before a Compose run

Expand Down
51 changes: 37 additions & 14 deletions docs/guides/native-candidate.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,11 @@ mkdir -m 700 /absolute/private/candidate-home
./hack-native --candidate-root /absolute/private/candidate-home --version
```

The home must already exist, be owned by the current user, and have mode `0700`.
The home must already exist, be owned by the current user, and have mode `0700`,
except that `runtime setup` and its read-only `inspect` accept an absent home.
Setup creates missing directories privately after consent.
Use its canonical absolute path without symlink components (on macOS, use
`/private/tmp` rather than `/tmp`). Every command requires this explicit home,
`/private/tmp` rather than `/tmp`). Every lower-level `hack-native` command requires this explicit home,
including help and version. Its `checkout` field is the historical receipt name
for this stable home; `channel` reports `installed-candidate`. State remains under
`<home>/.hack-local`. Keep this home fixed across binary upgrades: receipts and
Expand All @@ -110,11 +112,12 @@ an active home or adopting another installation's state is not.

For normal project commands, follow the short
[native start page](https://hack.foo/docs/v5/native/start). Manual bundle users
use the adjacent `hack-v5` entrypoint with an explicit `HACK_NATIVE_HOME`;
keep the bundle together. The [candidate installer guide](candidate-install.md#test-both-backends)
use the adjacent `hack-v5` entrypoint and keep the bundle together. It defaults to
`$HACK_HOME/native-runtime` or `~/.hack/native-runtime`; an absolute
`HACK_NATIVE_HOME` overrides that default. The [candidate installer guide](candidate-install.md#test-both-backends)
defines backend selectors, private versus shared homes, stable-daemon quiescence
and returning to Compose. Neither entrypoint prepares the provider, migrates a
project or falls back to Docker for an unsupported native command. An unversioned
and returning to Compose. Prepare the provider explicitly with `native setup`.
Neither entrypoint migrates a project or falls back to Docker for an unsupported native command. An unversioned
local build reports its repository version; only a versioned bundle includes
candidate version provenance. The entrypoint alone does not identify a release.
`hack-v5` passes arguments, exit codes and signals through `exec`; it never replaces
Expand Down Expand Up @@ -202,7 +205,9 @@ Environment-file findings may name their source path.
The runtime review half needs a native runtime, so run the preflight from the
`hack-next` launcher for the full list. Without native selection only the CLI's
checks run and the review is reported as `skipped`. The review needs no running
VM.
VM. A selected runtime also receives a read-only setup inspection. Incomplete or
unavailable setup is a `native_runtime_setup` blocker; run `hack native setup`
before retrying. Without native selection, setup is reported as unavailable.

Use a matching updated CLI and runtime. A runtime without start-admission review
is reported as `unavailable` with an update hint and cannot produce `ready: true`.
Expand Down Expand Up @@ -231,6 +236,12 @@ With `--json` the report is the `data` of the standard result envelope:
"backend": "native",
"compose_file": ".hack/docker-compose.yml",
"ready": false,
"runtime_setup": {
"state": "ready",
"installation_state": "ready",
"code": "native_setup_ready",
"fix": "Native runtime is set up."
},
"runtime_review": { "status": "completed" },
"blockers": [
{
Expand All @@ -247,8 +258,8 @@ With `--json` the report is the `data` of the standard result envelope:
}
```

- `ready` is true only when there is no blocker and the runtime review
completed.
- `ready` is true only when there is no blocker, setup is ready and the runtime
review completed.
- The exit status follows the blockers: `0` with none, `1` otherwise. A skipped
or unavailable review is not a blocker, so that run exits `0` with
`ready: false`. With `--json` the envelope is `ok: true` in both cases; read
Expand Down Expand Up @@ -277,7 +288,7 @@ With `--json` the report is the `data` of the standard result envelope:
`unsupported_build_form`, `emulated_build`, `environment_file_input`, `missing_image`,
`extra_hosts_without_dependencies`, `unsupported_logging`, `invalid_restart`,
`unsupported_label`, `invalid_http_probe`, `managed_env_unreadable`,
`environment_delivery`, `shared_source_grant_required`,
`environment_delivery`, `native_runtime_setup`, `shared_source_grant_required`,
`route_probe_required` and `too_many_bridges`. Runtime findings use the
review's own diagnostic codes, for example `privileged_service` or
`invalid_mount`, and `review_incompatible` when the review does not admit the
Expand Down Expand Up @@ -915,12 +926,23 @@ For ordinary setup and consent, use the short
The remainder describes the setup and recovery contract. `--no-interactive` (or
truthy `HACK_NO_INTERACTIVE` values `1`, `true`, `yes` or `on`, ignoring case and
surrounding whitespace) refuses with `E_INTERACTIVE_REQUIRED` unless
`--accept-downloads` explicitly consents. No provider download happens from `up`,
the installer, the probe or any other implicit path. The optional BuildKit client
`--accept-downloads` explicitly consents. Interactive `up` can offer setup with
the same explicit consent; noninteractive `up` refuses until setup is complete.
The installer and probe never download provider files. The optional BuildKit client
is still prepared separately below.
Setup lists the pinned SmolVM, Docker engine and four Alpine guest packages,
including exact compressed sizes, hosts, hashes, private cache and destinations.

Manual bundle frontends use `$HACK_HOME/native-runtime` or
`~/.hack/native-runtime` by default, with an absolute `HACK_NATIVE_HOME` override.
Managed `hack-next` uses the version's receipt-owned home. See
[native first use and moving homes](candidate-install.md#prepare-the-native-runtime-once).
The lower-level `hack-native --candidate-root /absolute/private/home runtime setup`
remains available for explicit runtime administration. Its read-only
`runtime setup inspect --json` reports installation records without creating a
home, acquiring a lease or hashing provider trees. Only the manager's
`--quiescence` inspection takes existing locks; startup verifies full content.

The executable embeds `provider-pins.json` and checks its hashes against the
manual preparation pins. HTTPS redirects may use only the original host and the
pin's explicit `redirect_hosts`. The GitHub release pin allows
Expand Down Expand Up @@ -2530,8 +2552,9 @@ PID, path or depth in the file. Replace the authority fields with exactly one of
- `"host_lifecycle": "NAME"`: a persistent `up.before` hook (its `name`, or
`hook-N` when unnamed) or a `lifecycle.processes` entry of this instance. Hack
reads the pane PID from its lifecycle state and requires the live tmux session
to carry the recorded ownership token and that pane to be alive. zellij
sessions record no pane PID and refuse.
to carry the recorded ownership token and that pane to be alive. Interactive
workspaces require tmux; legacy zellij lifecycle records have no pane PID and
refuse. See [sessions and migration](../sessions.md).
- `"host_shared_helper": "NAME"`: an enabled `lifecycle.sharedHelpers` entry
whose claim is `owned` and `ready`, lists this instance as a holder, and whose
PID and birth time are live. An adopted helper refuses.
Expand Down
18 changes: 18 additions & 0 deletions docs/guides/native-first-use.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
flowchart TD
Up["hack up"] --> Inspect["Inspect installation"]
Inspect --> Ready{"Ready?"}
Ready -->|Yes| Start["Review project and start"]
Ready -->|No| Offer{"Interactive and resumable?"}
Offer -->|No| Refuse["Refuse with guidance"]
Offer -->|Yes| Consent{"Accept pinned downloads?"}
Consent -->|No| Refuse
Consent -->|Yes| Setup["Verify and prepare files"]
Setup -->|Success| Reinspect["Re-inspect installation"]
Reinspect --> Installed{"Ready after setup?"}
Installed -->|Yes| Start
Installed -->|No| Refuse
Setup -->|Failed or interrupted| Refuse
class Start ok
class Refuse fail
class Setup live
class Consent wait
Loading
Loading