> ## Documentation Index
> Fetch the complete documentation index at: https://better-pm.fdarian.com/llms.txt
> Use this file to discover all available pages before exploring further.

# pm cd

> Navigate to workspace packages

## Overview

The `pm cd` command helps you navigate to workspace packages in your monorepo. When combined with shell integration, it allows you to quickly jump between packages from anywhere in your project.

<Warning>
  Shell integration via `pm activate` is required for the actual directory change functionality. Without it, `pm cd` only prints the path.
</Warning>

## Syntax

```bash theme={null}
pm cd [package-name] [options]
```

## Arguments

<ParamField path="package-name" type="string">
  The name of the workspace package to navigate to. If omitted, returns to monorepo root.
</ParamField>

## Options

<ParamField path="-p, --path" type="boolean" default="false">
  Print the absolute path without navigation
</ParamField>

<ParamField path="--completions" type="boolean" default="false">
  Output package names for shell completion (internal use)
</ParamField>

## Examples

### Navigate to Package

```bash theme={null}
pm cd @myapp/web
```

```bash Output theme={null}
# With shell integration: changes to the package directory
# Without shell integration: prints the path
/path/to/monorepo/apps/web
```

### Return to Root

```bash theme={null}
pm cd
```

```bash Output theme={null}
# Changes to (or prints) the monorepo root directory
/path/to/monorepo
```

### Get Package Path

```bash theme={null}
pm cd @myapp/api --path
```

```bash Output theme={null}
/path/to/monorepo/services/api
```

### Use in Scripts

```bash theme={null}
# Store path for later use
PKG_PATH=$(pm cd @myapp/web --path)
echo "Package is at: $PKG_PATH"
```

## Shell Integration

To enable actual directory changes, activate shell integration:

<CodeGroup>
  ```bash zsh theme={null}
  # Add to ~/.zshrc
  eval "$(pm activate zsh)"
  ```

  ```bash bash theme={null}
  # Add to ~/.bashrc
  eval "$(pm activate bash)"
  ```
</CodeGroup>

This installs a wrapper function that:

1. Calls `pm cd` to get the directory path
2. Uses the shell's `cd` builtin to actually change directories
3. Provides tab completion for package names

From `src/commands/activate.ts:6-22`:

```bash theme={null}
pm() {
  if [ "$1" = "cd" ]; then
    shift;
    for arg in "$@"; do
      case "$arg" in
        -*) command pm cd "$@"; return;;
      esac;
    done;
    local dir;
    dir=$(command pm cd "$@");
    if [ $? -eq 0 ] && [ -d "$dir" ]; then
      builtin cd "$dir";
    fi;
  else
    command pm "$@";
  fi;
};
```

## Shell Completion

With shell integration, tab completion works automatically:

```bash theme={null}
pm cd <TAB>
# Shows all workspace package names
@myapp/api    @myapp/core    @myapp/web    @myapp/utils

pm cd @myapp/<TAB>
# Completes package names
```

## Error Handling

If a package doesn't exist, you'll see an error with available packages:

```bash theme={null}
pm cd @myapp/nonexistent
```

```bash Output theme={null}
Error: Package "@myapp/nonexistent" not found

Available packages:
├── packages/
│   ├── core "@myapp/core"
│   └── utils "@myapp/utils"
└── apps/
    └── web "@myapp/web"
```

## How It Works

From `src/commands/cd.ts:38-55`:

```typescript theme={null}
if (Option.isNone(args.packageName)) {
  yield* Console.log(pm.lockDir);
  return;
}

const packageName = args.packageName.value;
const pkg = packages.find((p) => p.name === packageName);

if (!pkg) {
  return yield* Effect.fail(
    new PackageNotFoundError(
      packageName,
      formatWorkspaceTree(packages, path.sep),
    ),
  );
}

yield* Console.log(path.resolve(pm.lockDir, pkg.relDir));
```

The command:

1. Lists all workspace packages
2. Finds the package by name
3. Resolves the absolute path
4. Prints the path (shell wrapper handles the actual cd)

## Related Commands

* [pm pls](/commands/pls) - List all workspace packages
* [pm activate](/commands/activate) - Set up shell integration
