Skip to content

docs(llms.txt): tell agents how Flox is actually installed - #90

Merged
imkarrer merged 3 commits into
mainfrom
isaac/dev-315-llms-installer
Sep 10, 2026
Merged

docs(llms.txt): tell agents how Flox is actually installed#90
imkarrer merged 3 commits into
mainfrom
isaac/dev-315-llms-installer

Conversation

@imkarrer

@imkarrer imkarrer commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Line 20 of the llms.txt preamble tells agents there is no curl | bash installer and that install.flox.dev and flox.dev/install do not exist. llms-full.txt, served from this same site, carries curl -fsSL https://get.flox.dev | sh six times. This replaces the prohibition with the command.

Review this first: the replacement line itself. llms.txt is the generated half — regenerated with scripts/generate-llms-txt.sh, as check-llms-txt.yml requires.

Linear: DEV-315

All three clauses are now false
Claim Now
"There is no curl | bash installer" get.flox.dev returns a ~37KB install script, and it is what /download/ and docs/install-flox/install both lead with
"install.flox.dev … does not exist" Becomes a second CloudFront alias for the same object under flox/deltaops#796 (DEV-146)
"flox.dev/install does not exist" Redirects to /download/ since flox/floxwebsite#1111

The line was correct when written, and it was added on purpose: agents were inventing install URLs, and naming the two they invented most often was the cheapest way to stop them. Nothing about it was careless. It outlived its facts, which every prohibition eventually does. It matters more here than it would elsewhere in the corpus because the preamble is what an agent reads before it reads anything else.

Why it does not warn about the other URLs

Every prohibition is a fact with an expiry date, and this line is what happens when three of them expire at once. The replacement names one command and the pin, and says nothing about what not to construct.

install.flox.dev goes unmentioned even though it is about to work. Its value is catching people who guess it, which it does whether or not the preamble mentions it. flox.dev/install also goes unmentioned: it resolves to an HTML page, so it is only dangerous when piped into a shell, and the guard for that belongs in the flox-skills eval suite rather than in a line that has to stay true for years.

How this was reported

Found while reviewing flox/floxhub#2366, which led FloxHub's onboarding with the curl installer. The reporter had hit the same wall as a user before joining Flox — several rounds of arguing with an agent that insisted flox.dev/install was the way, then that no installer existed at all.

Verification

./scripts/generate-llms-txt.sh run and committed: 107 pages in 21 sections, all with descriptions. The diff is two lines, one in llms.txt.header and its generated counterpart in llms.txt.

Live checks behind the table above: get.flox.dev 200 (content-type: text/x-shellscript), flox.dev/download/ 200 leading with the one-liner, install.flox.dev not yet resolving (pending flox/deltaops#796), flox.dev/install now 302s to /download/ (flox/floxwebsite#1111 deployed since this branch was cut).

The preamble told agents there is no `curl | bash` installer, and that
`install.flox.dev` and `flox.dev/install` do not exist. Every one of those
claims was true when it was written and none is true now: `get.flox.dev`
serves the install script, and llms-full.txt on this same site carries the
command six times. The guardrail had become the thing agents were wrong
about.

Replace the prohibition with the command, the platform dispatch the script
performs, and the FLOX_VERSION pin. Regenerate llms.txt, which
check-llms-txt.yml requires to match the generator.
@mintlify

mintlify Bot commented Sep 8, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
flox 🟢 Ready View Preview Sep 8, 2026, 11:05 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

Review found three problems with the replacement bullet.

It sent readers to flox.dev/download for "package-manager installs and the raw
downloads". That page leads with the same curl script and one platform button;
Homebrew, the APT and YUM repositories, and every raw .deb/.rpm/.pkg link are
on the install docs page, which the bullet cited second. The two clauses were
swapped relative to reality.

`FLOX_VERSION=<version> pins a release` did not say where the assignment goes.
It must follow the pipe; an agent writing `FLOX_VERSION=1.16.0 curl … | sh`
sets it on curl and silently installs current stable. Preventing exactly that
guess is what this preamble is for, so show the whole pipeline.

Added the bounds an agent will otherwise walk into: the script installs but
never upgrades, and it refuses on an existing Nix install, ostree
distributions, openSUSE/SLES, and RPM systems without dnf or yum.

Code-format apt, dnf and yum, per AGENTS.md, matching line 16 of this file.
@imkarrer

imkarrer commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Automated review: 2 independent seats (standards, spec).

Fixed here:

  • The bullet sent readers to flox.dev/download for package-manager installs and raw downloads. Those live on the install docs page — the two clauses were swapped.
  • FLOX_VERSION=<version> did not say where the assignment goes. It must follow the pipe; before it, it lands on curl and the pin silently no-ops into current stable. The whole pipeline is now shown.
  • apt/dnf/yum not code-formatted (AGENTS.md style rule), and one sentence carrying four ideas.
  • Added the bounds an agent walks into: the script installs but never upgrades, and refuses on an existing Nix install, ostree distributions, openSUSE/SLES, and RPM systems without dnf/yum.

Verified: generator re-run leaves an empty diff, so check-llms-txt.yml passes. llms-full.txt needs no change — Mintlify builds it from page content, which is already correct. No surviving copies of the retracted claim elsewhere in the repo.

Comment thread llms.txt Outdated
Comment thread llms.txt.header Outdated
Review: the landing page is for the marketing site, and an agent reading this
preamble has no use for it. The install docs page it already links carries
Homebrew, the APT and YUM repositories, and every raw package, so the second
URL added a hop rather than a destination.
imkarrer added a commit to flox/flox-skills that referenced this pull request Sep 9, 2026
…pins

Review (@stephenyeargin): we do not want an agent installing anything but the
newest Flox if we can help it, and FLOX_CHANNEL has no business in
agent-facing prose at all.

Both are right, and the evidence for the version half is in this branch's own
history: earlier drafts hardcoded 1.14.0 and then 1.16.0, and 1.14.0 was
already two releases stale the day it was written. An agent that pins picks
the version it remembers, which is exactly the failure mode.

So FLOX_CHANNEL is gone everywhere, and FLOX_VERSION is gone from SKILL.md,
ci.md and publish.md. It survives only as a named escape hatch in the two
places a reader could otherwise think it was forbidden, each saying not to
reach for it unasked. The after-the-pipe placement note goes with it — it
existed only to serve a pin we no longer teach.

`ghcr.io/flox/flox:latest` replaces the pinned tag, which also answers the
review question directly: latest is maintained, and resolves to the same
digest as v1.16.0, itself current stable. Pinning is now named as the
exception for byte-identical rebuilds rather than the default.

Carried the same reviewer's flox.dev/download point from flox/docs#90
through this repo: an agent does not care about the marketing landing page,
and the raw packages are on the install docs page anyway. Docs links take the
.md suffix, per the review suggestion and the rest of the file.

The gated task asked "how do I pin a specific version?", so it moved too —
otherwise the skill would start failing an eval for obeying the review.

  gate                     PASS   judge 4/5
  screening --reps 5       baseline 0/5, skills 5/5, gap 3.4, discriminator
@imkarrer
imkarrer added this pull request to the merge queue Sep 10, 2026
Merged via the queue into main with commit d6f03c4 Sep 10, 2026
4 checks passed
@imkarrer
imkarrer deleted the isaac/dev-315-llms-installer branch September 10, 2026 14:09
imkarrer added a commit to flox/flox-skills that referenced this pull request Sep 10, 2026
…answers that do (#113)

The `flox` skill told agents that Flox has no `curl | bash` installer.
One has existed since `get.flox.dev` shipped, and the eval suite
enforced the retracted claim — failing the *correct* answer on 24 of 36
tasks. This fixes the claim, the check that enforced it, and the gap it
left.

**Review this first:** the two endpoint rules in `evals/flox/run.py`,
and the Quick Reference entry in `SKILL.md`. Everything else follows
from those two decisions.

Linear:
[DEV-315](https://linear.app/floxdotdev/issue/DEV-315/update-llm-documentation-for-new-install-capabilities).
The `llms.txt` half is
[flox/docs#90](flox/docs#90).

Measured, `--reps 5` on the fixed harness: baseline **1/5**, skills
**5/5**, judge gap 3.4, classified a discriminator.

<details>
<summary>What was wrong</summary>

Three surfaces carried the claim, and each was correct when written:

- `SKILL.md` — "Do NOT suggest `install.flox.dev`, `flox.dev/install`,
or any `curl | bash` one-liner — none of these exist."
- `references/ci.md`, in three places, and `references/publish.md`'s
GitLab section.
- `evals/flox/run.py` — `no_fake_install_url` banned the `curl … | sh`
*shape*, on 24 tasks.

Meanwhile `llms-full.txt` on flox.dev carried the command six times. The
skill and the docs contradicted each other on the same site.

A confidently wrong answer is worse than the hallucination it replaced:
a model that invents a URL produces a 404 the user can see; a model that
says the installer does not exist sends them off to hand-roll a `.deb`
download.

</details>

<details>
<summary>The eval check: a shape ban became an endpoint
allowlist</summary>

Two rules replace the shape ban:

1. **Only a host that serves the script may be piped into a shell.**
Catches `curl https://flox.dev/install | sh` — that URL redirects to an
HTML page, so it installs nothing. Measured: `sh` exits 127 without
`-L`, 2 with it. Both loud, so this grades a *wrong* answer rather than
guarding a dangerous one.
2. **No invented `*.flox.dev` host anywhere.** `releases.flox.dev`
appears in a committed baseline un-piped, so rule 1 alone would miss it.

Each URL is paired with the pipe it actually feeds — the span to the
next URL — because scanning whole lines failed correct answers that
carried both the one-liner and a docs link.

`evals/floxify` keeps the old shape ban deliberately, now with a comment
saying why: it greps the generated *manifest*, where installing Flox is
wrong whatever URL it names.

</details>

<details>
<summary>The skill fix had to move, and the eval is how we
know</summary>

Rewriting the "Installing Flox" section was **not enough**. With the
prohibition deleted and the section leading with the installer, the
model still answered:

> "There is **no `curl | bash` one-liner** for Flox — ignore anything
you may have seen suggesting `install.flox.dev` or `flox.dev/install`."

It reproduced the retracted claim nearly verbatim while reading a skill
that no longer contains it. That text was published on flox.dev long
enough to be in the model's prior; deleting it from the skill does not
delete it from the model.

So the fact also lives in the Quick Reference — which `SKILL.md` defines
as the home for specifics "easy to get wrong from memory", authoritative
and used inline — and says plainly that recall to the contrary is stale.

Not isolated: whether the *placement* or the *wording* carries it. The
section-only variant has not been run on the fixed harness.

</details>

<details>
<summary>The harness was grading models against their own answer
key</summary>

Found while screening this change. A **baseline** answer opened:

> "I checked the eval's ground truth for the real Flox install URLs, so
this is accurate."

Both harnesses allow every arm the `Read` tool, which the skills arm
needs for a skill's reference files, and neither passed a `cwd` — so
`claude` inherited `evals/flox`, where `tasks/*.jsonl` hold the prompt,
the rubric and `must_match`. The answer key was one relative path away
for every run this suite has ever made.

It inflates the baseline hardest, because what a skill contributes is
what a rubric spells out — so it presents as "no signal",
indistinguishable from a task that genuinely fails to discriminate. That
is exactly how this task first screened.

The agent now launches in an empty temp directory; three tests pin it.
Closing it moved the same baseline from 5/5 to 1/5.

**Every screening number predating this is suspect,
`baselines/screen-*.json` included.** Failures are the exception: a run
that failed with the answer key reachable failed for real. Re-baselining
is bigger than this PR.

</details>

<details>
<summary>Installing Flox into an image</summary>

`containers.md` covered `flox containerize` — turning an environment
*into* an image — and nothing covered getting the CLI *into* an image
you build. That gap is why hand-rolled agent images reconstruct the
download with an architecture case statement and a stale pin.

Container-tested on aarch64 under Colima:

| Case | Result |
|---|---|
| Root, no daemon, `NIX_REMOTE=auto` | `flox activate` exit 0 |
| Non-root, no daemon | fails on `/nix/var/nix/db/big-lock` |
| Non-root, daemon started | exit 0 |
| `buildkite/agent:3-ubuntu` | runs as **root**; no `buildkite-agent`
account |

The first draft had this backwards, asserting the Buildkite agent runs
unprivileged. It does not, which also made its `USER root` line a no-op.
Root is a property of the **deployment**, not the image — `docker run
--user`, Compose `user:` and `securityContext.runAsUser` override it,
and the Buildkite Helm chart commonly does — so the section says that
and gives a check.

</details>

<details>
<summary>Verification</summary>

```
evals/flox     225 tests, OK
evals/floxify  599 tests, OK (15 skipped)
```

Screening, `--reps 5`, Opus: baseline 1/5 (judge 1.4, incorrect), skills
5/5 (judge 4.8, correct), gap 3.4, **discriminator**.

Container tests: both Dockerfiles in the new section built and run; the
root and non-root branches exercised in both states.

Live endpoint checks: `get.flox.dev` 200 `text/x-shellscript`;
`flox.dev/install` 302 to `/download/`; `install.flox.dev` unresolved
pending flox/deltaops#796.

</details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants