Use when working in repositories with multiple subprojects (monorepos) where commands need to run from specific directories - prevents directory confusion, redundant cd commands, and ensures commands execute from correct locations
/plugin marketplace add technicalpickles/pickled-claude-plugins/plugin install working-in-monorepos@technicalpickles-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
README.mdexamples/schemaflow.jsonexamples/zenpayroll.jsonscripts/monorepo-inittests/baseline-results.mdtests/baseline-scenarios.mdHelps Claude work effectively in monorepo environments by ensuring commands always execute from the correct location using absolute paths.
Core principle: Bash shell state is not guaranteed between commands. Always use absolute paths.
Announce at start: "I'm using the working-in-monorepos skill."
Use this skill when:
Don't use for:
When executing ANY command in a monorepo subproject:
✅ CORRECT:
cd /Users/josh/workspace/schemaflow/ruby && bundle exec rspec
cd /Users/josh/workspace/schemaflow/cli && npm test
❌ WRONG:
# Relative paths (assumes current directory)
cd ruby && bundle exec rspec
# No cd prefix (assumes location)
bundle exec rspec
# Chaining cd (compounds errors)
cd ruby && cd ruby && rspec
Why: You cannot rely on shell state. Absolute paths guarantee correct execution location regardless of where the shell currently is.
If .monorepo.json exists at repo root:
root field for absolute repo pathpath from subprojects mapcd {root}/{path} && commandExample:
{
"root": "/Users/josh/workspace/schemaflow",
"subprojects": { "ruby": { "path": "ruby" } }
}
→ cd /Users/josh/workspace/schemaflow/ruby && bundle exec rspec
Use git to find repo root, then construct absolute path:
git rev-parse --show-toplevelcd /absolute/path/to/repo/ruby && bundle exec rspecExample workflow:
# Step 1: Get repo root
git rev-parse --show-toplevel
# Output: /Users/josh/workspace/schemaflow
# Step 2: Use absolute path in commands
cd /Users/josh/workspace/schemaflow/ruby && bundle exec rspec
Why not use command substitution: cd $(git rev-parse --show-toplevel)/ruby requires user approval. Instead, run git rev-parse once, then use the absolute path directly in all subsequent commands.
⚠️ Git subtree caveat: In repositories containing git subtrees (nested git repos), git rev-parse --show-toplevel returns the innermost repo root, not the monorepo root. This makes it unreliable for subtree scenarios. Creating a .monorepo.json config is the robust solution that works in all cases.
When working in a repo without .monorepo.json:
git rev-parse --show-toplevel/Users/josh/workspace/schemaflowcd /Users/josh/workspace/schemaflow/subproject && commandDo NOT use command substitution like cd $(git rev-parse --show-toplevel)/subproject - this requires user approval every time. Get the path once, then use it directly.
Important limitation: git rev-parse --show-toplevel may not work correctly in repositories with git subtrees (nested git repos), as it returns the innermost repository root. For subtree scenarios, a .monorepo.json config is strongly recommended to explicitly define the true monorepo root.
When skill activates in a repo without .monorepo.json:
~/.claude/skills/working-in-monorepos/scripts/monorepo-init --dry-run, show output, ask for approval, then ~/.claude/skills/working-in-monorepos/scripts/monorepo-init --writeHelper Script Philosophy:
The monorepo-init script is designed as a black-box tool:
--help first to see usageScript Location:
The script is located at ~/.claude/skills/working-in-monorepos/scripts/monorepo-init (absolute path). Since skills are symlinked from the dotfiles repo via home/.claude/skills/ → ~/.claude/skills/, this path works universally regardless of which project directory you're currently in.
# Run from any directory - use the absolute path
~/.claude/skills/working-in-monorepos/scripts/monorepo-init --help
~/.claude/skills/working-in-monorepos/scripts/monorepo-init --dry-run
~/.claude/skills/working-in-monorepos/scripts/monorepo-init --write
If .monorepo.json defines command rules:
{
"commands": {
"rubocop": { "location": "root" },
"rspec": {
"location": "subproject",
"command": "bundle exec rspec",
"overrides": { "root": { "command": "bin/rspec" } }
}
}
}
Check rules before executing:
commands maplocation: "root" | "subproject"command overrideoverridesExample:
bundle exec rspecbin/rspec❌ "I just used cd, so I'm in the right directory" Reality: You cannot track shell state reliably. Always use absolute paths.
❌ "The shell remembers where I am" Reality: Shell state is not guaranteed between commands. Always use absolute paths.
❌ "It's wasteful to cd every time" Reality: Explicitness prevents bugs. Always use absolute paths.
❌ "Relative paths are simpler" Reality: They break when assumptions are wrong. Always use absolute paths.
| Task | Command Pattern |
|---|---|
| Get repo root | git rev-parse --show-toplevel (run once, use result in all commands) |
| Run tests in subproject | cd /absolute/path/to/repo/subproject && test-command |
| With config | cd {root}/{subproject.path} && command |
| Check for config | test -f .monorepo.json |
| Generate config | ~/.claude/skills/working-in-monorepos/scripts/monorepo-init --dry-run (works from any directory) |
| Always rule | Use absolute path + cd prefix for EVERY command. Get repo root first, then use absolute paths directly. |
.monorepo.json at repository root:
{
"root": "/absolute/path/to/repo",
"subprojects": {
"subproject-id": {
"path": "relative/path",
"type": "ruby|node|go|python|rust|java",
"description": "Optional"
}
},
"commands": {
"command-name": {
"location": "root|subproject",
"command": "optional override",
"overrides": {
"context": { "command": "context-specific" }
}
}
}
}
Minimal example:
{
"root": "/Users/josh/workspace/schemaflow",
"subprojects": {
"ruby": { "path": "ruby", "type": "ruby" },
"cli": { "path": "cli", "type": "node" }
}
}