Skip to main content
Shell integration unlocks Better PM’s full potential by enabling the pm cd command to actually change your shell’s working directory, rather than just printing a path.

Quick Setup

Add this line to your shell configuration file:
Then reload your shell:

What Gets Activated

The pm activate command outputs two things:
  1. Shell wrapper function - Intercepts pm cd to enable directory navigation
  2. Enhanced completions - Adds package name completions for pm cd

The Shell Wrapper

Here’s what the wrapper function does (from src/commands/activate.ts):
Shell wrapper (simplified)
How it works:
1

Intercepts pm cd

When you run pm cd @myapp/web, the shell function catches it before the actual CLI runs.
2

Executes the CLI command

Calls command pm cd @myapp/web to get the package directory path from the Better PM CLI.
3

Changes directory

If the CLI succeeds and returns a valid directory, uses builtin cd to navigate there.
4

Handles flags correctly

If you pass flags like --completions, it just executes the command normally without changing directory.

Enhanced Completions

The activation also sets up intelligent completions that list your workspace packages when you type:
This shows all available workspace package names, making navigation much faster.

Zsh Integration

For zsh, the activation adds custom completion logic:
Zsh completions
What this does:
  • First loads the base completions generated by Better PM’s CLI framework
  • Wraps the completion function to add custom behavior for pm cd
  • When completing the first argument after pm cd, calls pm cd --completions to get package names
  • For all other commands, delegates to the base completion function
The --completions flag is handled by src/commands/cd.ts and outputs one package name per line.

Bash Integration

Bash uses a similar but slightly different approach:
Bash completions
Key differences from zsh:
  • Uses COMP_WORDS array instead of zsh’s $words
  • Uses compgen for completion generation
  • Registers with the complete builtin instead of zsh’s completion system

Using pm cd

Once shell integration is active, you can navigate your workspace:

Without Shell Integration

If you haven’t activated shell integration, pm cd still works but only prints the path:
You can use this with command substitution:
Or use the -p / --path flag explicitly:

Troubleshooting

Symptoms: Running pm cd @myapp/web prints the path but doesn’t navigate.Diagnosis:
  1. Check if the shell wrapper is loaded:
    Should show: pm is a shell function (not pm is /path/to/pm)
  2. Verify activation line is in your shell config:
Solution:
  • Add eval "$(pm activate zsh)" to your ~/.zshrc (or bash equivalent)
  • Reload: source ~/.zshrc
Symptoms: Typing pm cd <TAB> doesn’t show your workspace packages.Diagnosis:
  1. Test completions directly:
    Should list all workspace package names.
  2. Check if you’re in a monorepo:
    Should list your packages. If not, you may not be in a workspace.
Solution:
  • Ensure you have workspace configuration (see Monorepo Setup)
  • Reload shell after adding activation line
  • For zsh, ensure compinit runs after the activation line
Symptoms: The shell wrapper interferes with other tools named pm.Solution: You can selectively disable the wrapper for specific commands:
Or rename the Better PM binary during installation if conflicts are severe.
Symptoms: Tab completion for pm cd takes several seconds.Cause: The CLI is being invoked synchronously to generate completions.Mitigation:
  • Install via Homebrew (recommended): Uses native binary, completions resolve in ~60ms
  • If using npm install: Completions invoke Node.js which is slower
  • Large monorepos (100+ packages) may still see slight delays
Note: This is listed in README as a known trade-off of the npm installation method.

Advanced Usage

Multiple Shells

If you use both zsh and bash, add activation to both config files:
~/.zshrc
~/.bashrc
The pm activate command outputs shell-specific code, so each shell gets the correct syntax.

Custom Prompts

The shell wrapper doesn’t interfere with prompt customization. You can still use tools like:
  • Starship
  • Oh My Zsh themes
  • Powerline
  • Custom PS1/PROMPT variables
Just ensure the activation line comes before prompt setup in your config.

Integration with Directory Jumpers

Better PM works alongside tools like:
  • z / zoxide - Frecency-based jumping
  • autojump - Smart directory navigation
  • j - Jump to recent directories
Example workflow:

Scripting with pm cd

In scripts, use the --path flag to avoid shell wrapper complications:
Script example
This works even without shell integration activated.

Performance Considerations

The shell wrapper adds minimal overhead:
  • Function check: ~0.1ms (checks if command is cd)
  • CLI invocation: 60ms (Homebrew) or 200-500ms (npm install)
  • Directory change: <1ms
Optimization tip: Use Homebrew installation for fastest performance:
The Homebrew version installs a native binary compiled from the Effect CLI framework, while npm installation runs through Node.js.

Source Code Reference

The shell integration is implemented in /src/commands/activate.ts (lines 6-66):
  • shellWrapper (lines 6-22): The bash/zsh function that intercepts pm cd
  • zshCompletions (lines 24-34): Zsh-specific completion enhancement
  • bashCompletions (lines 36-44): Bash-specific completion enhancement
  • activateCmd (lines 57-66): Command that outputs the combined activation code
The pm cd --completions flag is handled in /src/commands/cd.ts (lines 31-36).