plugins/working-in-monorepos/skills/working-in-monorepos/SKILL.md
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
npx skillsauth add technicalpickles/pickled-claude-plugins working-in-monoreposInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Helps 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" }
}
}
tools
--- name: writing-for-scannability description: Use when structuring prose so readers can skim it - drafting or restructuring READMEs, docs, PR or issue bodies, design docs, RFCs, or any long-form text where a wall of prose hides the structure. Also use when explicitly asked to make something scannable or skimmable, convert prose to a list, surface a buried list, fix a wall of text, or decide whether bullets or prose fit. Strong signal: text with parallel sentence shapes, contrast markers ("that
development
Ignore actually-lsp nudges for an ecosystem in this project. Use when the user wants to silence, dismiss, or ignore the LSP setup nudges for a specific ecosystem (Rust, TypeScript, Ruby), or invokes `/actually-lsp-ignore` directly. Writes `dismissed=true` to `.claude/actually-lsp.json`. Persistent across sessions for this project only.
tools
Diagnose and fix LSP setup for the current project's detected ecosystems (Rust, TypeScript, Ruby). Use when the SessionStart hook nudged about a missing LSP plugin, when the env isn't ready (no `bundle install`, no `cargo build`, missing server binary), when LSP calls are failing, or when the user invokes `/actually-lsp-doctor` directly. Walks the per-ecosystem state machine, reports what's missing, then runs the fix.
tools
--- name: investigating-runs description: Use whenever the user mentions a GitHub Actions / GHA run, even casually — invoke this skill before reaching for raw `gh` commands, because the bundled `gha-snapshot` helper distills `gh run view --log-failed` (a firehose) into a readable block with per-job status, failed-step log tails, and annotations. Specific triggers (any one is enough): a `github.com/.../actions/runs/...` URL; the phrase "GitHub Actions" or "GHA"; the `gh run` CLI; a failing workfl