Skip to content

fix(mods): respect environment directory for loading mods#3334

Open
KY64 wants to merge 2 commits into
letta-ai:mainfrom
KY64:fix/respect-mod-directory-env-vars
Open

fix(mods): respect environment directory for loading mods#3334
KY64 wants to merge 2 commits into
letta-ai:mainfrom
KY64:fix/respect-mod-directory-env-vars

Conversation

@KY64

@KY64 KY64 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

LETTA_MODS_DIR and LETTA_EXTENSIONS_DIR env vars were respected by install / update / remove commands (via
resolveDefaultGlobalModsDirectory()), but ignored by both the runtime mod engine and letta mods list. This meant:

  1. letta install npm:foo → installed to the custom directory ✅
  2. letta mods list → looked in ~/.letta/mods/ instead
  3. Starting the TUI → loaded mods from ~/.letta/mods/ instead

Silent failure: the CLI appeared to work but the agent runtime never saw the mod.

Fixes #3333.

Root Cause

  • src/mods/mod-engine.ts called getGlobalModsDirectory() and
    getLegacyGlobalExtensionsDirectory() which is resolved to the hardcoded defaults (~/.letta/mods/, ~/.letta/extensions/) even
    when env vars were set.

  • src/cli/subcommands/mods.ts had the same pattern: listMods() called getGlobalModsDirectory() and
    getLegacyGlobalExtensionsDirectory() directly, bypassing env var resolution entirely.

Changes

src/mods/paths.ts

  • New ResolvedGlobalModDirectories interface and resolveGlobalModDirectories() function — resolves both
    directories independently from env vars, falling back to the hardcoded defaults. Unlike
    resolveDefaultGlobalModsDirectory(), this does NOT fall back from ~/.letta/mods/ to ~/.letta/extensions/ — the
    runtime treats them as separate sources.

src/mods/mod-engine.ts

  • resolveLocalModSources() now respect env vars for mods directory.
  • getLegacyExtensionMigrationTarget() now resolves the migration target root from env vars instead of the
    hardcoded default, so the diagnostic message points to the correct custom directory.

src/cli/subcommands/mods.ts

  • listMods() now respect env vars for mods directory.

This is to ensure consistency from installing, loading, listing mods
to respect LETTA_MODS_DIR and LETTA_EXTENSIONS_DIR
Comment thread src/mods/paths.ts Outdated
const envDirs = getModsDirectoryFromEnv(env);
return {
globalModsDirectory:
envDirs.globalModsDirectory ?? getGlobalModsDirectory(homeDirectory),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This keeps an empty string from getModsDirectoryFromEnv because it uses ??. That regresses the existing env parsing where LETTA_MODS_DIR=/whitespace is treated as unset: runtime/list now resolve the global mods root to "" and stop loading the default mods dir. Can we normalize empty strings to undefined, or use the same || fallback here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, let me update.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated a408d9c

@KY64 KY64 requested a review from carenthomas July 15, 2026 00:57
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.

[bug] inconsistent use of LETTA_MODS_DIR and LETTA_EXTENSIONS_DIR

2 participants