EveryInc/compound-engineering-plugin · error · Error
Could not find ${PLUGIN_MANIFEST} under ${inputPath}
Error message
Could not find ${PLUGIN_MANIFEST} under ${inputPath} What it means
`resolveClaudeRoot()` locates the plugin root from an input path (the root itself, a `.claude-plugin` dir, or a `plugin.json` file). If none of the layouts match — i.e. no `.claude-plugin/plugin.json` manifest can be found under the given path — it throws this error, meaning the input is not a recognizable Claude plugin directory.
Source
Thrown at src/parsers/claude.ts:54
}
}
async function resolveClaudeRoot(inputPath: string): Promise<string> {
const absolute = path.resolve(inputPath)
const manifestAtPath = path.join(absolute, PLUGIN_MANIFEST)
if (await pathExists(manifestAtPath)) {
return absolute
}
if (absolute.endsWith(PLUGIN_MANIFEST)) {
return path.dirname(path.dirname(absolute))
}
if (absolute.endsWith("plugin.json")) {
return path.dirname(path.dirname(absolute))
}
throw new Error(`Could not find ${PLUGIN_MANIFEST} under ${inputPath}`)
}
async function loadAgents(agentsDirs: string[]): Promise<ClaudeAgent[]> {
const files = await collectMarkdownFiles(agentsDirs)
const agents: ClaudeAgent[] = []
for (const file of files) {
const raw = await readText(file)
const { data, body } = parseFrontmatter(raw, file)
const name = (data.name as string) ?? deriveMarkdownStem(file)
agents.push({
name,
description: data.description as string | undefined,
capabilities: data.capabilities as string[] | undefined,
model: data.model as string | undefined,
body: body.trim(),
sourcePath: file,
})View on GitHub (pinned to c9c10f8c75)
Solutions
- Point the input at the plugin root — the directory containing `.claude-plugin/plugin.json`
- Verify the file exists: `ls <path>/.claude-plugin/plugin.json`
- If you intended a plugin.json file path, pass the path to that file directly
- Restore a missing manifest from git or create a valid one
Example fix
// before
await loadClaudePlugin("./skills/ce-plan")
// after: use the plugin root
await loadClaudePlugin("./") Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from "node:fs"
import path from "node:path"
if (!existsSync(path.join(inputPath, ".claude-plugin", "plugin.json"))) {
throw new Error(`${inputPath} is not a Claude plugin root (no .claude-plugin/plugin.json)`)
}
await loadClaudePlugin(inputPath) Type guard
function hasClaudeManifest(p: string): boolean { return existsSync(path.join(p, ".claude-plugin", "plugin.json")) } Try / catch
try {
const plugin = await loadClaudePlugin(inputPath)
} catch (error) {
if (String(error).includes("Could not find")) {
console.error(`${inputPath} is not a Claude plugin root; point at the directory containing .claude-plugin/plugin.json`)
} else throw error
} Prevention
- Pass the plugin root directory, not a subdirectory like skills/ or .claude-plugin's parent's child
- Verify `.claude-plugin/plugin.json` exists before converting
- Restore the manifest if a checkout/merge removed it
When it happens
Trigger: Calling `loadClaudePlugin(inputPath)` (or the `root`/`resolveClaudeRoot` path) with a directory that does not exist, is not a plugin checkout, or lacks `.claude-plugin/plugin.json`; passing a file path other than `plugin.json`; passing the `.claude-plugin` directory of a plugin whose manifest was renamed or removed.
Common situations: Typo in the path or pointing at the repo's `skills/` subdirectory instead of the plugin root; running the converter against a plugin missing its manifest; git sparse/symlink checkout where `.claude-plugin` wasn't materialized.
Related errors
- Cleanup currently supports only the compound-engineering plu
- Invalid ${label}: ${entry}. Paths must stay within the plugi
AI-assisted analysis of EveryInc/compound-engineering-plugin@c9c10f8c75 (2026-08-31).
Data as JSON: /api/errors/5ef18fc8f6125d29.
Report an issue: GitHub.