diff --git a/docs/guides/native-candidate.md b/docs/guides/native-candidate.md index 648dbc57c..421f36272 100644 --- a/docs/guides/native-candidate.md +++ b/docs/guides/native-candidate.md @@ -4112,9 +4112,11 @@ command exit code, and never falls back to Compose. With piped input/output or `HACK_NO_INTERACTIVE=1`, it uses finite exec with a 30-second observation budget; a timeout may leave the command running and is not retried. `--env` and `--profile` changes are refused. A command name such as `bun` -uses the selected container's PATH; no host PATH or implicit shell is used. Normal -`hack exec` resolves the saved startup overlay and AWS profile again, and delivers -fresh selected-service values through private stdin. +uses the selected container's PATH; no host PATH or implicit shell is used. For +adopted Compose services, `hack exec` resolves the saved startup overlay and AWS profile again, and delivers +fresh selected-service managed, allowed caller-shell and env-file values through +private stdin. These values can differ from startup; use `hack restart` when +the running service must receive changed inputs too. Each request binds the reviewed plan, current container and generation, and has its own short ingress lifetime. Startup leases and files are not renewed or rewritten. The allocation is selected from the current container's exact read-only mounts and @@ -4123,7 +4125,7 @@ by earlier restores do not compete with this selection; pending, mismatched or ambiguous mounted allocations are refused. Legacy mappings without explicit selectors and services with older launcher mounts refuse before execution; restart with the matching candidate to adopt this path. -Services without managed values use ordinary exec. The native live qualification +Services with no private values to deliver use ordinary exec. The native live qualification of this fresh-delivery path remains separate from its unit and transport tests. With terminal stdin and stdout in the foreground, `hack exec SERVICE -- /bin/sh` selects interactive diff --git a/docs/guides/v5-release-notes.md b/docs/guides/v5-release-notes.md index 2e6f71e37..91a8f5c0c 100644 --- a/docs/guides/v5-release-notes.md +++ b/docs/guides/v5-release-notes.md @@ -5,7 +5,8 @@ > [Install a prerelease](candidate-install.md). Hack 5 keeps the v4 project model and commands. Your `.hack/` folder, encrypted env -values, branch instances, lifecycle processes and sessions carry over, and Docker +values, branch instances and lifecycle processes carry over; interactive +workspaces require tmux, with the zellij stop procedure below. Docker Compose stays the default backend. The release tightens how Hack handles commands and env, makes agent integrations opt-in, and introduces a native backend as a beta. `hack dev`, added in 4.3.0, is part of the core. @@ -20,17 +21,39 @@ release is published. Check the installed candidate's version and release notes before using a new flag or changing a script. An installed next.16 bundle keeps its original behavior. +### Breaking change: zellij workspaces removed + +`hack session` now requires tmux. Zellij is removed; `auto` detects tmux only. +Project/global `sessions.mux=zellij` and `HACK_SESSIONS_MUX=zellij` refuse, +including during `hack global install`. Install tmux, remove the old setting +and environment override, or set `sessions.mux` to `tmux`. Existing zellij +workspaces are neither stopped nor migrated. + +**Before upgrading a project with saved zellij lifecycle state**, keep zellij +installed and use the retained v4 CLI to run `hack down` for that project. +Confirm its lifecycle processes stopped and take a fresh private backup before +switching to v5. Keep the earlier copy too, but use the stopped-state backup for +rollback so it does not restore live zellij state. If already upgraded, +return to the retained v4 CLI for that stop. V5 start, restart and down refuse +saved zellij lifecycle state they cannot verify or stop. Changing the setting +alone does not clear it; do not delete or edit managed state to bypass the refusal. +See [the upgrade stop procedure](../versions/v5/guides/upgrade-from-v4.md#breaking-change-zellij-workspaces-removed) +and [sessions](../sessions.md). + +### Env, native input and log changes + | Change | What to do | | --- | --- | +| **Native accepts Compose service `env_file`.** Strings, ordered lists and long-form entries support optional missing files and `format: raw`; unsafe or unreadable active files refuse. Container precedence is managed env, explicit service environment, ordered files, then image defaults. | Keep files inside the project root and follow the [environment-file rules](../native/environment-files.md). Dotenv is an interpolation source, not automatic service injection. The Compose backend keeps its behavior. | | **Native reads `.hack/.env` on every start and preflight, even with managed env.** Symlinks, other-owner or group/other-writable files and project ancestors refuse, as do `COMPOSE_*`/`HACK_*` keys and dotted/dashed identifiers. | Use an owned regular file, deliberately correct permissions, remove control entries and rename unsupported identifiers, or move values into managed env. A sibling `.env.state.json` also refuses possible materialized output; deliberately retire that output after moving to managed env. | -| **Native service-environment defaults take allowed shell values.** Shell presence can change normalized declarations and plan identity, without storing values in that identity. | Unset the exported name to retain the authored fallback. In projects with `env_file` or adjacent `.env`, public-field references to ambient values now refuse even with a default: unset the source or write a public literal. Without those file sources, public defaults keep their previous behavior. | +| **Native service-environment defaults take allowed shell values.** Shell presence can change normalized declarations and plan identity, without storing values in that identity. | Unset the exported name to retain the authored fallback. In projects with `env_file` or adjacent `.env`, public-field references to ambient values now refuse even with a default: unset the source or write a public literal. Authored fallbacks for newly file-backed names are frozen before private ownership; runtime-bound compounds refuse. Without those file sources, public defaults keep their previous behavior. | | **An unresolved bare service-environment key is now unset instead of empty, including in projects without env files.** It removes an image default; an older runtime that cannot confirm the unset names refuses the review. Reserved runtime/adapter-owned names keep their existing behavior. | Use a matching current CLI/runtime bundle. Write `KEY: ""` when you intend an explicitly empty value instead of removing the key. | | **Fresh native `hack exec` now delivers allowed caller-shell and selected-service file values privately.** Shell delivery also changes projects without env files; exec values may differ from those used at service startup. | Run exec from the intended shell and environment selection. Restart the service when changed inputs should also replace its startup environment; exec alone does not do that. | | **Native removes `dotenv_without_managed_env`.** A project-root `.env` outside the Compose directory is now ignored with one names-only notice. | Move required inputs beside Compose (normally `.hack/.env`) or into managed env. Dotenv alone does not inject service variables. | -| **Native preflight reads the caller's allowed environment and decrypts managed env.** A missing key becomes a structured blocker; the report remains usable. | Run from the intended shell and recover the existing project key when asked. Do not generate a replacement key for existing ciphertext. | -| **Native env-file paths must stay separate from build inputs.** Contexts, Dockerfiles and Dockerfile-specific ignore inputs may not overlap declared env files, adjacent `.env` or a present project-root `.env`, including optional and inactive paths. A root `.env` triggers this refusal even when there is no `env_file` or adjacent `.env`; ignored for interpolation does not exclude it from `COPY .`. | Use disjoint build inputs or prebuilt images. The build-argument value guard stays limited to nonempty managed `secret: true` values, with no minimum length; plain file and shell values do not widen it. See [the full rules](../native/environment-files.md). | +| **Native preflight reads the caller's allowed environment and decrypts managed env.** A missing key becomes a structured `managed_env_unreadable` blocker; the report remains usable. | Run from the intended shell and recover the existing project key when asked. Do not generate a replacement key for existing ciphertext. | +| **Native env-file paths must stay separate from build inputs.** Contexts, Dockerfiles and Dockerfile-specific ignore inputs may not overlap declared env files, adjacent `.env` or a present project-root `.env`, including optional and inactive paths. A root `.env` triggers this refusal even when there is no `env_file` or adjacent `.env`; ignored for interpolation does not exclude it from `COPY .`. Authored ignore rules do not lift this refusal. | Use disjoint build inputs or prebuilt images. The build-argument value guard stays limited to nonempty managed `secret: true` values, with no minimum length; plain file and shell values do not widen it. See [the full rules](../native/environment-files.md). | | **Native plain `logs SERVICE --follow` output changes.** It now prints application-text lines, matching a finite snapshot, instead of adding a `SERVICE \| ` prefix. Both service streams go to stdout; Hack notices go to stderr. | Stop parsing the old plain prefix. Use `--json` and the log event's `entry.service`, `entry.stream` and `entry.message` when a script needs those fields. Use `--timestamps` to request Engine timestamps. | -| **Env listings hide values by default, including migrated plaintext.** Ordinary `env` / `env list` text and JSON output are metadata. JSON omits `value` and reports `has_value`. | Use `has_value` for availability checks. For a value a script actually needs, call `hack env get KEY` with the same `--env` and `--service`; that command prints plaintext. Bulk `--show-values` requires interactive stdin and stdout; `--show-secrets` remains an alias. | +| **Breaking: env listings hide values by default, including migrated plaintext.** Ordinary `env` / `env list` text and JSON output are metadata. JSON omits `value` and reports `has_value`. | Use `has_value` for availability checks. For a value a script actually needs, call `hack env get KEY` with the same `--env` and `--service`; that command prints plaintext. Bulk `--show-values` requires terminal stdin/stdout and interaction enabled; `--show-secrets` remains an alias. | | **Migration cleanup preserves live keys (HACK-2172).** A legacy store's `keyPath` can no longer make the current project/shared key a cleanup target. Current config and YAML inputs are protected too, including filesystem aliases. | Keep key and env backups before migration. On next.16 or an earlier prerelease, do not run `doctor --migrate-env-config` without a private readable copy of `.hack.secret.key`. The fix does not recover a key already removed. | | **Doctor fails when an env layer cannot be used by the runtime.** Unreadable, invalid or undecryptable layers no longer get an apparent all-clear. | Run `hack doctor` after upgrading. Fix the reported layer or recover the original key before starting; keep the encrypted file rather than generating a replacement key over it. | | **Doctor reports secrets hygiene (#764).** The report covers loose modes, staging leftovers and stale terminal payloads, naming files rather than values. | Review `hack doctor`, then use `hack doctor --fix` to tighten eligible files, add missing project ignore entries and remove stale Hack artifacts. Removal excludes live inputs and retired stores; it rechecks configuration before each removal. | @@ -39,6 +62,70 @@ its original behavior. | **Native route readiness can be inferred.** A complete standard Caddy route with no authored healthcheck gets a reviewed HTTP probe and 240 seconds of initial grace. A complete HTTP 200–499 response establishes endpoint readiness, not application correctness. | Review the route port and startup logs. Explicit healthchecks are not replaced, and inferred readiness does not satisfy `depends_on: condition: service_healthy`. The grace does not extend the whole graph's deadline. | | **Native start waits for bridge sockets after a stopped pool resumes.** An immediate start no longer fails merely because provider readiness preceded the bridge listener. | Use normal native `up`; startup still requires a successful bridge connection within its deadline. Do not replace readiness checks with a fixed sleep. | +### Upgrade assistant: check, review, apply and recover + +The assistant now covers checks and selected file repairs. It does not install +a release, hand over the daemon, migrate env formats or qualify application data. +Keep the [backup-first upgrade procedure](../versions/v5/upgrade.md), including +the original project key and application-aware data backups. + +| Change | What to do | +| --- | --- | +| **`hack upgrade check` is read-only.** It checks the machine and registered checkouts, separates dead entries from unreadable live ones, and groups the plan by fix. Exit 1 means blockers or incomplete checks; optional native preflight is not a required upgrade gate. | Run the selected v5 CLI. Use `--verbose` (or `--all`) for every checkout and `--json` for full detail. Repair or investigate blockers and unchecked findings; an unknown result is not a pass. | +| **`hack upgrade review` batches decisions without applying them.** It runs a fresh read-only check and explains env/key/tracked-file findings across selected checkouts. | Use `--only env-secrets,env-format,env-key,tracked-files` and `--project NAME` to narrow the review. It executes neither fixes nor the commands it prints. | +| **`hack upgrade apply` snapshots and journals selected repairs.** It refreshes ignore rules, removes verified superseded standalone agent files, and removes group/other access from eligible existing keys while preserving owner bits. Blocked or unchecked checkouts are skipped. | Read `hack upgrade apply --dry-run` first; add `--verbose` for paths. Apply does not create/rotate keys, change ownership, untrack files, accept tracked env edits, migrate env or run broad Doctor fixes. Keep its printed recovery commands. | +| **Apply resumes only an explicit run.** `--resume` reuses the saved selection and snapshot; unexpected edits or damaged original blobs refuse. Targets on another filesystem are skipped before snapshot creation. | Use `hack upgrade apply --resume `, optionally with `--dry-run`. Do not combine resume with new selection flags. For another volume, select one project with an owned private `--snapshot-root` outside Git on that volume. | +| **`hack upgrade snapshot` writes a private file backup.** Bytes, including selected keys, live in private blobs; the manifest contains metadata. Coverage gaps are reported. | Treat the snapshot as sensitive and retain it until recovery is checked. It does not back up containers, volumes, login services or installed versions. Snapshots do not expire automatically. | +| **`hack upgrade rollback` restores files, not the running system.** With `--rollback-manifest `, it restores exact bytes/modes and keeps displaced copies. Without a manifest it only lists snapshots. | Review conflicts before `--overwrite`; it explicitly permits replacing later edits, whose copies are kept. Stop the candidate and restore the chosen executable, daemon and application data separately. | +| **Upgrade JSON findings and steps add `kind: safe`, `admin` or `manual`, separately from severity.** Grouped apply is safe only when all its targets are eligible; a broad Doctor repair stays manual. | Treat missing/unknown kinds as manual and require a command before offering Run. `admin` calls for terminal review, not necessarily sudo. The label grants no authority and bypasses no checks. | + +See [assistant coverage and recovery](../versions/v5/guides/upgrade-from-v4.md#check-first) +for selection, snapshot coverage and cross-volume limits. + +### Read-only status and administrator plans + +These four new JSON contracts are **shape may change before 5.0.0**: +global observe status, project observe listing, version identity, and global +install/trust plans. At this candidate they return bare objects; HACK-2238 will +move them to the `{ ok, data }` envelope before they are declared stable. +Pin the candidate used by a script and review that migration before upgrading. + +| Change | What to do | +| --- | --- | +| **`hack global status --json --observe` never starts Docker, services, hackd or a VM.** It runs bounded read-only probes; failed or timed-out evidence is unknown. Ordinary global status can start Docker. | Use observe mode for polling. `--observe` requires `--json`. Exit 0 means a report was printed: inspect the report's true/false/unknown fields. See [the contract](../reference/global-status-observe.md). | +| **`hack projects --json --observe` preserves the registry and avoids daemon/engine contact.** Live state is unknown by default. Ordinary listing keeps its discovery writes. | Use this for read-only registry polling. `--runtime` explicitly opts in to Docker reads, whose socket contact can start an on-demand engine. Native rows still need native `ps`; unknown is not stopped. `--meta` is refused. See [project listing](../cli.md#core-commands). | +| **`hack global install --plan --json` and `hack global trust --plan --json` preview administrator operations without running them.** Steps show privilege, guarded argv and stdin size/digest; bootstrap-dependent phases remain incomplete. | Review the plan, then run the real command in a terminal when intended. No permission is granted by a plan. Exit 0 means complete, 1 refused, 3 incomplete; omitting `--json` with `--plan` exits 2. See [admin plans](../reference/global-admin-plan.md). | +| **`hack version --json` identifies the running CLI.** It reports `version`, `channel`, `install_kind` and `binary_path`, without PATH lookup, network or runtime startup. Text output is unchanged. | Use it to record the build actually running. A source invocation reports Bun's path and `install_kind: source`, not another Hack found on PATH. See [version identity](../reference/version.md). | + +### Lifecycle history, commands and recovery + +| Change | What to do | +| --- | --- | +| **Lifecycle commands now write activity history.** Compose and native `up`, `down` and `restart` append to `~/.hack/activity.jsonl` (or the selected Hack home), including refused commands that reach the handler. Records are written when the command returns. | Read newest-first history with `hack activity --json`, optionally `--project NAME --limit 100`. Files are private and rotate to one kept generation. Records contain names/outcomes, not env values, argv or paths. This is best-effort history, not a complete audit: a killed command or failed append can leave no record. | +| **Ctrl-C waits for owned lifecycle commands to retire before wrappers and state are removed.** Each phase allows five seconds of TERM grace, then at most one SIGKILL. Transient census failures retry; a second Ctrl-C can request the forced command-group stop. Unknown retirement keeps ownership evidence. | Allow the first stop to finish. Inspect a refusal and use `hack down` or the documented `hack doctor --fix` recovery rather than deleting state. See [lifecycle](../lifecycle.md). | +| **Native terminal exec is interactive.** With foreground terminal stdin/stdout, `hack exec SERVICE -- /bin/sh` streams a sized, resizable terminal and preserves the exit status. Redirects, background shell jobs and `HACK_NO_INTERACTIVE=1` keep finite exec. | Use the same native home/version as the project. Old managed-env launchers need a restart with the matching bundle or finite exec. For an uncertain outcome, inspect `hack exec-sessions`, then use `--reconcile` or project `down` as directed; never replay an unknown command blindly. See [exec and recovery](native-candidate.md#normal-native-exec). | +| **Native `ps` no longer holds a mutation lease, and plain `down` can recover proved, settled failed starts, including before Ready was saved.** Changed journal evidence can still report `runtime_busy`. | Poll normally; retry busy reads. Try ordinary `down` first and follow retained-recovery instructions when proof is incomplete. Do not remove receipts or assume every failed start was cleaned up. | +| **Native followed logs can reattach after a project restart.** Re-admission is bounded to 30 seconds and 1,000 initial replacement-container lines. Session failures emit a named JSON `end`, a stderr diagnostic and exit 1, without an extra global error envelope. | Parse the session's named end; do not treat transport loss as success. Reattach failure and stopped-idle remain explicit failures. See [followed logs](../reference/native-authored-commands.md#followed-service-logs). | +| **Detached native startup names failed services.** It points to foreground output rather than returning only `engine_rejected`. | Rerun without `--detach` to inspect the failed services' last lines; keep sensitive output out of reports. | +| **Compose startup recognizes short successful one-shot services and briefly retries attaching network members.** Exit-zero initializers no longer cause false `E_STARTUP_INCOMPLETE`; persistent placeholders and foreign members still refuse. | Use ordinary `up --detach` or `restart`; inspect real nonzero jobs and ownership refusals. This does not relax ownership checks or every saved-command read. | +| **Native understands standard Hack networks and metadata, and preflight shares start admission.** Exact `hack-dev`/`hack-logging` networks become project-owned bridges; generated labels are inert. Private env with automatic restart and UDP publications can now block preflight instead of failing only at start. | Review preflight findings. These bridges provide neither Docker-global network membership nor cross-project DNS. Use Compose for unsupported topology; do not strip ownership checks to start. | +| **`hack open` warns about a definite DNS miss, or a missing managed resolver on macOS after an unknown lookup.** JSON keeps `url` and adds `dns`/`hint`; timeout alone is not a confirmed miss. `init --auto` warns when it wrote a placeholder instead of discovering a service. | Follow the same CLI's `hack global install` or `hack config set dev_host NAME` hint. Edit a generated placeholder's image/command before `up`. See [first project](../versions/v5/getting-started.md). | + +### Background output, secret custody and host setup + +| Change | What to do | +| --- | --- | +| **`hack exec --detach` and `hack run --detach` add retained background commands.** CLI and MCP share cursor reads, inspection and cancellation. Output capture has byte and retention limits; an unknown exit is not success. | Keep the returned ID/cursor. Use `hack commands read ID`, `hack commands show ID` and `hack commands cancel ID`; prefer this over a long foreground MCP call. Read [capture and ownership limits](background-commands.md). | +| **Background recovery drops unscanned orphan output when redaction values are lost.** Takeover/sweep truncates unannounced tails, and final sync failures are recorded. Scanning many redaction values now uses one pass. | Handle truncation/unknown outcomes in readers. Partial redaction still misses short, transformed or uninjected values; native output is unredacted. Choose `--capture metadata` when output may contain secrets. | +| **Hack decryption keys no longer pass to ordinary children; env parse errors no longer echo parser messages.** Local-layer writes refuse links, tracked destinations or ineffective ignore rules. Legacy dotenv reads refuse symlinks. | Pass only application env to hooks/host commands. Keep local layers untracked and ignored, correct file boundaries, and fix syntax at the named coordinates; do not expect a raw source excerpt. | +| **Secret stores and writes refuse unsafe or unreadable inputs instead of treating them as empty or replacing a needed key.** Key-file reads reject links, loose access and tracking; writes cannot silently mix project encryption keys. | Recover the existing key and repair the reported file. Explicit provisioning cannot overwrite a different key. Do not create a new key over ciphertext or remove an unreadable store to bypass the refusal. | +| **Lifecycle logs/FIFOs and staging are private; terminal payloads expire.** Local writes tighten loose modes; automatic stale-payload cleanup, like Doctor, preserves live and retired inputs and skips cleanup when configuration cannot be resolved. | Review Doctor hygiene findings. Logs, MCP results and retained argv/output can still contain plaintext or injected instructions; review before sending them to an agent or sharing them. | +| **MCP project selectors explain registration; foreground timeouts are explicit.** Timed-out results add `timedOut: true` and cannot report success. Codex MCP installation adds a 660-second client limit when no value is set; existing choices remain. | Register an explicit project with `hack status`, `hack projects` or `hack init`, or deliberately use the server's current directory. For long work, use background commands or raise `timeoutMs` within its limit. Run `hack mcp install --codex` to adopt the installer setting; it does not change an existing timeout. | +| **Native setup JSON reports files actually acquired.** Entries include byte accounting; supplied archives are `offline`, and complete installed-home reuse has `files: []`. | Do not require a file entry on reuse or count offline input as a download. See [setup](../native/try-it.md#2-prepare-the-runtime). | +| **Updater publication verifies inventory/version and keeps recovery files.** Downloads are bounded/retried; the compiler publishes before the CLI. A caught publication failure restores earlier files. Candidate uninstall moves the channel aside reversibly and retains user homes. | Keep printed recovery manifests until the new install is checked. A killed multi-directory swap may need manual restoration. These updater fixes require the newer updater; old v4 binaries retain old behavior. See [installation recovery](upgrading-from-v4.md#download-and-installation-recovery). | +| **Linux daemon stop proves the live process's Hack home; unavailable service-manager queries refuse instead of looking absent.** Candidate Compose Doctor treats a missing daemon as healthy/optional. | Follow printed manual service steps on refusal. Leave another home's daemon alone; do not use repeated stable daemon starts to repair a candidate trial. | +| **Doctor checks actual local-CA trust, separately from the exported CA file.** Failed reads are unknown. Linux NSS writes now refuse changed database identities, and privileged install cancellation no longer signals a saved reader PID. | Read `local ca trust` in `hack doctor --json` (`caTrust`), then review `hack global trust` if needed. Stop competing certificate-database writers before retrying a changed-file refusal. Host/browser verification remains separate. | + Detached native starts do not show per-key "unresolved input" notices because the owner's stdio is ignored. Use a foreground start or native preflight to inspect those notices; only forwarded shell names and the fixed ignored-root @@ -104,6 +191,9 @@ Merged [#779](https://github.com/hack-dance/hack/pull/779), intended for next.17 makes a missing or wrong store key a Doctor error only in projects whose runtime reads that store. Other projects receive a warning. The finding names registered projects that read it; without the key, entries cannot be counted or read. +Reader summaries now group linked worktrees under their project, with a count +and up to three examples. Unchecked registry entries point to +`hack projects prune --dry-run`; preview before pruning. Choose one: restore the original key, or, if it is gone for good, run `hack secrets retire-store --path ` for a project that selects the store. @@ -276,11 +366,3 @@ and writes both service stdout and stderr to the CLI's stdout, so pipes receive Remote, gateway, node and dispatch commands and the macOS app remain in the repository but are unsupported. See [unsupported retained surfaces](../extensions.md). - -## Breaking change: zellij workspaces removed - -v5 supports tmux for interactive workspaces. `sessions.mux=zellij` and `HACK_SESSIONS_MUX=zellij` now fail with migration guidance. Install tmux, then remove the setting or set it to `tmux`; `auto` detects tmux only. Existing zellij sessions are not stopped or migrated by Hack. - -**Before upgrading a project that used zellij for lifecycle processes:** with zellij installed, use the v4 CLI to run `hack down` for that project and confirm its lifecycle processes have stopped. Then switch to v5 and change the mux setting. Saved zellij lifecycle state blocks v5 start, restart and down because v5 cannot verify or stop that session. If already upgraded, use the retained v4 CLI to stop the affected project first; do not delete or edit managed state files. Removing a workspace setting alone does not clear saved lifecycle state. A stale-state migration path remains part of the lifecycle supervisor work. - -A leftover zellij setting also makes `hack global install` fail with the same migration guidance. Fix the setting before retrying. diff --git a/docs/native/limits.md b/docs/native/limits.md index 3b213e284..3cc462c61 100644 --- a/docs/native/limits.md +++ b/docs/native/limits.md @@ -4,6 +4,9 @@ The native backend supports part of what Compose supports. When a project needs something outside that part, Hack refuses and tells you. It does not guess, and it does not fall back to Docker without telling you. +The changes labelled next.17 below describe candidate source `5002cf87bb`. +An installed next.16 bundle keeps its older behavior. + ## Platform | Platform | Native backend | @@ -22,7 +25,7 @@ does not fall back to Docker without telling you. | Stop the project | `hack down`, and `hack down --recover` after a crash | | See what is running | `hack ps` | | Read recent logs | `hack logs --no-follow`, a bounded snapshot | -| Run a command in a running service | `hack exec`, without an interactive terminal | +| Run a command in a running service | Next.17: foreground terminal `hack exec SERVICE -- /bin/sh` is interactive; redirected input/output and `HACK_NO_INTERACTIVE=1` use finite exec | | Run a one-off command | `hack run`, for services without source, data or private env mounts | | Preview without starting | `hack config validate`, `hack config plan`, `hack config import --dry-run`, `hack config adopt --dry-run` | @@ -49,7 +52,10 @@ The exact rules for each command are in - Proving a complete tail without transport EOF. A stopped service whose stream stays open for five idle seconds ends with `native_log_stopped_idle` and exit 1, not a clean EOF. The final tail may be incomplete. -- Interactive `exec` sessions. +- Interactive exec on an older next.16 bundle. Next.17 supports sized terminals, + resize and control bytes; old managed-env launchers require a matching restart + or finite exec. Inspect uncertain outcomes with `hack exec-sessions`; see + [exec recovery](../guides/native-candidate.md#normal-native-exec). - Changing the env overlay, profiles or target of a project that is already running. Stop it and start it again. - Starting or restarting single services. Native starts and restarts the whole @@ -64,9 +70,9 @@ refuses with `E_NATIVE_PROJECT_UNSUPPORTED`, names the feature, and starts nothi | Compose feature | Why it stays on Compose | | --- | --- | -| External networks | Native only uses networks it creates and owns | +| Foreign external networks | Exact `hack-dev` and `hack-logging` identities map to project-owned bridges in next.17; they do not join Docker's shared networks or provide cross-project DNS | | External volumes | Native only uses volumes it creates and owns | -| Labels Hack or Compose reserve | These labels prove which tool owns a resource | +| Unsupported routing labels | Generated Hack/Compose metadata is inert in next.17; authored labels never grant resource ownership | | Builds beyond a basic `context`, `dockerfile` and `target` | Build arguments, secrets, SSH and cache options are not supported | | Platforms other than Linux arm64 | The virtual machine runs Linux arm64. `linux/amd64` works only for services you opt in to emulation. | @@ -82,9 +88,12 @@ Details and the exact checks: mount a named volume at that path, for example `redis-data:/data`. Without one the project refuses with `graph_image_volume_uncovered`. A bind mount or a read-only mount there does not count. -- **Stopping with Ctrl-C.** In this prerelease, Ctrl-C may not stop a foreground - project cleanly when it publishes ports. Use `hack down` from another terminal, - and `hack down --recover` if it reports that the owner is gone. +- **Stopping with Ctrl-C.** The native publisher-shutdown fix (HACK-2087, #719) + already shipped in next.16. Next.17 adds lifecycle-command retirement fixes + (HACK-2184): transient reads retry, cleanup waits for proved command retirement, + and a second Ctrl-C can request the forced command-group stop. Unknown cleanup + still retains evidence. Use `hack down` from another terminal, then + `hack down --recover` if it reports the owner is gone; do not delete state. - **Images.** Images need a Linux arm64 variant. Local registries need an explicit opt-in. Registries signed by a private certificate authority are not supported. - **Data.** Data does not move between backends, or between prerelease versions. diff --git a/docs/native/try-it.md b/docs/native/try-it.md index cf9e14f07..ac1c49ea3 100644 --- a/docs/native/try-it.md +++ b/docs/native/try-it.md @@ -143,10 +143,12 @@ Native `up` runs in the foreground and holds the project until you stop it. Add "$HOME/.hack-next/bin/hack-next" down --path /absolute/project ``` -Stop the project with `hack down` from another terminal, as above. In this -prerelease, Ctrl-C may not stop a foreground project cleanly when it publishes -ports. If you already pressed Ctrl-C, run `hack down`, and `hack down --recover` if -it reports that the owner is gone. A fix is in progress. +Stop the project with `hack down` from another terminal, as above. The native +publisher-shutdown fix (HACK-2087, #719) already shipped in next.16. Next.17 adds +lifecycle-command retirement fixes (HACK-2184): transient reads retry and a second +Ctrl-C can request the forced command-group stop. If cleanup is uncertain, run +`hack down`, then `hack down --recover` if it reports that the owner is gone. +Keep the receipts and follow the printed recovery procedure. Then check the application itself: sign in, load a page that reads data, restart, and confirm the data is still there. A green status alone does not prove the diff --git a/docs/versions/v5/guides/upgrade-from-v4.md b/docs/versions/v5/guides/upgrade-from-v4.md index eaa8c60c0..7399473c9 100644 --- a/docs/versions/v5/guides/upgrade-from-v4.md +++ b/docs/versions/v5/guides/upgrade-from-v4.md @@ -12,6 +12,10 @@ project, the v4.2.1 path, env migration, data recovery or rollback. Those remain steps are **to be confirmed in the dogfood run**. Native setup and log following remain **under verification**. +The next.17 additions below were checked against candidate source `5002cf87bb`. +They do not change the next.16 trial record. The assistant now handles checks and +selected file repairs; env migration and the runtime trial remain separate. + ```mermaid --- title: Choose an upgrade path @@ -64,6 +68,24 @@ Sources: [candidate channel contract](https://github.com/hack-dance/hack/blob/26 ## 2. Before you start +### Breaking change: zellij workspaces removed + +Next.17 requires tmux for interactive workspaces. Project/global +`sessions.mux=zellij` and `HACK_SESSIONS_MUX=zellij` fail with migration guidance. +Install tmux, then remove the setting and override or set the mode to `tmux`; +`auto` detects tmux only. Existing zellij sessions are not stopped or migrated. + +After backing up, **before switching a project that used zellij lifecycle +processes**, keep zellij installed and use the retained v4 CLI to run `hack down` +for that project. Confirm its lifecycle processes stopped. If already upgraded, +use the retained v4 CLI for that stop first. Then take a fresh private backup +using the procedure below, keeping the earlier copy. Use the stopped-state copy +for rollback so it does not restore live zellij state. Saved zellij lifecycle state blocks +v5 start, restart and down: v5 cannot verify or stop it. Changing the setting +alone does not clear saved state. Do not delete or edit managed state files. +A leftover zellij setting also makes `hack global install` fail; fix it before +retrying. A stale-state migration path remains separate lifecycle work. + ### Check first v5 builds that include the upgrade assistant can check the machine before you @@ -487,7 +509,7 @@ not prove the key survived. Implicit migration cleanup removes only migrated dotenv files, not the store's `keyPath`, but it still writes project state: keep the backup before env-consuming commands that can migrate automatically too. The section 2 template already saves the key privately as -`$BACKUP/project-.hack.secret.key`, outside the working tree. A published fix +`$BACKUP/project-.hack.secret.key`, outside the working tree. A fix for explicit Doctor cleanup is merged in [#769](https://github.com/hack-dance/hack/pull/769), intended for next.17. In a build containing that fix, project/shared env keys and current config/YAML @@ -979,11 +1001,3 @@ Keep the printed resume and rollback commands for a custom `--snapshot-root`: ordinary snapshot listings scan only the default root. Resume preserves completed outcomes across interruption and refuses a damaged original blob even when its agent file has already been removed. - -## Breaking change: zellij workspaces removed - -v5 supports tmux for interactive workspaces. `sessions.mux=zellij` and `HACK_SESSIONS_MUX=zellij` now fail with migration guidance. Install tmux, then remove the setting or set it to `tmux`; `auto` detects tmux only. Existing zellij sessions are not stopped or migrated by Hack. - -**Before upgrading a project that used zellij for lifecycle processes:** with zellij installed, use the v4 CLI to run `hack down` for that project and confirm its lifecycle processes have stopped. Then switch to v5 and change the mux setting. Saved zellij lifecycle state blocks v5 start, restart and down because v5 cannot verify or stop that session. If already upgraded, use the retained v4 CLI to stop the affected project first; do not delete or edit managed state files. Removing a workspace setting alone does not clear saved lifecycle state. A stale-state migration path remains part of the lifecycle supervisor work. - -A leftover zellij setting also makes `hack global install` fail with the same migration guidance. Fix the setting before retrying. diff --git a/docs/versions/v5/native/overview.md b/docs/versions/v5/native/overview.md index 0bb35e48a..7293f5b94 100644 --- a/docs/versions/v5/native/overview.md +++ b/docs/versions/v5/native/overview.md @@ -8,6 +8,10 @@ Native setup and live log following are available in next.16 **under verificatio Real-VM acceptance remains pending; start with disposable projects and synthetic data. See [Prepare the runtime](setup.md) and [Follow service logs](log-follow.md). +Next.17 source adds interactive exec, guarded Compose env-file reads and +retirement fixes. These do not change an installed next.16 bundle; see +[what changed and what to do](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/guides/v5-release-notes.md#next17-what-changed-and-what-to-do). + ## What it is Hack needs something to run your services in. Today that is Docker Compose, which @@ -99,7 +103,10 @@ What you give up today: - Following logs live as a verified native capability. `hack logs --follow` is available for testing; real-VM acceptance for authored and adopted projects is still pending. -- Interactive shells in a container. +- Interactive shells on next.16. Next.17 supports foreground terminal + `hack exec SERVICE -- /bin/sh`; redirects and `HACK_NO_INTERACTIVE=1` keep + finite exec. Use the matching runtime and follow its retained-session + recovery instructions after an uncertain outcome. - UDP ports. - Automatic restart for services that publish a port. diff --git a/docs/versions/v5/native/start.md b/docs/versions/v5/native/start.md index f6683426a..73d71838d 100644 --- a/docs/versions/v5/native/start.md +++ b/docs/versions/v5/native/start.md @@ -88,6 +88,14 @@ If writable source sharing asks for consent, review the exact source roots and [sharing limits](full-reference.md#explicit-writable-development-source) before opting in. Check the app and saved data yourself; a running VM is not acceptance. +In a build containing next.17's interactive exec, use +`"$CANDIDATE" exec api -- /bin/sh` from a foreground terminal for a live shell. +Terminal stdin and stdout are required; redirects or `HACK_NO_INTERACTIVE=1` +select finite exec. Use the matching runtime, and restart old managed-env +launchers if requested. After an uncertain outcome, inspect +`"$CANDIDATE" exec-sessions` and follow the +[next.17 source recovery instructions](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/guides/native-candidate.md#normal-native-exec). + Stop with the **same version and native home**: ```sh diff --git a/docs/versions/v5/upgrade.md b/docs/versions/v5/upgrade.md index c9b533f9c..3727af301 100644 --- a/docs/versions/v5/upgrade.md +++ b/docs/versions/v5/upgrade.md @@ -4,8 +4,9 @@ Start here: [1. Install](install.md) · [2. First project](getting-started.md) **3. Upgrade** · [4. Try native](native/start.md). This is today's manual path. **To be replaced by the upgrade assistant** -(HACK-2189 and HACK-2191, in progress). Until it lands, keep stable v4 installed -and try v5 on one Compose project at a time. Native is a separate trial. +(HACK-2189 and HACK-2191). Next.17 source already checks and repairs selected +files; env migration and the runtime trial remain manual. Keep stable v4 +installed and try one Compose project at a time. Native is a separate trial. The published v5 candidate bundle requires an Apple Silicon Mac. ```mermaid @@ -40,7 +41,15 @@ offered as Run. Host changes and decisions still need review. and confirm you can read the original key. If stable routing needs starting, run stable `command hack global up` before the backup procedure stops its daemon and copies the files. -2. **Confirm stable's daemon stays stopped.** In a terminal where +2. **Stop saved zellij lifecycle sessions before switching to v5.** Keep zellij + installed and use retained v4 `command hack down` for each affected project. + Confirm the lifecycle processes stopped, then take a **fresh backup** with the + step 1 procedure. Keep the earlier copy too; use the stopped-state backup for + rollback so it does not restore live zellij state. Next.17 requires tmux; remove + `sessions.mux=zellij` and `HACK_SESSIONS_MUX=zellij`, or select `tmux`. + Changing the setting alone does not clear saved state. See the + [stop procedure](guides/upgrade-from-v4.md#breaking-change-zellij-workspaces-removed). +3. **Confirm stable's daemon stays stopped.** In a terminal where `hack` is the stable executable, run: ```sh @@ -52,7 +61,7 @@ offered as Run. Host changes and decisions still need review. The last command must print nothing before you continue. On macOS uninstall removes the launchd service so it cannot restart the daemon during the trial. Run no stable commands while the candidate uses the shared home. -3. **Install v5 beside stable**, following [Install](install.md). Use a fresh +4. **Install v5 beside stable**, following [Install](install.md). Use a fresh terminal for the trial, select Compose, and check the chosen version: ```sh @@ -63,7 +72,7 @@ offered as Run. Host changes and decisions still need review. hack doctor ``` -4. **Review env migration before accepting it.** `up` can offer migration; +5. **Review env migration before accepting it.** `up` can offer migration; sessions and some env commands can migrate without a prompt. Keep backups before any of them. If explicit migration is needed, use `hack doctor --migrate-env-config` only after reading the @@ -71,7 +80,7 @@ offered as Run. Host changes and decisions still need review. On next.16 or earlier, cleanup can remove a project key a legacy store names: never run that repair without the private readable key copy. The merged fix intended for next.17 cannot recover an already deleted key. -5. **Run the project and check it**, using `hack up --detach`, `hack open`, +6. **Run the project and check it**, using `hack up --detach`, `hack open`, `hack logs --no-follow --tail 50` and `hack down`. Check sign-in, saved data, hooks and a restart. Keep the backup until rollback and data recovery have been checked. See [known problems](guides/upgrade-from-v4.md#known-problems-and-the-dogfood-record).