From 4117c15e8eab680c4690a4f5ddf92d0d3a6c34c4 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Thu, 26 Mar 2026 18:17:56 -0700 Subject: [PATCH 01/22] docs: add auto-activation concept page and cross-links Add documentation for the auto-activation feature (flox/flox#4117): - New concept page explaining auto-activation lifecycle, trust model, nested environments, deactivation, and hook state variables - Add note admonition and section in activation concept page - Add note admonition in default environment tutorial - Add auto-activation to mkdocs nav Man pages for `flox allow`, `flox revoke`, and `flox deactivate` will be generated from CLI source once the feature ships. Edits to the `flox activate` and `flox` man pages must happen in flox/flox. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/concepts/activation.md | 21 +++ docs/concepts/auto-activation.md | 231 ++++++++++++++++++++++++++ docs/tutorials/default-environment.md | 8 + mkdocs.yml | 1 + 4 files changed, 261 insertions(+) create mode 100644 docs/concepts/auto-activation.md diff --git a/docs/concepts/activation.md b/docs/concepts/activation.md index 03752970..bcf752c2 100644 --- a/docs/concepts/activation.md +++ b/docs/concepts/activation.md @@ -173,6 +173,12 @@ Unlike `-c`, when exec'ing a command directly with `--`: When none of those features are needed, using `--` is faster than `-c` since there's no intermediate shell. +!!! note + + Looking for **auto-activation**? Flox can automatically activate + environments when you `cd` into a directory. + See [Auto-activation](./auto-activation.md) for details. + ## Activation flow In order to understand where `hook` and `profile` fit into the picture, @@ -331,6 +337,21 @@ attach to this new version of the environment. See the [`options.activate.mode`](../man/manifest.toml.md#options) option in the manifest. +## Auto-activation + +In addition to the manual activation methods described above, +Flox supports **auto-activation**: environments activate automatically +when you `cd` into a directory containing a `.flox/` subdirectory, +and deactivate when you leave. + +This is powered by a shell hook that runs on every prompt, +discovering `.flox` directories in your directory's ancestor chain and +managing their activation lifecycle — including hooks, services, nested +environments, and trust-based security. + +To learn more, see the full +[Auto-activation](./auto-activation.md) concept page. + ## Conclusion As you can see, there's a lot going on under the hood, diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md new file mode 100644 index 00000000..ab835f69 --- /dev/null +++ b/docs/concepts/auto-activation.md @@ -0,0 +1,231 @@ +--- +title: Auto-activation +description: How environments activate automatically when you enter a directory +--- + +# Auto-activation + +Flox environments are powerful, +but remembering to run `flox activate` every time you enter a project +directory can be tedious. +**Auto-activation** solves this by automatically activating environments +when you `cd` into a directory containing a `.flox/` directory, +and deactivating them when you leave. + +This means your tools, environment variables, hooks, and services are +always ready — no manual activation required. + +## Enabling auto-activation + +To enable auto-activation, add a single line to your shell's RC file: + +=== "Bash" + + Add the following line to the end of your `~/.bashrc`: + + ```{ .bash .copy } + eval "$(flox activate)" + ``` + +=== "Zsh" + + Add the following line to the end of your `~/.zshrc`: + + ```{ .zsh .copy } + eval "$(flox activate)" + ``` + +=== "Fish" + + Add the following line to the end of your `~/.config/fish/config.fish`: + + ```{ .fish .copy } + flox activate | source + ``` + +=== "Tcsh" + + Add the following line to the end of your `~/.tcshrc`: + + ```{ .tcsh .copy } + eval "`flox activate`" + ``` + +When `flox activate` is invoked in-place without targeting a specific +environment (no `-d` or `-r` flag), +it activates the current directory's environment _and_ installs a shell +hook that enables auto-activation for the rest of the session. + +!!! note + + If you previously used `eval "$(flox activate -r owner/default)"` to + set up your default environment, the new + `eval "$(flox activate)"` line replaces it. + It activates your current directory's environment (if one exists) + and enables auto-activation everywhere. + See the + [default environment tutorial](../tutorials/default-environment.md) + for more details. + +## How it works + +Once the shell hook is installed, it runs on every prompt +(or directory change, depending on your shell). +Here is what happens on each prompt: + +1. **Discovery** — The hook walks the directory tree from your current + working directory up to the filesystem root, + collecting all directories that contain a `.flox/` subdirectory. +2. **Trust check** — Each discovered environment is checked against the + trust store. Only trusted environments proceed. +3. **Activation** — Trusted environments are activated outermost-first. + Environment variables are set, hooks run, and services start. +4. **Deactivation** — When you leave a directory, its environment is + deactivated and its changes to the shell are reverted. +5. **Reattachment** — If you return to a previously activated directory, + the environment reattaches from cache rather than re-running hooks, + making it nearly instant. + +Most prompts trigger the **fast path**: the hook detects that nothing has +changed (same directory, same environments, same manifest timestamps) and +exits immediately with no output or delay. + +## Trust and security + +Environments can run arbitrary code via their `[hook]` and `[profile]` +scripts. +Auto-activation means this code runs automatically when you enter a +directory, +so Flox requires you to explicitly trust an environment before it will be +auto-activated. + +!!! warning + + Before trusting an environment, review its manifest to understand what + hooks and scripts it will run. + This is especially important for environments obtained from untrusted + sources (e.g. cloned repositories). + +### Trusting and denying environments + +Use [`flox allow`](../man/flox-allow.md) to trust an environment: + +```{ .bash .copy } +flox allow +``` + +Use [`flox revoke`](../man/flox-revoke.md) to deny auto-activation: + +```{ .bash .copy } +flox revoke +``` + +### How trust works + +- **Allow is content-sensitive.** The trust hash includes both the + environment's absolute path and the content of its manifest. + If the manifest changes (e.g. after `git pull`), trust is automatically + revoked and you must run `flox allow` again. + +- **Deny is path-only.** The deny hash includes only the environment's + path, so a denial persists across manifest changes. + +- **Deny always wins.** If both allow and deny records exist for an + environment, it will not be auto-activated. + +### Automatic trust + +You don't need to manually run `flox allow` for environments you create +or modify through normal Flox commands: + +- `flox init` automatically trusts the newly created environment. +- `flox install`, `flox uninstall`, and `flox edit` automatically + re-trust the environment after modifying the manifest. + +Only **out-of-band changes** — such as `git pull`, manual edits, or +another user modifying the manifest — require you to run `flox allow` +again. + +## Nested environments + +When multiple `.flox` directories exist in your directory's ancestor +chain, +all trusted environments are activated simultaneously. +Environments are activated outermost-first, +so an environment in `/home/user/projects` activates before one in +`/home/user/projects/myapp`. + +The shell prompt reflects all active environments: + +``` +flox [projects myapp] $ +``` + +Use `flox deactivate` to peel off layers one at a time, +starting with the innermost (closest to CWD). + +## Deactivation + +[`flox deactivate`](../man/flox-deactivate.md) reverses the effects of +the innermost auto-activated environment: + +- Reverts environment variables set by that environment. +- Restores the shell prompt. +- **Suppresses** that environment so the hook does not re-activate it + while you remain in the directory. + +If you leave the directory and return later, +the suppression is lifted and the environment auto-activates again. + +Calling `flox deactivate` multiple times peels off additional layers, +one at a time. + +## Interaction with manual activation + +Environments activated manually — via `flox activate -d ` or +`flox activate -r /` — are excluded from auto-activation +management. +The shell hook does not discover, activate, deactivate, or suppress +manually activated environments. + +## Relationship to the default environment + +Previously, setting up a default environment required a line like: + +```{ .bash } +eval "$(flox activate -r /default)" +``` + +With auto-activation, the simplified setup is: + +```{ .bash } +eval "$(flox activate)" +``` + +This single line both activates the current directory's environment (if +one exists) and installs the auto-activation hook. +If you have a `.flox` environment in your home directory, +it will be auto-activated in every shell — serving the same purpose as +the old default environment pattern. + +See the +[default environment tutorial](../tutorials/default-environment.md) +for more details on setting up a default environment. + +## Advanced: hook state variables + +Auto-activation tracks its state using internal environment variables. +These are implementation details and subject to change, +but are documented here for debugging purposes. + +??? note "Internal state variables" + + | Variable | Description | + |----------|-------------| + | `_FLOX_HOOK_DIFF` | Compressed record of all environment variable changes (additions, modifications, deletions) applied by auto-activated environments | + | `_FLOX_HOOK_DIRS` | Colon-separated list of `.flox` directories currently active via auto-activation | + | `_FLOX_HOOK_WATCHES` | JSON array of watched manifest file paths and their modification times, used to detect changes | + | `_FLOX_HOOK_SUPPRESSED` | Colon-separated list of directories suppressed by `flox deactivate` | + | `_FLOX_HOOK_NOTIFIED` | Colon-separated list of directories for which the user has already been warned about trust | + | `_FLOX_HOOK_CWD` | Last-seen working directory, used for fast-path detection | + | `_FLOX_HOOK_ACTIVATIONS` | Compressed record of per-environment activation metadata (store paths, cached hook output) | diff --git a/docs/tutorials/default-environment.md b/docs/tutorials/default-environment.md index 19e5a614..b3583dec 100644 --- a/docs/tutorials/default-environment.md +++ b/docs/tutorials/default-environment.md @@ -27,6 +27,14 @@ so let's take a look at how to set it up. ## Initial setup +!!! note + + With **auto-activation**, you can replace the per-environment RC + file setup below with a single `eval "$(flox activate)"` line. + Auto-activation discovers and activates `.flox` environments + automatically as you `cd` into directories. + See [Auto-activation](../concepts/auto-activation.md) for details. + At the most basic level, the `default` environment is simply an environment called `default`. `default` environments are typically [shared via FloxHub][floxhub-env]; diff --git a/mkdocs.yml b/mkdocs.yml index 00b81c97..9fce7f9a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -69,6 +69,7 @@ nav: - Concepts: - Environments: concepts/environments.md - Activating environments: concepts/activation.md + - Auto-activation: concepts/auto-activation.md - Compatibility policy: concepts/compatibility.md - FloxHub: concepts/floxhub.md - FloxHub environments: concepts/floxhub-environments.md From 5348ded4c7c08ece0b8ff5abf64846479dd818b0 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Thu, 26 Mar 2026 19:32:52 -0700 Subject: [PATCH 02/22] docs: fix markdown lint error for fenced code block language Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/concepts/auto-activation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index ab835f69..7a22842b 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -157,7 +157,7 @@ so an environment in `/home/user/projects` activates before one in The shell prompt reflects all active environments: -``` +```text flox [projects myapp] $ ``` From e3907019825369102464d7a9ec4523be2e3ff792 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Fri, 27 Mar 2026 09:28:22 -0700 Subject: [PATCH 03/22] docs: add comparison table and behavior notes for auto-activation Add a "Comparison with manual activation" section with a table covering trigger, activation mode, services, trust, deactivation, multiple environments, hook.on-activate, and error handling differences. Clarify that auto-activation starts all manifest services automatically (unlike flox activate which requires --start-services). Add admonitions for activation mode limitation and hook.on-activate subprocess isolation behavior. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/concepts/auto-activation.md | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 7a22842b..78cce9ea 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -79,7 +79,9 @@ Here is what happens on each prompt: 2. **Trust check** — Each discovered environment is checked against the trust store. Only trusted environments proceed. 3. **Activation** — Trusted environments are activated outermost-first. - Environment variables are set, hooks run, and services start. + Environment variables are set, hooks run, and **all services defined in + the manifest are started automatically** (unlike `flox activate`, which + requires the `--start-services` flag). 4. **Deactivation** — When you leave a directory, its environment is deactivated and its changes to the shell are reverted. 5. **Reattachment** — If you return to a previously activated directory, @@ -188,6 +190,38 @@ management. The shell hook does not discover, activate, deactivate, or suppress manually activated environments. +## Comparison with manual activation + +Auto-activation and `flox activate` share the same core behavior +(packages, environment variables, hooks) but differ in several ways: + +| Behavior | `flox activate` (manual) | Auto-activation | +|----------|--------------------------|-----------------| +| **Trigger** | Explicit `flox activate` command | Automatic on `cd` into `.flox` directory | +| **Activation mode** | Configurable via `--mode` (dev/run/build) | Always `dev` mode | +| **Services** | Started only with `--start-services` flag | Started automatically for all manifest services | +| **Trust** | Implicit (user intentionally ran command) | Explicit trust required (`flox allow`) | +| **Deactivation** | `exit` (leaves subshell) | `flox deactivate` (stays in shell, suppresses for session) | +| **Multiple environments** | Nested subshells via repeated `flox activate` | Simultaneous activation of all `.flox` dirs in ancestor chain | +| **hook.on-activate** | Runs in activation subprocess; shell options, functions, and aliases take effect | Runs in separate subprocess; only env var changes are captured | +| **Error handling** | Activation aborts on failure | Failures are non-fatal; other environments still activate | + +!!! note "Activation mode" + + Auto-activation always uses `dev` mode. If you need `run` or `build` + mode, use `flox activate --mode run` explicitly. + +!!! info "hook.on-activate behavior" + + When an environment is auto-activated, the `hook.on-activate` script + runs in an isolated subprocess. Only environment variable changes are + captured and applied to your shell. Shell functions, aliases, and + shell options (e.g. `set -o vi`) set in `hook.on-activate` will not + take effect. + + For shell-level customizations, use `[profile]` scripts instead, + or activate the environment manually with `flox activate`. + ## Relationship to the default environment Previously, setting up a default environment required a line like: From 6b04dc310cbd2e5a9f1c0cc4dae2a4399c4651f6 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Fri, 27 Mar 2026 10:09:28 -0700 Subject: [PATCH 04/22] docs: fix accuracy issues in auto-activation documentation Correct three inaccuracies identified during code review: - Hook installation applies to all eval-mode invocations, not just bare `flox activate` - Subshell exclusion applies to all subshell activations, not just `-d`/`-r` - Default environment section now explains the old `-r` pattern still works and gets auto-activation for free, and clarifies `eval "$(flox activate)"` doesn't fetch from FloxHub Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/concepts/auto-activation.md | 52 ++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 78cce9ea..ea34621c 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -51,18 +51,19 @@ To enable auto-activation, add a single line to your shell's RC file: eval "`flox activate`" ``` -When `flox activate` is invoked in-place without targeting a specific -environment (no `-d` or `-r` flag), -it activates the current directory's environment _and_ installs a shell -hook that enables auto-activation for the rest of the session. +When `flox activate` is used in eval mode (e.g. `eval "$(flox activate)"`), +it installs a shell hook that enables auto-activation for the rest of the +session. If an environment exists in the current directory, it is also +activated. This applies regardless of whether `-d` or `-r` flags are +specified — the hook is always installed in eval mode. !!! note - If you previously used `eval "$(flox activate -r owner/default)"` to - set up your default environment, the new - `eval "$(flox activate)"` line replaces it. - It activates your current directory's environment (if one exists) - and enables auto-activation everywhere. + If you already have `eval "$(flox activate -r owner/default)"` in + your shell RC file for your default environment, you don't need to + change it. Auto-activation hooks are installed automatically + whenever `flox activate` is used in eval mode, regardless of + whether `-r` or `-d` flags are specified. See the [default environment tutorial](../tutorials/default-environment.md) for more details. @@ -184,11 +185,16 @@ one at a time. ## Interaction with manual activation -Environments activated manually — via `flox activate -d ` or -`flox activate -r /` — are excluded from auto-activation -management. +Environments activated in a **subshell** — via `flox activate`, +`flox activate -d `, or `flox activate -r /` without +`eval` — are excluded from auto-activation management. The shell hook does not discover, activate, deactivate, or suppress -manually activated environments. +these environments within the subshell. + +When `flox activate` is used in **eval mode** (e.g. +`eval "$(flox activate -d )"`), the activated environment is not +excluded. Instead, the auto-activation hook manages it alongside any +other discovered environments. ## Comparison with manual activation @@ -224,23 +230,29 @@ Auto-activation and `flox activate` share the same core behavior ## Relationship to the default environment -Previously, setting up a default environment required a line like: +If you already use a line like this for your default environment: ```{ .bash } eval "$(flox activate -r /default)" ``` -With auto-activation, the simplified setup is: +You don't need to change it. Since auto-activation hooks are installed +for all eval-mode invocations, this line already enables auto-activation +in addition to activating your default environment. + +Alternatively, if you prefer a local-only setup, you can replace it with: ```{ .bash } eval "$(flox activate)" ``` -This single line both activates the current directory's environment (if -one exists) and installs the auto-activation hook. -If you have a `.flox` environment in your home directory, -it will be auto-activated in every shell — serving the same purpose as -the old default environment pattern. +This installs the auto-activation hook without targeting a specific +remote environment. If you have a `.flox` environment in your home +directory (created with `flox init` or `flox pull`), it will be +auto-activated in every shell — serving a similar purpose to the old +default environment pattern. Note that `eval "$(flox activate)"` does +not fetch environments from FloxHub; it only discovers local `.flox/` +directories. See the [default environment tutorial](../tutorials/default-environment.md) From 44192757f79015d9a9e358a169995578c14eeb72 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Tue, 31 Mar 2026 14:18:29 -0700 Subject: [PATCH 05/22] Apply suggestion from @mkenigs Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index ea34621c..f2bda04e 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -85,9 +85,6 @@ Here is what happens on each prompt: requires the `--start-services` flag). 4. **Deactivation** — When you leave a directory, its environment is deactivated and its changes to the shell are reverted. -5. **Reattachment** — If you return to a previously activated directory, - the environment reattaches from cache rather than re-running hooks, - making it nearly instant. Most prompts trigger the **fast path**: the hook detects that nothing has changed (same directory, same environments, same manifest timestamps) and From 83a94a289f8ea240b2e8f4d1dc2f6a62e4970ca0 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Tue, 31 Mar 2026 14:19:06 -0700 Subject: [PATCH 06/22] Apply suggestion from @mkenigs Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index f2bda04e..08b1f159 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -130,8 +130,6 @@ flox revoke - **Deny is path-only.** The deny hash includes only the environment's path, so a denial persists across manifest changes. -- **Deny always wins.** If both allow and deny records exist for an - environment, it will not be auto-activated. ### Automatic trust From e8de96f655782b1adfc8247b13824d99c7c6cfc8 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Tue, 31 Mar 2026 14:19:43 -0700 Subject: [PATCH 07/22] Apply suggestion from @mkenigs Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 08b1f159..d3e2f969 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -200,7 +200,6 @@ Auto-activation and `flox activate` share the same core behavior |----------|--------------------------|-----------------| | **Trigger** | Explicit `flox activate` command | Automatic on `cd` into `.flox` directory | | **Activation mode** | Configurable via `--mode` (dev/run/build) | Always `dev` mode | -| **Services** | Started only with `--start-services` flag | Started automatically for all manifest services | | **Trust** | Implicit (user intentionally ran command) | Explicit trust required (`flox allow`) | | **Deactivation** | `exit` (leaves subshell) | `flox deactivate` (stays in shell, suppresses for session) | | **Multiple environments** | Nested subshells via repeated `flox activate` | Simultaneous activation of all `.flox` dirs in ancestor chain | From 841a85415fd8202bdf959f8ef2366f34f093337f Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Tue, 31 Mar 2026 14:20:05 -0700 Subject: [PATCH 08/22] Apply suggestion from @mkenigs Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index d3e2f969..d205865c 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -201,7 +201,6 @@ Auto-activation and `flox activate` share the same core behavior | **Trigger** | Explicit `flox activate` command | Automatic on `cd` into `.flox` directory | | **Activation mode** | Configurable via `--mode` (dev/run/build) | Always `dev` mode | | **Trust** | Implicit (user intentionally ran command) | Explicit trust required (`flox allow`) | -| **Deactivation** | `exit` (leaves subshell) | `flox deactivate` (stays in shell, suppresses for session) | | **Multiple environments** | Nested subshells via repeated `flox activate` | Simultaneous activation of all `.flox` dirs in ancestor chain | | **hook.on-activate** | Runs in activation subprocess; shell options, functions, and aliases take effect | Runs in separate subprocess; only env var changes are captured | | **Error handling** | Activation aborts on failure | Failures are non-fatal; other environments still activate | From a24619e74ac84a6be764275504df4452da31cbc5 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Tue, 31 Mar 2026 14:20:39 -0700 Subject: [PATCH 09/22] Apply suggestion from @mkenigs Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index d205865c..35a4244a 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -201,7 +201,6 @@ Auto-activation and `flox activate` share the same core behavior | **Trigger** | Explicit `flox activate` command | Automatic on `cd` into `.flox` directory | | **Activation mode** | Configurable via `--mode` (dev/run/build) | Always `dev` mode | | **Trust** | Implicit (user intentionally ran command) | Explicit trust required (`flox allow`) | -| **Multiple environments** | Nested subshells via repeated `flox activate` | Simultaneous activation of all `.flox` dirs in ancestor chain | | **hook.on-activate** | Runs in activation subprocess; shell options, functions, and aliases take effect | Runs in separate subprocess; only env var changes are captured | | **Error handling** | Activation aborts on failure | Failures are non-fatal; other environments still activate | From 72834099628560769d8c3e066961856eb917b155 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Tue, 31 Mar 2026 14:20:54 -0700 Subject: [PATCH 10/22] Apply suggestion from @mkenigs Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 35a4244a..aa1dbbca 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -202,7 +202,7 @@ Auto-activation and `flox activate` share the same core behavior | **Activation mode** | Configurable via `--mode` (dev/run/build) | Always `dev` mode | | **Trust** | Implicit (user intentionally ran command) | Explicit trust required (`flox allow`) | | **hook.on-activate** | Runs in activation subprocess; shell options, functions, and aliases take effect | Runs in separate subprocess; only env var changes are captured | -| **Error handling** | Activation aborts on failure | Failures are non-fatal; other environments still activate | +| **Error handling** | Activation aborts on failure | Individual activations abort on failure, but other layered activations continue | !!! note "Activation mode" From a0fe08a05c3ea422481ad01312693d06f1727ad4 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Tue, 31 Mar 2026 15:38:19 -0700 Subject: [PATCH 11/22] Apply review decisions from PR #456 - Document 3-command model: eval "$(flox activate)", flox activate, eval "$(flox hook)" - Update trust model to latest-decision-wins (timestamp-based) - Update services to use manifest config option instead of auto-start - Unify deactivation around flox deactivate, clarify innermost-only constraint - Remove hook.on-activate isolated subprocess note (profile scripts run consistently) - Update comparison table (add Deactivation row, remove hook.on-activate/Services rows) - Add "Why auto-activation instead of direnv?" section to activation.md Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/concepts/activation.md | 23 ++++++++++++ docs/concepts/auto-activation.md | 61 +++++++++++++++++++------------- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/docs/concepts/activation.md b/docs/concepts/activation.md index bcf752c2..4b701d95 100644 --- a/docs/concepts/activation.md +++ b/docs/concepts/activation.md @@ -352,6 +352,29 @@ environments, and trust-based security. To learn more, see the full [Auto-activation](./auto-activation.md) concept page. +### Why auto-activation instead of direnv? + +[direnv](https://direnv.net/) is a popular tool for loading environment +variables when you enter a directory. +Flox's auto-activation serves a similar purpose but goes further in +several ways: + +- **Aliases and functions** — direnv cannot export shell aliases or + functions ([direnv/direnv#73](https://github.com/direnv/direnv/issues/73)). + Flox environments can define both via `[profile]` scripts, and they + work in auto-activated environments just as they do in manual + activations. +- **Service interoperability** — Flox + [services](./services.md) persist across directory changes and + allow new shells to attach to already-running services. direnv has no + built-in service management. +- **CLI update notifications** — Flox can notify you when a newer CLI + version is available and provide a command or link to download it. +- **Better UX outside activated context** — Flox provides useful + commands (`flox search`, `flox show`, etc.) even when you are not + inside an activated environment, so you can discover and inspect + packages without entering a project directory first. + ## Conclusion As you can see, there's a lot going on under the hood, diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index aa1dbbca..84a8223d 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -51,11 +51,19 @@ To enable auto-activation, add a single line to your shell's RC file: eval "`flox activate`" ``` -When `flox activate` is used in eval mode (e.g. `eval "$(flox activate)"`), -it installs a shell hook that enables auto-activation for the rest of the -session. If an environment exists in the current directory, it is also -activated. This applies regardless of whether `-d` or `-r` flags are -specified — the hook is always installed in eval mode. +Flox provides three commands for shell integration: + +- **`eval "$(flox activate)"`** — Activates the environment in the current + directory _and_ installs the auto-activation hook. This is the recommended + command for your shell RC file. If no environment exists in the current + directory, the command fails with an error. The `-d` and `-r` flags can + target a specific environment, and the hook is always installed regardless + of which flags are used. +- **`flox activate`** — Activates an environment (subshell or in-place) without + installing the auto-activation hook. +- **`eval "$(flox hook)"`** — Installs the auto-activation hook _without_ + activating any environment. Use this if you want auto-activation but don't + have a default environment. !!! note @@ -80,9 +88,10 @@ Here is what happens on each prompt: 2. **Trust check** — Each discovered environment is checked against the trust store. Only trusted environments proceed. 3. **Activation** — Trusted environments are activated outermost-first. - Environment variables are set, hooks run, and **all services defined in - the manifest are started automatically** (unlike `flox activate`, which - requires the `--start-services` flag). + Environment variables are set and hooks run. + Services are controlled by the manifest's + [`options.services.auto-start`](../man/manifest.toml.md#options) option, + which applies equally to manual and auto-activation. 4. **Deactivation** — When you leave a directory, its environment is deactivated and its changes to the shell are reverted. @@ -127,8 +136,10 @@ flox revoke If the manifest changes (e.g. after `git pull`), trust is automatically revoked and you must run `flox allow` again. -- **Deny is path-only.** The deny hash includes only the environment's - path, so a denial persists across manifest changes. +- **Latest decision wins.** If both an allow and a deny exist for an + environment, the most recent decision (by timestamp) takes effect. + Running `flox allow` after `flox revoke` re-trusts the environment, + and vice versa. ### Automatic trust @@ -164,20 +175,33 @@ starting with the innermost (closest to CWD). ## Deactivation -[`flox deactivate`](../man/flox-deactivate.md) reverses the effects of -the innermost auto-activated environment: +[`flox deactivate`](../man/flox-deactivate.md) is the unified way to leave +any environment, whether it was activated manually or via auto-activation. + +`flox deactivate` reverses the effects of the **innermost** environment: - Reverts environment variables set by that environment. - Restores the shell prompt. - **Suppresses** that environment so the hook does not re-activate it while you remain in the directory. +Only the innermost (closest to CWD) environment can be deactivated. +Running `flox deactivate` on a non-innermost environment fails with a +helpful error — deactivate the inner layers first. +Environments that were explicitly activated (not auto-activated) are +immune to auto-deactivation by the hook. + If you leave the directory and return later, the suppression is lifted and the environment auto-activates again. Calling `flox deactivate` multiple times peels off additional layers, one at a time. +!!! note + + For subshell activations, `exit` still works to leave the subshell, + but `flox deactivate` is the recommended approach for consistency. + ## Interaction with manual activation Environments activated in a **subshell** — via `flox activate`, @@ -201,7 +225,7 @@ Auto-activation and `flox activate` share the same core behavior | **Trigger** | Explicit `flox activate` command | Automatic on `cd` into `.flox` directory | | **Activation mode** | Configurable via `--mode` (dev/run/build) | Always `dev` mode | | **Trust** | Implicit (user intentionally ran command) | Explicit trust required (`flox allow`) | -| **hook.on-activate** | Runs in activation subprocess; shell options, functions, and aliases take effect | Runs in separate subprocess; only env var changes are captured | +| **Deactivation** | `flox deactivate` or `exit` (subshell) | `flox deactivate` | | **Error handling** | Activation aborts on failure | Individual activations abort on failure, but other layered activations continue | !!! note "Activation mode" @@ -209,17 +233,6 @@ Auto-activation and `flox activate` share the same core behavior Auto-activation always uses `dev` mode. If you need `run` or `build` mode, use `flox activate --mode run` explicitly. -!!! info "hook.on-activate behavior" - - When an environment is auto-activated, the `hook.on-activate` script - runs in an isolated subprocess. Only environment variable changes are - captured and applied to your shell. Shell functions, aliases, and - shell options (e.g. `set -o vi`) set in `hook.on-activate` will not - take effect. - - For shell-level customizations, use `[profile]` scripts instead, - or activate the environment manually with `flox activate`. - ## Relationship to the default environment If you already use a line like this for your default environment: From 6cadd5615a9fce645b60c3f21fc244e19235da9f Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Tue, 31 Mar 2026 16:47:29 -0700 Subject: [PATCH 12/22] Separate trust from auto-activation preference in docs Split the "Trust and security" section into two distinct subsections: "Security trust" (existing mechanism) and "Auto-activation preference" (new `flox enable`/`flox disable` commands). Restructure "Enabling auto-activation" into two paths (with/without default env), add 3-command table, and address all 7 open review threads from PR #456. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/concepts/activation.md | 12 +- docs/concepts/auto-activation.md | 204 +++++++++++++++++++++++-------- 2 files changed, 158 insertions(+), 58 deletions(-) diff --git a/docs/concepts/activation.md b/docs/concepts/activation.md index 4b701d95..5ca20dcf 100644 --- a/docs/concepts/activation.md +++ b/docs/concepts/activation.md @@ -347,7 +347,8 @@ and deactivate when you leave. This is powered by a shell hook that runs on every prompt, discovering `.flox` directories in your directory's ancestor chain and managing their activation lifecycle — including hooks, services, nested -environments, and trust-based security. +environments, security trust, and per-environment auto-activation +preferences. To learn more, see the full [Auto-activation](./auto-activation.md) concept page. @@ -368,12 +369,9 @@ several ways: [services](./services.md) persist across directory changes and allow new shells to attach to already-running services. direnv has no built-in service management. -- **CLI update notifications** — Flox can notify you when a newer CLI - version is available and provide a command or link to download it. -- **Better UX outside activated context** — Flox provides useful - commands (`flox search`, `flox show`, etc.) even when you are not - inside an activated environment, so you can discover and inspect - packages without entering a project directory first. +- **Nested environment support** — Flox auto-activation natively supports + activating multiple layered environments from ancestor directories. + direnv does not natively support nested environments. ## Conclusion diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 84a8223d..619620fc 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -17,7 +17,21 @@ always ready — no manual activation required. ## Enabling auto-activation -To enable auto-activation, add a single line to your shell's RC file: +To enable auto-activation, add a single line to your shell's RC file. + +!!! note + + If you already have `eval "$(flox activate -r owner/default)"` in + your shell RC file for your default environment, you don't need to + change it. Auto-activation hooks are installed automatically + whenever `flox activate` is used in eval mode, regardless of + whether `-r` or `-d` flags are specified. + See the + [default environment tutorial](../tutorials/default-environment.md) + for more details. + +**With a default environment** — use `eval "$(flox activate)"` to +activate your default environment _and_ install the auto-activation hook: === "Bash" @@ -51,31 +65,61 @@ To enable auto-activation, add a single line to your shell's RC file: eval "`flox activate`" ``` +**Without a default environment** — use `eval "$(flox hook)"` to install +the auto-activation hook without activating any environment: + +=== "Bash" + + Add the following line to the end of your `~/.bashrc`: + + ```{ .bash .copy } + eval "$(flox hook)" + ``` + +=== "Zsh" + + Add the following line to the end of your `~/.zshrc`: + + ```{ .zsh .copy } + eval "$(flox hook)" + ``` + +=== "Fish" + + Add the following line to the end of your `~/.config/fish/config.fish`: + + ```{ .fish .copy } + flox hook | source + ``` + +=== "Tcsh" + + Add the following line to the end of your `~/.tcshrc`: + + ```{ .tcsh .copy } + eval "`flox hook`" + ``` + Flox provides three commands for shell integration: +| Command | Activates environment | Installs hook | +|---|---|---| +| `eval "$(flox activate)"` | Yes (fails if no env) | Yes | +| `flox activate` | Yes | No | +| `eval "$(flox hook)"` | No | Yes | + - **`eval "$(flox activate)"`** — Activates the environment in the current directory _and_ installs the auto-activation hook. This is the recommended - command for your shell RC file. If no environment exists in the current - directory, the command fails with an error. The `-d` and `-r` flags can - target a specific environment, and the hook is always installed regardless - of which flags are used. + command for your shell RC file if you have a default environment. If no + environment exists in the current directory, the command fails with an + error. The `-d` and `-r` flags can target a specific environment, and the + hook is always installed regardless of which flags are used. - **`flox activate`** — Activates an environment (subshell or in-place) without installing the auto-activation hook. - **`eval "$(flox hook)"`** — Installs the auto-activation hook _without_ activating any environment. Use this if you want auto-activation but don't have a default environment. -!!! note - - If you already have `eval "$(flox activate -r owner/default)"` in - your shell RC file for your default environment, you don't need to - change it. Auto-activation hooks are installed automatically - whenever `flox activate` is used in eval mode, regardless of - whether `-r` or `-d` flags are specified. - See the - [default environment tutorial](../tutorials/default-environment.md) - for more details. - ## How it works Once the shell hook is installed, it runs on every prompt @@ -85,9 +129,11 @@ Here is what happens on each prompt: 1. **Discovery** — The hook walks the directory tree from your current working directory up to the filesystem root, collecting all directories that contain a `.flox/` subdirectory. -2. **Trust check** — Each discovered environment is checked against the - trust store. Only trusted environments proceed. -3. **Activation** — Trusted environments are activated outermost-first. +2. **Eligibility check** — Each discovered environment is checked for two + conditions: (a) the environment must be **trusted** (security gate), + and (b) auto-activation must be **enabled** for it (preference gate). + Only environments that satisfy both conditions proceed. +3. **Activation** — Eligible environments are activated outermost-first. Environment variables are set and hooks run. Services are controlled by the manifest's [`options.services.auto-start`](../man/manifest.toml.md#options) option, @@ -101,12 +147,15 @@ exits immediately with no output or delay. ## Trust and security +Auto-activation involves two separate gates that must both be satisfied +before an environment will auto-activate: **security trust** and +**auto-activation preference**. + +### Security trust + Environments can run arbitrary code via their `[hook]` and `[profile]` scripts. -Auto-activation means this code runs automatically when you enter a -directory, -so Flox requires you to explicitly trust an environment before it will be -auto-activated. +Trust gates whether this code is allowed to execute. !!! warning @@ -115,51 +164,95 @@ auto-activated. This is especially important for environments obtained from untrusted sources (e.g. cloned repositories). -### Trusting and denying environments +- **Remote environments** — Trust is managed via the existing + [`flox activate -t`](../man/flox-activate.md) flag and the + `trusted_environments` configuration key + (e.g. `flox config --set trusted_environments."owner/name" trust`). + Trust is **content-sensitive**: the trust hash includes both the + environment's identity and the content of its manifest. If the manifest + changes (e.g. after `git pull`), trust is automatically revoked and you + must re-trust the environment. + +- **Local environments** — Trust is implicit in the act of enabling + auto-activation. When you run `flox enable` for a local environment, + that explicit action implies you have reviewed and trust the environment's + code. There is no separate trust step for local environments. + +### Auto-activation preference + +Even if an environment is trusted, it will not auto-activate unless you +have explicitly **enabled** auto-activation for it. This is a separate +preference gate that controls whether the hook should activate the +environment when you enter its directory. + +#### Interactive prompt + +When the hook discovers an environment that has not been registered +(neither enabled nor disabled), it prompts in interactive shells: + +```text +Auto-activate environment in /path/to/project? [y/N] +``` + +Answering **y** enables auto-activation for that environment. +Answering **N** (or pressing Enter) skips it for the current session. + +#### CLI commands -Use [`flox allow`](../man/flox-allow.md) to trust an environment: +Use [`flox enable`](../man/flox-enable.md) to enable auto-activation for +an environment: ```{ .bash .copy } -flox allow +flox enable ``` -Use [`flox revoke`](../man/flox-revoke.md) to deny auto-activation: +Use [`flox disable`](../man/flox-disable.md) to disable auto-activation: ```{ .bash .copy } -flox revoke +flox disable ``` -### How trust works +A single preference record is stored per environment — the latest decision +overwrites any previous one. + +#### How auto-activation preference works -- **Allow is content-sensitive.** The trust hash includes both the - environment's absolute path and the content of its manifest. - If the manifest changes (e.g. after `git pull`), trust is automatically - revoked and you must run `flox allow` again. +- **Not content-sensitive.** Unlike security trust, auto-activation + preference is not tied to manifest content. Once enabled, an environment + stays enabled regardless of manifest changes. If the trust mechanism + revokes trust due to content changes, that gates activation separately. -- **Latest decision wins.** If both an allow and a deny exist for an - environment, the most recent decision (by timestamp) takes effect. - Running `flox allow` after `flox revoke` re-trusts the environment, - and vice versa. +- **`flox init` does not auto-enable.** Creating a new environment does + not automatically enable auto-activation for it. You must explicitly + enable it via `flox enable` or by answering **y** at the interactive + prompt. +- **Preferences are stored** in `$XDG_STATE_HOME/flox/` (default + `~/.local/state/flox/`), mirroring where trust preferences are stored. -### Automatic trust +#### Global configuration -You don't need to manually run `flox allow` for environments you create -or modify through normal Flox commands: +The `auto_activate` configuration key controls the default behavior for +unregistered environments: -- `flox init` automatically trusts the newly created environment. -- `flox install`, `flox uninstall`, and `flox edit` automatically - re-trust the environment after modifying the manifest. +```{ .bash .copy } +flox config --set auto_activate "" +``` -Only **out-of-band changes** — such as `git pull`, manual edits, or -another user modifying the manifest — require you to run `flox allow` -again. +| Value | Behavior | +|---|---| +| `"prompt"` (default) | Prompt interactively for unregistered environments | +| `"always"` | Auto-activate all trusted environments without prompting (opt-out model) | +| `"never"` | Disable auto-activation entirely, even for explicitly enabled environments | + +This supports a phased rollout: Flox ships with `"prompt"` (opt-in) and +may later change the default to `"always"` (opt-out). ## Nested environments When multiple `.flox` directories exist in your directory's ancestor chain, -all trusted environments are activated simultaneously. +all eligible environments are activated simultaneously. Environments are activated outermost-first, so an environment in `/home/user/projects` activates before one in `/home/user/projects/myapp`. @@ -173,6 +266,12 @@ flox [projects myapp] $ Use `flox deactivate` to peel off layers one at a time, starting with the innermost (closest to CWD). +!!! note + + Environments in directories owned by other users require explicit + opt-in via `flox enable` like any other environment. Directory + ownership alone does not grant or deny trust. + ## Deactivation [`flox deactivate`](../man/flox-deactivate.md) is the unified way to leave @@ -224,14 +323,17 @@ Auto-activation and `flox activate` share the same core behavior |----------|--------------------------|-----------------| | **Trigger** | Explicit `flox activate` command | Automatic on `cd` into `.flox` directory | | **Activation mode** | Configurable via `--mode` (dev/run/build) | Always `dev` mode | -| **Trust** | Implicit (user intentionally ran command) | Explicit trust required (`flox allow`) | +| **Gate** | None — user explicitly chose to activate | Requires security trust + auto-activation enabled | | **Deactivation** | `flox deactivate` or `exit` (subshell) | `flox deactivate` | | **Error handling** | Activation aborts on failure | Individual activations abort on failure, but other layered activations continue | !!! note "Activation mode" - Auto-activation always uses `dev` mode. If you need `run` or `build` - mode, use `flox activate --mode run` explicitly. + Auto-activation always uses `dev` mode. The manifest setting + [`options.activate.mode`](../man/manifest.toml.md#options) controls + the default activation mode. Auto-activation respects this setting. + If you need `run` or `build` mode, use + `flox activate --mode run` explicitly. ## Relationship to the default environment @@ -277,6 +379,6 @@ but are documented here for debugging purposes. | `_FLOX_HOOK_DIRS` | Colon-separated list of `.flox` directories currently active via auto-activation | | `_FLOX_HOOK_WATCHES` | JSON array of watched manifest file paths and their modification times, used to detect changes | | `_FLOX_HOOK_SUPPRESSED` | Colon-separated list of directories suppressed by `flox deactivate` | - | `_FLOX_HOOK_NOTIFIED` | Colon-separated list of directories for which the user has already been warned about trust | + | `_FLOX_HOOK_NOTIFIED` | Colon-separated list of directories for which the user has already been prompted about auto-activation preference | | `_FLOX_HOOK_CWD` | Last-seen working directory, used for fast-path detection | | `_FLOX_HOOK_ACTIVATIONS` | Compressed record of per-environment activation metadata (store paths, cached hook output) | From 43d174dec40b31c8ffb01681bfa9e8e6dfa9831e Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Wed, 1 Apr 2026 12:24:53 -0700 Subject: [PATCH 13/22] Update manifest to schema-version 1.10.0 and add outputs Co-Authored-By: Claude Opus 4.6 (1M context) --- .flox/env/manifest.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.flox/env/manifest.toml b/.flox/env/manifest.toml index fcb15e05..298ec58c 100644 --- a/.flox/env/manifest.toml +++ b/.flox/env/manifest.toml @@ -1,14 +1,19 @@ -version = 1 +schema-version = "1.10.0" [install] coreutils.pkg-path = "coreutils" +coreutils.outputs = "all" findutils.pkg-path = "findutils" +findutils.outputs = "all" gnutar.pkg-path = "gnutar" +gnutar.outputs = "all" pandoc.pkg-path = "pandoc" poetry.pkg-path = "poetry" +poetry.outputs = "all" python.pkg-path = "python311" pngquant.pkg-path = "pngquant" gnused.pkg-path = "gnused" +gnused.outputs = "all" d2.pkg-path = "d2" lychee.pkg-path = "lychee" @@ -17,6 +22,7 @@ lychee.version = ">=0.23" markdownlint-cli2.pkg-path = "markdownlint-cli2" markdownlint-cli2.pkg-group = "lint" curl.pkg-path = "curl" +curl.outputs = "all" [hook] on-activate = ''' From 1f33042e4ce1dad0505ece76a3a15831967f207e Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Wed, 1 Apr 2026 12:24:54 -0700 Subject: [PATCH 14/22] Clarify services auto-start behavior and document manifest option Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/concepts/services.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/concepts/services.md b/docs/concepts/services.md index c373f00b..7390aae7 100644 --- a/docs/concepts/services.md +++ b/docs/concepts/services.md @@ -62,19 +62,25 @@ You can define a `shutdown.command` for any service, including services that do ## Starting services -Services can be started automatically when you activate your environment via -the `flox activate --start-services` command -(or via the shorter `flox activate -s`). -This will start services as part of activating your environment. +By default, services do not start automatically when you activate your +environment. There are two ways to start them: + +1. **Flag:** Pass `--start-services` (or `-s`) to `flox activate`. + This starts all services defined in the manifest for the current system. + +2. **Manifest option:** Set `options.services.auto-start = true` in your + manifest. This causes services to start automatically whenever the + environment is activated — including via + [auto-activation](auto-activation.md). The `-s` flag is not needed when + this option is set. + When activating your environment from multiple shells you only need to start the services once. Since your services are just processes running on your machine, they will be visible to any other activations. -Activating your environment without the `--start-services` flag will not start -the services. -If you activate your environment without services and then later decide that -you want to start them, that is done via the `flox services start` command. +If you activate your environment without starting services and then later +decide that you want to start them, use the `flox services start` command. When called without any arguments this command will start all services listed in the manifest. You can also specify individual service names, From 98d43a89e3f1965940b6180c633a14577b2dbac2 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Wed, 1 Apr 2026 12:24:55 -0700 Subject: [PATCH 15/22] Clarify that services are not started by default during auto-activation Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/concepts/auto-activation.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 619620fc..7cebbdbd 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -135,9 +135,10 @@ Here is what happens on each prompt: Only environments that satisfy both conditions proceed. 3. **Activation** — Eligible environments are activated outermost-first. Environment variables are set and hooks run. - Services are controlled by the manifest's - [`options.services.auto-start`](../man/manifest.toml.md#options) option, - which applies equally to manual and auto-activation. + Services are **not** started by default. + To have services start automatically, set + [`options.services.auto-start = true`](../man/manifest.toml.md#options) + in the manifest. 4. **Deactivation** — When you leave a directory, its environment is deactivated and its changes to the shell are reverted. From c671669e4e60ae4242e1f4c78ee10468ad32e8f1 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Wed, 1 Apr 2026 12:48:51 -0700 Subject: [PATCH 16/22] revert: remove manifest.toml schema and outputs changes from PR These changes are unrelated to the auto-activation documentation. Co-Authored-By: Claude Opus 4.6 (1M context) --- .flox/env/manifest.toml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.flox/env/manifest.toml b/.flox/env/manifest.toml index 298ec58c..fcb15e05 100644 --- a/.flox/env/manifest.toml +++ b/.flox/env/manifest.toml @@ -1,19 +1,14 @@ -schema-version = "1.10.0" +version = 1 [install] coreutils.pkg-path = "coreutils" -coreutils.outputs = "all" findutils.pkg-path = "findutils" -findutils.outputs = "all" gnutar.pkg-path = "gnutar" -gnutar.outputs = "all" pandoc.pkg-path = "pandoc" poetry.pkg-path = "poetry" -poetry.outputs = "all" python.pkg-path = "python311" pngquant.pkg-path = "pngquant" gnused.pkg-path = "gnused" -gnused.outputs = "all" d2.pkg-path = "d2" lychee.pkg-path = "lychee" @@ -22,7 +17,6 @@ lychee.version = ">=0.23" markdownlint-cli2.pkg-path = "markdownlint-cli2" markdownlint-cli2.pkg-group = "lint" curl.pkg-path = "curl" -curl.outputs = "all" [hook] on-activate = ''' From 7e587b9033e28a2e58e4eee93622ac5b1db8d3ce Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Thu, 2 Apr 2026 15:21:53 -0700 Subject: [PATCH 17/22] Update docs/concepts/auto-activation.md Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 7cebbdbd..453d71d1 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -137,7 +137,7 @@ Here is what happens on each prompt: Environment variables are set and hooks run. Services are **not** started by default. To have services start automatically, set - [`options.services.auto-start = true`](../man/manifest.toml.md#options) + [`services.auto-start = true`](../man/manifest.toml.md#options) in the manifest. 4. **Deactivation** — When you leave a directory, its environment is deactivated and its changes to the shell are reverted. From b8aef7b3a28bfdefdb7a2add8a9fa6467e6f41f7 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Thu, 2 Apr 2026 15:22:27 -0700 Subject: [PATCH 18/22] Update docs/concepts/auto-activation.md Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 453d71d1..24592439 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -323,7 +323,6 @@ Auto-activation and `flox activate` share the same core behavior | Behavior | `flox activate` (manual) | Auto-activation | |----------|--------------------------|-----------------| | **Trigger** | Explicit `flox activate` command | Automatic on `cd` into `.flox` directory | -| **Activation mode** | Configurable via `--mode` (dev/run/build) | Always `dev` mode | | **Gate** | None — user explicitly chose to activate | Requires security trust + auto-activation enabled | | **Deactivation** | `flox deactivate` or `exit` (subshell) | `flox deactivate` | | **Error handling** | Activation aborts on failure | Individual activations abort on failure, but other layered activations continue | From 27062257fd50877bbda30427c44870bd8eeeb64b Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Thu, 2 Apr 2026 15:22:58 -0700 Subject: [PATCH 19/22] Update docs/concepts/auto-activation.md Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 24592439..853d7d10 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -329,7 +329,7 @@ Auto-activation and `flox activate` share the same core behavior !!! note "Activation mode" - Auto-activation always uses `dev` mode. The manifest setting + The manifest setting [`options.activate.mode`](../man/manifest.toml.md#options) controls the default activation mode. Auto-activation respects this setting. If you need `run` or `build` mode, use From 6eefeeac2139fd6ae40a03337be6cb804dc79f1d Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Thu, 2 Apr 2026 15:23:48 -0700 Subject: [PATCH 20/22] Update docs/concepts/auto-activation.md Co-authored-by: Matthew Kenigsberg --- docs/concepts/auto-activation.md | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 853d7d10..9bcec84a 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -365,20 +365,3 @@ See the [default environment tutorial](../tutorials/default-environment.md) for more details on setting up a default environment. -## Advanced: hook state variables - -Auto-activation tracks its state using internal environment variables. -These are implementation details and subject to change, -but are documented here for debugging purposes. - -??? note "Internal state variables" - - | Variable | Description | - |----------|-------------| - | `_FLOX_HOOK_DIFF` | Compressed record of all environment variable changes (additions, modifications, deletions) applied by auto-activated environments | - | `_FLOX_HOOK_DIRS` | Colon-separated list of `.flox` directories currently active via auto-activation | - | `_FLOX_HOOK_WATCHES` | JSON array of watched manifest file paths and their modification times, used to detect changes | - | `_FLOX_HOOK_SUPPRESSED` | Colon-separated list of directories suppressed by `flox deactivate` | - | `_FLOX_HOOK_NOTIFIED` | Colon-separated list of directories for which the user has already been prompted about auto-activation preference | - | `_FLOX_HOOK_CWD` | Last-seen working directory, used for fast-path detection | - | `_FLOX_HOOK_ACTIVATIONS` | Compressed record of per-environment activation metadata (store paths, cached hook output) | From 53ae3845e4c4a7d52d2bb06e0497ef4afb3a3736 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Thu, 2 Apr 2026 15:48:54 -0700 Subject: [PATCH 21/22] Incorporate PR review feedback for auto-activation docs - Rename flox enable/disable to flox allow/deny (mirrors direnv) - Remove hallucinated trust/security content; simplify to single eligibility check (whether auto-activation is allowed) - Cut "always" from auto_activate config; default to "never" - Use flox activate -D for default environment examples - Move command descriptions above comparison table; use in-place/subshell terminology - Remove redundant "Relationship to default environment" section - Add auto-activation preference storage path - Note that "never" config disables hook installation Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/concepts/activation.md | 5 +- docs/concepts/auto-activation.md | 221 +++++++++++-------------------- 2 files changed, 83 insertions(+), 143 deletions(-) diff --git a/docs/concepts/activation.md b/docs/concepts/activation.md index 5ca20dcf..9952d9ae 100644 --- a/docs/concepts/activation.md +++ b/docs/concepts/activation.md @@ -346,9 +346,8 @@ and deactivate when you leave. This is powered by a shell hook that runs on every prompt, discovering `.flox` directories in your directory's ancestor chain and -managing their activation lifecycle — including hooks, services, nested -environments, security trust, and per-environment auto-activation -preferences. +managing their activation lifecycle — including hooks, services, and +nested environments. To learn more, see the full [Auto-activation](./auto-activation.md) concept page. diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 9bcec84a..6ec9a623 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -19,18 +19,28 @@ always ready — no manual activation required. To enable auto-activation, add a single line to your shell's RC file. -!!! note +Flox provides three commands for shell integration: - If you already have `eval "$(flox activate -r owner/default)"` in - your shell RC file for your default environment, you don't need to - change it. Auto-activation hooks are installed automatically - whenever `flox activate` is used in eval mode, regardless of - whether `-r` or `-d` flags are specified. - See the - [default environment tutorial](../tutorials/default-environment.md) - for more details. +- **In-place activation** (`eval "$(flox activate ...)"` in Bash/Zsh, + or equivalent in other shells) — Activates an environment in the + current shell _and_ installs the auto-activation hook. You can target + any environment with `-D` (default), `-d` (directory), or `-r` + (remote). If no environment exists, the command fails with an error. +- **Subshell activation** (`flox activate`) — Activates an environment + in a subshell without installing the auto-activation hook. +- **Hook only** (`eval "$(flox hook)"` in Bash/Zsh, or equivalent in + other shells) — Installs the auto-activation hook _without_ activating + any environment. Use this if you want auto-activation but don't have a + default environment. -**With a default environment** — use `eval "$(flox activate)"` to +| Command | Activates environment | Installs hook | +|---|---|---| +| `eval "$(flox activate -D)"` | Yes (default env) | Yes | +| `eval "$(flox activate -d .)"` | Yes (directory env) | Yes | +| `flox activate` | Yes | No | +| `eval "$(flox hook)"` | No | Yes | + +**With a default environment** — use in-place activation with `-D` to activate your default environment _and_ install the auto-activation hook: === "Bash" @@ -38,7 +48,7 @@ activate your default environment _and_ install the auto-activation hook: Add the following line to the end of your `~/.bashrc`: ```{ .bash .copy } - eval "$(flox activate)" + eval "$(flox activate -D)" ``` === "Zsh" @@ -46,7 +56,7 @@ activate your default environment _and_ install the auto-activation hook: Add the following line to the end of your `~/.zshrc`: ```{ .zsh .copy } - eval "$(flox activate)" + eval "$(flox activate -D)" ``` === "Fish" @@ -54,7 +64,7 @@ activate your default environment _and_ install the auto-activation hook: Add the following line to the end of your `~/.config/fish/config.fish`: ```{ .fish .copy } - flox activate | source + flox activate -D | source ``` === "Tcsh" @@ -62,9 +72,19 @@ activate your default environment _and_ install the auto-activation hook: Add the following line to the end of your `~/.tcshrc`: ```{ .tcsh .copy } - eval "`flox activate`" + eval "`flox activate -D`" ``` +!!! note + + Any in-place `flox activate` invocation installs the hook — not just + `-D`. If you already have + `eval "$(flox activate -r owner/default)"` in your shell RC file, + you don't need to change it. + See the + [default environment tutorial](../tutorials/default-environment.md) + for more details. + **Without a default environment** — use `eval "$(flox hook)"` to install the auto-activation hook without activating any environment: @@ -100,26 +120,6 @@ the auto-activation hook without activating any environment: eval "`flox hook`" ``` -Flox provides three commands for shell integration: - -| Command | Activates environment | Installs hook | -|---|---|---| -| `eval "$(flox activate)"` | Yes (fails if no env) | Yes | -| `flox activate` | Yes | No | -| `eval "$(flox hook)"` | No | Yes | - -- **`eval "$(flox activate)"`** — Activates the environment in the current - directory _and_ installs the auto-activation hook. This is the recommended - command for your shell RC file if you have a default environment. If no - environment exists in the current directory, the command fails with an - error. The `-d` and `-r` flags can target a specific environment, and the - hook is always installed regardless of which flags are used. -- **`flox activate`** — Activates an environment (subshell or in-place) without - installing the auto-activation hook. -- **`eval "$(flox hook)"`** — Installs the auto-activation hook _without_ - activating any environment. Use this if you want auto-activation but don't - have a default environment. - ## How it works Once the shell hook is installed, it runs on every prompt @@ -129,10 +129,10 @@ Here is what happens on each prompt: 1. **Discovery** — The hook walks the directory tree from your current working directory up to the filesystem root, collecting all directories that contain a `.flox/` subdirectory. -2. **Eligibility check** — Each discovered environment is checked for two - conditions: (a) the environment must be **trusted** (security gate), - and (b) auto-activation must be **enabled** for it (preference gate). - Only environments that satisfy both conditions proceed. +2. **Eligibility check** — Each discovered environment is checked to see + whether auto-activation has been **allowed** for it (see + [Allowing and denying auto-activation](#allowing-and-denying-auto-activation) + below). Only allowed environments proceed. 3. **Activation** — Eligible environments are activated outermost-first. Environment variables are set and hooks run. Services are **not** started by default. @@ -146,95 +146,65 @@ Most prompts trigger the **fast path**: the hook detects that nothing has changed (same directory, same environments, same manifest timestamps) and exits immediately with no output or delay. -## Trust and security - -Auto-activation involves two separate gates that must both be satisfied -before an environment will auto-activate: **security trust** and -**auto-activation preference**. +## Allowing and denying auto-activation -### Security trust - -Environments can run arbitrary code via their `[hook]` and `[profile]` -scripts. -Trust gates whether this code is allowed to execute. +An environment will not auto-activate unless you have explicitly +**allowed** it. This prevents unexpected code execution when you `cd` +into a directory containing an unfamiliar `.flox/` directory. !!! warning - Before trusting an environment, review its manifest to understand what - hooks and scripts it will run. - This is especially important for environments obtained from untrusted - sources (e.g. cloned repositories). - -- **Remote environments** — Trust is managed via the existing - [`flox activate -t`](../man/flox-activate.md) flag and the - `trusted_environments` configuration key - (e.g. `flox config --set trusted_environments."owner/name" trust`). - Trust is **content-sensitive**: the trust hash includes both the - environment's identity and the content of its manifest. If the manifest - changes (e.g. after `git pull`), trust is automatically revoked and you - must re-trust the environment. - -- **Local environments** — Trust is implicit in the act of enabling - auto-activation. When you run `flox enable` for a local environment, - that explicit action implies you have reviewed and trust the environment's - code. There is no separate trust step for local environments. + Before allowing auto-activation for an environment, review its + manifest to understand what hooks and scripts it will run. + This is especially important for environments obtained from + untrusted sources (e.g. cloned repositories). -### Auto-activation preference - -Even if an environment is trusted, it will not auto-activate unless you -have explicitly **enabled** auto-activation for it. This is a separate -preference gate that controls whether the hook should activate the -environment when you enter its directory. - -#### Interactive prompt +### Interactive prompt When the hook discovers an environment that has not been registered -(neither enabled nor disabled), it prompts in interactive shells: +(neither allowed nor denied), it prompts in interactive shells: ```text Auto-activate environment in /path/to/project? [y/N] ``` -Answering **y** enables auto-activation for that environment. +Answering **y** allows auto-activation for that environment. Answering **N** (or pressing Enter) skips it for the current session. -#### CLI commands +### CLI commands -Use [`flox enable`](../man/flox-enable.md) to enable auto-activation for +Use [`flox allow`](../man/flox-allow.md) to allow auto-activation for an environment: ```{ .bash .copy } -flox enable +flox allow ``` -Use [`flox disable`](../man/flox-disable.md) to disable auto-activation: +Use [`flox deny`](../man/flox-deny.md) to deny auto-activation: ```{ .bash .copy } -flox disable +flox deny ``` -A single preference record is stored per environment — the latest decision -overwrites any previous one. +A single preference record is stored per environment — the latest +decision overwrites any previous one. Preferences are stored in +`$XDG_STATE_HOME/flox/auto-activation.toml` +(default `~/.local/state/flox/auto-activation.toml`). -#### How auto-activation preference works +### How auto-activation preference works -- **Not content-sensitive.** Unlike security trust, auto-activation - preference is not tied to manifest content. Once enabled, an environment - stays enabled regardless of manifest changes. If the trust mechanism - revokes trust due to content changes, that gates activation separately. +- **Not content-sensitive.** Auto-activation preference is tied to the + environment's identity, not its manifest content. Once allowed, an + environment stays allowed regardless of manifest changes. -- **`flox init` does not auto-enable.** Creating a new environment does - not automatically enable auto-activation for it. You must explicitly - enable it via `flox enable` or by answering **y** at the interactive +- **`flox init` does not auto-allow.** Creating a new environment does + not automatically allow auto-activation for it. You must explicitly + allow it via `flox allow` or by answering **y** at the interactive prompt. -- **Preferences are stored** in `$XDG_STATE_HOME/flox/` (default - `~/.local/state/flox/`), mirroring where trust preferences are stored. - -#### Global configuration +### Global configuration -The `auto_activate` configuration key controls the default behavior for -unregistered environments: +The `auto_activate` configuration key controls the global behavior: ```{ .bash .copy } flox config --set auto_activate "" @@ -242,12 +212,16 @@ flox config --set auto_activate "" | Value | Behavior | |---|---| -| `"prompt"` (default) | Prompt interactively for unregistered environments | -| `"always"` | Auto-activate all trusted environments without prompting (opt-out model) | -| `"never"` | Disable auto-activation entirely, even for explicitly enabled environments | +| `"never"` (default) | Disable auto-activation entirely; the shell hook is not installed | +| `"prompt"` | Prompt interactively for unregistered environments | + +!!! note -This supports a phased rollout: Flox ships with `"prompt"` (opt-in) and -may later change the default to `"always"` (opt-out). + The initial release ships with `"never"` as the default so that + early adopters can opt in explicitly. The default may change to + `"prompt"` in a future release. When `auto_activate` is `"never"`, + in-place `flox activate` only activates the specified environment + without installing the shell hook. ## Nested environments @@ -270,8 +244,8 @@ starting with the innermost (closest to CWD). !!! note Environments in directories owned by other users require explicit - opt-in via `flox enable` like any other environment. Directory - ownership alone does not grant or deny trust. + opt-in via `flox allow` like any other environment. Directory + ownership alone does not grant or deny auto-activation. ## Deactivation @@ -306,11 +280,11 @@ one at a time. Environments activated in a **subshell** — via `flox activate`, `flox activate -d `, or `flox activate -r /` without -`eval` — are excluded from auto-activation management. +in-place mode — are excluded from auto-activation management. The shell hook does not discover, activate, deactivate, or suppress these environments within the subshell. -When `flox activate` is used in **eval mode** (e.g. +When `flox activate` is used **in-place** (e.g. `eval "$(flox activate -d )"`), the activated environment is not excluded. Instead, the auto-activation hook manages it alongside any other discovered environments. @@ -323,7 +297,7 @@ Auto-activation and `flox activate` share the same core behavior | Behavior | `flox activate` (manual) | Auto-activation | |----------|--------------------------|-----------------| | **Trigger** | Explicit `flox activate` command | Automatic on `cd` into `.flox` directory | -| **Gate** | None — user explicitly chose to activate | Requires security trust + auto-activation enabled | +| **Gate** | None — user explicitly chose to activate | Requires auto-activation to be allowed | | **Deactivation** | `flox deactivate` or `exit` (subshell) | `flox deactivate` | | **Error handling** | Activation aborts on failure | Individual activations abort on failure, but other layered activations continue | @@ -332,36 +306,3 @@ Auto-activation and `flox activate` share the same core behavior The manifest setting [`options.activate.mode`](../man/manifest.toml.md#options) controls the default activation mode. Auto-activation respects this setting. - If you need `run` or `build` mode, use - `flox activate --mode run` explicitly. - -## Relationship to the default environment - -If you already use a line like this for your default environment: - -```{ .bash } -eval "$(flox activate -r /default)" -``` - -You don't need to change it. Since auto-activation hooks are installed -for all eval-mode invocations, this line already enables auto-activation -in addition to activating your default environment. - -Alternatively, if you prefer a local-only setup, you can replace it with: - -```{ .bash } -eval "$(flox activate)" -``` - -This installs the auto-activation hook without targeting a specific -remote environment. If you have a `.flox` environment in your home -directory (created with `flox init` or `flox pull`), it will be -auto-activated in every shell — serving a similar purpose to the old -default environment pattern. Note that `eval "$(flox activate)"` does -not fetch environments from FloxHub; it only discovers local `.flox/` -directories. - -See the -[default environment tutorial](../tutorials/default-environment.md) -for more details on setting up a default environment. - From cf18fb4734a67c288a0863d198e12a27a61b0963 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Fri, 3 Apr 2026 12:05:52 -0700 Subject: [PATCH 22/22] Apply suggestions from code review Co-authored-by: Daniel Sauble --- docs/concepts/auto-activation.md | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/docs/concepts/auto-activation.md b/docs/concepts/auto-activation.md index 6ec9a623..74de446c 100644 --- a/docs/concepts/auto-activation.md +++ b/docs/concepts/auto-activation.md @@ -37,12 +37,10 @@ Flox provides three commands for shell integration: |---|---|---| | `eval "$(flox activate -D)"` | Yes (default env) | Yes | | `eval "$(flox activate -d .)"` | Yes (directory env) | Yes | +| `eval "$(flox activate -r /)"` | Yes (remote env) | Yes | | `flox activate` | Yes | No | | `eval "$(flox hook)"` | No | Yes | -**With a default environment** — use in-place activation with `-D` to -activate your default environment _and_ install the auto-activation hook: - === "Bash" Add the following line to the end of your `~/.bashrc`: @@ -78,7 +76,7 @@ activate your default environment _and_ install the auto-activation hook: !!! note Any in-place `flox activate` invocation installs the hook — not just - `-D`. If you already have + `-D`. For example, if you already have `eval "$(flox activate -r owner/default)"` in your shell RC file, you don't need to change it. See the @@ -262,14 +260,12 @@ any environment, whether it was activated manually or via auto-activation. Only the innermost (closest to CWD) environment can be deactivated. Running `flox deactivate` on a non-innermost environment fails with a helpful error — deactivate the inner layers first. -Environments that were explicitly activated (not auto-activated) are -immune to auto-deactivation by the hook. If you leave the directory and return later, the suppression is lifted and the environment auto-activates again. -Calling `flox deactivate` multiple times peels off additional layers, -one at a time. +Calling `flox deactivate` multiple times peels off additional layers, one at a time. +You can also specify a list of environments to deactivate (`flox deactivate foo bar bar`), but these must be the innermost environments. !!! note @@ -280,14 +276,10 @@ one at a time. Environments activated in a **subshell** — via `flox activate`, `flox activate -d `, or `flox activate -r /` without -in-place mode — are excluded from auto-activation management. -The shell hook does not discover, activate, deactivate, or suppress -these environments within the subshell. - -When `flox activate` is used **in-place** (e.g. -`eval "$(flox activate -d )"`), the activated environment is not -excluded. Instead, the auto-activation hook manages it alongside any -other discovered environments. +in-place mode — are managed alongside any other discovered environments. +Any newly activated environment becomes the innermost activation, and +must be deactivated before any other environment, regardless of how +they were activated. ## Comparison with manual activation @@ -297,12 +289,7 @@ Auto-activation and `flox activate` share the same core behavior | Behavior | `flox activate` (manual) | Auto-activation | |----------|--------------------------|-----------------| | **Trigger** | Explicit `flox activate` command | Automatic on `cd` into `.flox` directory | +| **Mode** | `flox activate -m` or `options.activate.mode` (manifest setting) | `options.activate.mode` (manifest setting) | | **Gate** | None — user explicitly chose to activate | Requires auto-activation to be allowed | | **Deactivation** | `flox deactivate` or `exit` (subshell) | `flox deactivate` | | **Error handling** | Activation aborts on failure | Individual activations abort on failure, but other layered activations continue | - -!!! note "Activation mode" - - The manifest setting - [`options.activate.mode`](../man/manifest.toml.md#options) controls - the default activation mode. Auto-activation respects this setting.