Hmbown/CodeWhale · error
skill ' ' exists in both project and global Codewhale…
Error message
skill '{name}' exists in both project and global Codewhale roots; specify --project or --global What it means
When a name-based mutation matches more than one owned skill — one in the project root and one in the global root — the library refuses to guess which one to operate on and requires an explicit scope selection (--project or --global, or the scoped request variants).
Solutions
- Re-run the mutation with --project to target the project-root copy
- Or re-run with --global to target the global-root copy
- In code, construct the scoped request variant (project or global) instead of the name-only variant
- Remove one of the duplicate copies to make future unscoped commands unambiguous
Example fix
// before cmd.args(["skills", "remove", "my-skill"]); // after cmd.args(["skills", "remove", "my-skill", "--project"]);
Defensive patterns
Strategy: validation
Validate before calling
fn scope_is_unambiguous(catalog: &SkillCatalog, name: &str) -> bool {
let canonical = canonicalize_name(name);
let hits = catalog.owned_skills().iter()
.filter(|s| s.id.canonical_name == canonical).count();
hits <= 1
} Try / catch
if !scope_is_unambiguous(&catalog, name) {
eprintln!("skill exists in both project and global roots; pass --project or --global");
} else {
mutation::execute(request, &ctx)?;
} Prevention
- Always pass --project or --global in scripts that mutate skills by name
- Avoid keeping the same skill in both roots, or remove duplicates deliberately
- Detect duplicates at install time by checking the other scope first
When it happens
Trigger: execute/execute_sync with an unscoped name-based request (remove/update/trust by name) while the canonical name exists in both the project and the global Codewhale skills roots, so the resolver's match list has more than one entry.
Common situations: A user installed the same skill both per-project and globally (common after promoting a project skill to global) and then runs an unscoped uninstall/update; scripts that omit the scope flag after a global install was added.
Understand the failure class
Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.
Related errors
- model ` ` is available from configured provider route(s): …
- A positive pull request number is required
- account_agent_model_unconfigured
- Account settings import is not available yet; local config…
- Agent session name ' ' is ambiguous; use an agent_id
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/fe5e370b04ba301a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/skills/mutation.rs:509
&& s.source_kind == SkillSourceKind::CompatibleExternal
}) {
bail!(
"skill '{name}' exists only in a compatible external root; \
import it with /skills (refusing to write external harness directories)"
);
}
bail!("skill '{name}' not found in Codewhale-owned project/global roots");
}
[only] => {
let DigestState::Known(digest) = &only.digest else {
bail!("skill '{name}' has unknown package digest; refusing mutation");
};
Ok(ResolvedOwnedSkill {
id: only.id.clone(),
digest: digest.clone(),
})
}
_ => bail!(
"skill '{name}' exists in both project and global Codewhale roots; \
specify --project or --global"
),
}
}
fn find_audited_skill(
ctx: &MutationContext<'_>,
skill_id: &AuditedSkillId,
) -> Result<(AuditedSkill, PathBuf)> {
let snap = scan_with_configured(
ctx.workspace,
ctx.home,
ctx.configured_skills_dir,
SkillAuditMode::Compatible,
None,
);
let skill = snapView on GitHub (pinned to 73e0f67d83)