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

  1. Rename one of the colliding agents in its definition so the sanitized names differ (e.g. 'CodeReview' vs 'code-review-helper').
  2. Check the source plugin/manifest for duplicate agent definitions and remove the stale one.
  3. If collisions come from merging bundles, scope one set of agents into a different directory or prefix their names.
  4. 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

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


AI-assisted analysis of EveryInc/compound-engineering-plugin@c9c10f8c75 (2026-08-31). Data as JSON: /api/errors/4e53a59584e35415. Report an issue: GitHub.