Context
legacy_shell (modules/module_legacy_shell.sh, core/core_legacy_shell.sh) was
just built to detect and disable shell tooling that duplicates what devboost already
manages: a pre-existing zinit setup duplicating znap's plugins, asdf duplicating
mise, and — the big one — nvm's shell hook in ~/.zprofile duplicating mise,
measured at ~850-900ms per login shell via zprof on the investigation machine
(the dominant real-world contributor to the "new terminal tab takes 1-2s" complaint
that started this whole investigation — see #5).
Two product gaps identified in review, both from the same conversation:
1. Naming
"legacy_shell" is an internal engineering label, not something that reads well to a
user in doctor/apply output or docs. Wanted: something coder-familiar, not
consumer-sales-y — explicitly ruled out anything in the "optimize your system!"
register. Needs a real naming pass (module name, config key legacy_shell: in
.devboost.yaml, migration IDs like nvm-mise-dup, CLI-facing strings) — not just a
cosmetic string swap, since the config key is user-facing surface once anyone adopts
this.
2. Removal needs the same product care as installation
Every existing devboost module explains what it's adding and why (README's "What
Gets Installed" section, doctor's success/warn messages). This module removes
things, and that's a fundamentally different, higher-stakes action from the user's
perspective — but today apply just prints a flat "Disabled redundant lines
(nvm-mise-dup) in: ~/.zprofile" with none of the reasoning a user would want before
trusting a tool to touch their shell config.
Wanted, per conversation, using nvm as the concrete example:
- Quantify the win: state the measured/estimated time saved (e.g. "this was
costing ~850ms on every new terminal tab") — not just "redundant." Ideally
measured on the user's own machine via a quick before/after, not a hardcoded
number from one investigation.
- Explain the risk of the status quo, not just the redundancy: running multiple
version managers for the same language isn't just slower, it's a correctness
hazard — they can each install their own shims/PATH entries and silently disagree
about which Node version is active depending on shell init order, which is a much
harder bug to diagnose than "shell is slow." Worth naming this explicitly so users
understand why consolidating isn't just a performance nice-to-have.
- Give a forward path: since disabling nvm's hook doesn't migrate anything (any
Node versions installed only via nvm still need moving to mise), the output should
point at how to do that — ideally a link to a migration doc/guide (devboost's own
README section, or upstream mise docs on migrating from nvm) rather than leaving
the user to figure it out.
- General principle: this should generalize beyond nvm to any current or future
removal this module performs (asdf, zinit) and probably to any future
removal-shaped module — letting go of something in the user's system should always
be visible and explained, symmetric with how installation is already treated.
Worth deciding whether this is a per-migration static message (simplest) or
something more structured (a small "migration notes" registry keyed by
migration_id, so apply's output and a doctor/plan preview can both draw from
the same source).
Scope note
This is explicitly a follow-up, not a blocker for the initial legacy_shell module
landing — the mechanism (detect, comment-out-not-delete, clean command,
snapshots) is solid and tested; this issue is about the naming and the
explain-what-we-removed-and-why UX layer on top of it.
Relates to
Context
legacy_shell(modules/module_legacy_shell.sh,core/core_legacy_shell.sh) wasjust built to detect and disable shell tooling that duplicates what devboost already
manages: a pre-existing
zinitsetup duplicating znap's plugins,asdfduplicatingmise, and — the big one —
nvm's shell hook in~/.zprofileduplicating mise,measured at ~850-900ms per login shell via
zprofon the investigation machine(the dominant real-world contributor to the "new terminal tab takes 1-2s" complaint
that started this whole investigation — see #5).
Two product gaps identified in review, both from the same conversation:
1. Naming
"legacy_shell" is an internal engineering label, not something that reads well to a
user in
doctor/applyoutput or docs. Wanted: something coder-familiar, notconsumer-sales-y — explicitly ruled out anything in the "optimize your system!"
register. Needs a real naming pass (module name, config key
legacy_shell:in.devboost.yaml, migration IDs likenvm-mise-dup, CLI-facing strings) — not just acosmetic string swap, since the config key is user-facing surface once anyone adopts
this.
2. Removal needs the same product care as installation
Every existing devboost module explains what it's adding and why (README's "What
Gets Installed" section, doctor's success/warn messages). This module removes
things, and that's a fundamentally different, higher-stakes action from the user's
perspective — but today
applyjust prints a flat "Disabled redundant lines(nvm-mise-dup) in: ~/.zprofile" with none of the reasoning a user would want before
trusting a tool to touch their shell config.
Wanted, per conversation, using nvm as the concrete example:
costing ~850ms on every new terminal tab") — not just "redundant." Ideally
measured on the user's own machine via a quick before/after, not a hardcoded
number from one investigation.
version managers for the same language isn't just slower, it's a correctness
hazard — they can each install their own shims/PATH entries and silently disagree
about which Node version is active depending on shell init order, which is a much
harder bug to diagnose than "shell is slow." Worth naming this explicitly so users
understand why consolidating isn't just a performance nice-to-have.
Node versions installed only via nvm still need moving to mise), the output should
point at how to do that — ideally a link to a migration doc/guide (devboost's own
README section, or upstream mise docs on migrating from nvm) rather than leaving
the user to figure it out.
removal this module performs (asdf, zinit) and probably to any future
removal-shaped module — letting go of something in the user's system should always
be visible and explained, symmetric with how installation is already treated.
Worth deciding whether this is a per-migration static message (simplest) or
something more structured (a small "migration notes" registry keyed by
migration_id, so
apply's output and adoctor/planpreview can both draw fromthe same source).
Scope note
This is explicitly a follow-up, not a blocker for the initial
legacy_shellmodulelanding — the mechanism (detect, comment-out-not-delete,
cleancommand,snapshots) is solid and tested; this issue is about the naming and the
explain-what-we-removed-and-why UX layer on top of it.
Relates to
conventions should live for any future removal-shaped module, not just this one)