Flox auto-activation

Intro

I led and co-built cd-to-activate for Flox. It shipped on by default in Flox 1.14.0. That was about four months after a prototype I started in a day.

Flox environments only help when they're active. Activating one meant typing flox activate. Tools like direnv taught developers to expect activation on cd. The bet was that people would use Flox more if it turned on by itself.

As a product designer at Flox, I kicked this off with a prototype of an idea on our CTO's roadmap. I wrote the user docs before the production code. I became project lead in mid-June, and I was a main implementer.

Team and collaboration

I worked most closely with our CTO and three engineers.

Engineer CTO Engineer Engineer

Work moved from my prototype to user docs, then to formal requirements and small PRs.

Deactivation problem

It started as an experiment while I tried the Amp coding agent. What would a direnv-like Flox feel like?

Entering a directory turned out to be the easy half. Leaving has to undo variables, [profile] scripts, services, and nested environments, in four shells. That needs a flox deactivate that actually deactivates. Ours was hidden and only told you to type exit.

A prototype in a day

Over March 19–20, I built the first version with Amp. Our CTO saw a working demo, not a mockup. The next two weeks of hardening were in Claude Code.

Docs as the spec

On March 26, I opened a user-facing docs PR. When the engineer who wrote our requirements noted the 4,000-line prototype was too big to review, I pitched it as a throwaway. The docs became the spec, which would force us to say how it works for an end user. Open questions went into a Notion doc.

After an April 2 design review, he turned the docs into formal requirements and a design. Then we rebuilt in small PRs.

I later wrote the shipped version of those docs, the auto-activation concept page:

The auto-activation concept page in the Flox docs

Claude Code in production

Every commit in my 28 merged PRs carries a Claude co-author trailer. Claude's review bot caught a shell-injection risk in one of them before it merged.

The second time: making activation visible

In-place and auto-activations were silent, so you couldn't tell what was on. On July 30–31, I prototyped a fix with Claude Code. Our CTO pitched it as an experiment: prototype to release in one sprint.

Claude Code drafted six PRs. I questioned the telemetry one and had another one split, which made eight. Five merged on August 5, within three days of opening.

Two commands, not three

I cut flox hook, leaving flox activate and flox deactivate. It's a simpler mental model, even though people who wanted only the hook now get a default environment.

One prompt per cd

I made the default one batched consent prompt, even though that costs an extra prompt. While it was behind a flag, anyone who turned it on wanted to try it. So requiring flox activate allow first felt like needless friction.

The docs show the prompt:

Auto-activate the environment in '/path/to/project'? [y/N]

Before launch, the engineer who wrote our requirements made a "no" stick, since typing a command to refuse for good was surprising. I agreed.

Announce once, then get out of the way

Colleagues suggested announcing activations in one line and showing default environments in the prompt. My framing was that a line on each change buys a shorter prompt. So flox [acme/core (local)] became flox [core].

We also considered abbreviating the owner instead of hiding it, and adding a setting to silence announcements. I decided against both. You know whose environment you're in, and the old (bad) behavior didn't need a setting. The cost is that two default environments look alike, and announcements have no off setting.

What didn't work

Outcome