EveryInc/compound-engineering-plugin · warning
Skipping agent "${agent.name}": sanitized name "${safeName}"
Error message
Skipping agent "${agent.name}": sanitized name "${safeName}" collides with another agent What it means
writeOpenCodeBundle in src/targets/opencode.ts sanitizes each agent's name into a filename via sanitizePathName. If two distinct agent names sanitize to the same filename (e.g. 'Code Review' and 'code_review' both -> 'code-review'), the second is skipped with this warning and its agent file is not written, since one file cannot hold both.
Source
Thrown at src/targets/opencode.ts:138
if (!skillsEscaped) await cleanupRemovedManagedDirectories(openCodePaths.skillsDir, manifest, "skills", currentSkills)
const hadExistingConfig = await pathExists(openCodePaths.configPath)
const backupPath = await backupFile(openCodePaths.configPath)
if (backupPath) {
console.log(`Backed up existing config to ${backupPath}`)
}
const merged = await mergeOpenCodeConfig(openCodePaths.configPath, bundle.config)
await writeJson(openCodePaths.configPath, merged)
if (hadExistingConfig) {
console.log("Merged plugin config into existing opencode.json (user settings preserved)")
}
const seenAgents = new Set<string>()
const preservedAgentNames = new Set<string>()
for (const agent of bundle.agents) {
const safeName = sanitizePathName(agent.name)
if (seenAgents.has(safeName)) {
console.warn(`Skipping agent "${agent.name}": sanitized name "${safeName}" collides with another agent`)
continue
}
seenAgents.add(safeName)
const agentFileName = `${safeName}.md`
if (agentsEscaped) {
preservedAgentNames.add(agentFileName)
continue
}
const targetPath = path.join(openCodePaths.agentsDir, agentFileName)
const preserved = await cleanupCurrentManagedFile(targetPath, manifest, "agents", agentFileName)
if (preserved) {
preservedAgentNames.add(agentFileName)
continue
}
await writeText(targetPath, agent.content + "\n")
}
const preservedCommandNames = new Set<string>()View on GitHub (pinned to c9c10f8c75)
Solutions
- Rename one of the colliding agents in its definition so the sanitized names differ (e.g. 'CodeReview' vs 'code-review-helper').
- Check the source plugin/manifest for duplicate agent definitions and remove the stale one.
- If collisions come from merging bundles, scope one set of agents into a different directory or prefix their names.
- Re-run the install and confirm the warning is gone and both agent files exist.
Example fix
// before: two agents colliding
{ "name": "Code Review" }
{ "name": "code_review" } // both sanitize to code-review
// after
{ "name": "Code Review" }
{ "name": "Code Reviewer" } // distinct sanitized names Defensive patterns
Strategy: validation
Validate before calling
function findSanitizedCollisions(agents: { name: string }[], sanitize: (s: string) => string): string[] {
const seen = new Map<string, string[]>()
for (const a of agents) {
const k = sanitize(a.name)
seen.set(k, [...(seen.get(k) ?? []), a.name])
}
return [...seen.entries()].filter(([, v]) => v.length > 1).map(([k, v]) => `${k}: ${v.join(', ')}`)
}
// run before writing the bundle; empty array means no collisions Prevention
- Give agents names that stay distinct after lowercasing and stripping punctuation/underscores
- Lint plugin definitions for duplicate or near-duplicate agent names before release
- When merging bundles, check for cross-bundle name overlaps first
When it happens
Trigger: A bundle.agents array contains two agents whose names normalize to the same safeName — differing only by case, whitespace, underscores/dashes, or other characters stripped by sanitizePathName. The second occurrence in iteration order triggers the warning and `continue`.
Common situations: Plugin authors defining agents whose names differ only in case or punctuation; merging multiple plugins whose agents share a name; renaming an agent without removing the old definition so both 'OldName' and 'old-name' exist.
Related errors
- Skipping ${targetPath}: existing user-managed symlink (not o
- Skipping ${targetPath}: existing unmanaged file (not overwri
- Warning: existing ${configPath} is not valid JSON. Writing p
AI-assisted analysis of EveryInc/compound-engineering-plugin@c9c10f8c75 (2026-08-31).
Data as JSON: /api/errors/4e53a59584e35415.
Report an issue: GitHub.