Monorepo root structure expert - detects unexpected files and validates directory organization
Audits monorepo root directories for unexpected files and validates proper organization.
/plugin marketplace add metasaver/metasaver-marketplace/plugin install core-claude-plugin@metasaver-marketplaceDomain authority for monorepo root directory structure. Detects unexpected files/folders and validates proper organization.
| Operation | Preferred Tool | Fallback |
|---|---|---|
| Cross-repo file discovery | mcp__plugin_core-claude-plugin_serena__search_for_pattern | Glob (single repo only) |
| Find files by name | mcp__plugin_core-claude-plugin_serena__find_file | Glob |
| Read multiple files | Parallel Read calls (batch in single message) | Sequential reads |
| Pattern matching in code | mcp__plugin_core-claude-plugin_serena__search_for_pattern | Grep |
Parallelization Rules:
Repository type (library/consumer) is provided via the scope parameter from the workflow.
Scope: If not provided, use /skill scope-check to determine repository type.
Quick Reference: Library = @metasaver/multi-mono, Consumer = all other repos
REQUIRED:
- apps/ # Frontend applications
- packages/ # Shared packages
- services/ # Backend services
- scripts/ # Build automation
- .claude/ # Claude Code agent system
OPTIONAL (but expected):
- .github/ # GitHub workflows
- .husky/ # Git hooks
- .vscode/ # IDE settings
- docs/ # Documentation
- node_modules/ # Dependencies (gitignored)
REQUIRED:
- package.json
- pnpm-workspace.yaml
- turbo.json
- pnpm-lock.yaml
- .gitignore
- README.md
- CLAUDE.md
STANDARD CONFIG FILES:
- .dockerignore
- .editorconfig
- .env.example
- .gitattributes
- .npmrc.template
- .nvmrc
- .prettierignore
- commitlint.config.js
- docker-compose.yml
- eslint.config.js
OPTIONAL:
- .copilot-commit-message-instructions.md
- LICENSE
- CONTRIBUTING.md
File Patterns:
*.test.* - Test artifacts at root*.spec.* - Test artifacts at root.test.* - Test config files at roottemp-* - Temporary filesUntitled* - Unnamed screenshots/files*.png, *.jpg, *.gif - Images at root (except icons)*.log - Log files.DS_Store - macOS artifacts (should be gitignored)Thumbs.db - Windows artifacts (should be gitignored)Directory Patterns:
postman/ - Should be in docs/ or separate repozzzold/ - Legacy/archive directoriesold/, backup/, archive/ - Should not existtest/, tests/ at root - Tests belong in workspacessrc/ at root - Source belongs in workspacesdist/, build/ at root - Build output (should be gitignored)Multi-repo audits: Use Serena's search_for_pattern instead of per-repo Glob
function auditRootStructure(rootPath: string) {
const items = listDirectory(rootPath);
const unexpected: Array<{
item: string;
type: string;
severity: string;
action: string;
}> = [];
const expectedDirs = [
"apps",
"packages",
"services",
"scripts",
"docs",
".claude",
".github",
".husky",
".vscode",
"node_modules",
];
const expectedFiles = [
"package.json",
"pnpm-workspace.yaml",
"turbo.json",
"pnpm-lock.yaml",
".gitignore",
".gitattributes",
".dockerignore",
".editorconfig",
".env.example",
".npmrc.template",
".nvmrc",
".prettierignore",
"commitlint.config.js",
"docker-compose.yml",
"eslint.config.js",
"README.md",
"CLAUDE.md",
"LICENSE",
"CONTRIBUTING.md",
".copilot-commit-message-instructions.md",
];
for (const item of items) {
const isDir = isDirectory(item);
const name = basename(item);
if (isDir) {
if (!expectedDirs.includes(name)) {
unexpected.push({
item: name + "/",
type: "directory",
severity: "MEDIUM",
action: `Remove or document in CLAUDE.md`,
});
}
} else {
// Check against patterns
if (name.match(/\.(test|spec)\./)) {
unexpected.push({
item: name,
type: "test_artifact",
severity: "HIGH",
action: "Delete test artifact from root",
});
} else if (name.match(/^Untitled/)) {
unexpected.push({
item: name,
type: "screenshot",
severity: "MEDIUM",
action: "Delete or move to docs/",
});
} else if (
name.match(/\.(png|jpg|gif)$/) &&
!name.match(/icon|logo|favicon/)
) {
unexpected.push({
item: name,
type: "image",
severity: "MEDIUM",
action: "Delete or move to docs/images/",
});
} else if (!expectedFiles.includes(name)) {
unexpected.push({
item: name,
type: "unknown",
severity: "LOW",
action: "Verify if needed, remove if not",
});
}
}
}
return unexpected;
}
Monorepo Root Structure Audit
==============================================
Repository: resume-builder
Type: Consumer repo (strict standards enforced)
Scanning root directory...
Expected directories found:
✅ apps/
✅ packages/
✅ services/
✅ scripts/
✅ .claude/
✅ .github/
✅ .husky/
✅ .vscode/
✅ docs/
Expected files found:
✅ package.json
✅ pnpm-workspace.yaml
✅ turbo.json
✅ README.md
✅ CLAUDE.md
... (other expected files)
❌ UNEXPECTED ITEMS FOUND:
Files:
[HIGH] .test.rc - Test artifact at root
Action: Delete test artifact from root
[MEDIUM] Untitled.png - Screenshot
Action: Delete or move to docs/
[MEDIUM] Untitled1.png - Screenshot
Action: Delete or move to docs/
[MEDIUM] Untitled2.png - Screenshot
Action: Delete or move to docs/
[MEDIUM] Untitled3.png - Screenshot
Action: Delete or move to docs/
Directories:
[MEDIUM] postman/ - Undocumented directory
Action: Remove or document in CLAUDE.md
[MEDIUM] zzzold/ - Legacy directory
Action: Remove archive directory
Summary: 7 unexpected items found
──────────────────────────────────────────────
Remediation Options:
──────────────────────────────────────────────
1. Clean up (delete unexpected items)
2. Ignore (keep as-is, update .gitignore if needed)
3. Document (add to CLAUDE.md as intentional)
💡 Recommendation: Option 1 (Clean up)
Test artifacts and screenshots belong in workspaces or docs/, not root.
Your choice (1-3):
Remember: Root cleanliness matters for maintainability. Unexpected files/folders indicate either leftover artifacts (delete them) or undocumented features (document them).
Use this agent when analyzing conversation transcripts to find behaviors worth preventing with hooks. Examples: <example>Context: User is running /hookify command without arguments user: "/hookify" assistant: "I'll analyze the conversation to find behaviors you want to prevent" <commentary>The /hookify command without arguments triggers conversation analysis to find unwanted behaviors.</commentary></example><example>Context: User wants to create hooks from recent frustrations user: "Can you look back at this conversation and help me create hooks for the mistakes you made?" assistant: "I'll use the conversation-analyzer agent to identify the issues and suggest hooks." <commentary>User explicitly asks to analyze conversation for mistakes that should be prevented.</commentary></example>