{"record":{"id":"fe5e370b04ba301a","repo":"Hmbown/CodeWhale","slug":"skill-name-exists-in-both-project-and-global-codewhale-roots","errorCode":null,"errorMessage":"skill '{name}' exists in both project and global Codewhale roots; specify --project or --global","messagePattern":"skill '(.+?)' exists in both project and global Codewhale roots; specify --project or --global","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/skills/mutation.rs","lineNumber":509,"sourceCode":"                    && s.source_kind == SkillSourceKind::CompatibleExternal\n            }) {\n                bail!(\n                    \"skill '{name}' exists only in a compatible external root; \\\n                     import it with /skills (refusing to write external harness directories)\"\n                );\n            }\n            bail!(\"skill '{name}' not found in Codewhale-owned project/global roots\");\n        }\n        [only] => {\n            let DigestState::Known(digest) = &only.digest else {\n                bail!(\"skill '{name}' has unknown package digest; refusing mutation\");\n            };\n            Ok(ResolvedOwnedSkill {\n                id: only.id.clone(),\n                digest: digest.clone(),\n            })\n        }\n        _ => bail!(\n            \"skill '{name}' exists in both project and global Codewhale roots; \\\n             specify --project or --global\"\n        ),\n    }\n}\n\nfn find_audited_skill(\n    ctx: &MutationContext<'_>,\n    skill_id: &AuditedSkillId,\n) -> Result<(AuditedSkill, PathBuf)> {\n    let snap = scan_with_configured(\n        ctx.workspace,\n        ctx.home,\n        ctx.configured_skills_dir,\n        SkillAuditMode::Compatible,\n        None,\n    );\n    let skill = snap","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/skills/mutation.rs#L491-L527","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ncmd.args([\"skills\", \"remove\", \"my-skill\"]);\n// after\ncmd.args([\"skills\", \"remove\", \"my-skill\", \"--project\"]);","handlingStrategy":"validation","validationCode":"fn scope_is_unambiguous(catalog: &SkillCatalog, name: &str) -> bool {\n    let canonical = canonicalize_name(name);\n    let hits = catalog.owned_skills().iter()\n        .filter(|s| s.id.canonical_name == canonical).count();\n    hits <= 1\n}","typeGuard":null,"tryCatchPattern":"if !scope_is_unambiguous(&catalog, name) {\n    eprintln!(\"skill exists in both project and global roots; pass --project or --global\");\n} else {\n    mutation::execute(request, &ctx)?;\n}","preventionTips":["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"],"tags":["skills","ambiguity","cli","scoping"],"backgroundTag":"missing-required-flag","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}