{"record":{"id":"a7f22aa8bedd482a","repo":"Hmbown/CodeWhale","slug":"only-codewhale-managed-skills-can-be-removed-mutation","errorCode":null,"errorMessage":"only Codewhale managed skills can be removed","messagePattern":"only Codewhale managed skills can be removed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/skills/mutation.rs","lineNumber":945,"sourceCode":"            safe_target_path: safe_display_path(&path, Some(ctx.workspace), ctx.home),\n            before_digest: before,\n            after_digest: None,\n            outcome: SkillMutationOutcome::NetworkDenied(host),\n        }),\n    }\n}\n\nfn remove_skill(\n    skill_id: AuditedSkillId,\n    expected_digest: Option<String>,\n    ctx: &MutationContext<'_>,\n) -> Result<SkillMutationReceipt> {\n    let (skill, path) = find_audited_skill(ctx, &skill_id)?;\n    if !skill.root.is_writable_owned() {\n        bail!(\"refusing to remove skill outside Codewhale-owned roots\");\n    }\n    if skill.source_kind != SkillSourceKind::CodeWhaleManaged {\n        bail!(\"only Codewhale managed skills can be removed\");\n    }\n    let skills_dir = validate_owned_skill_path(ctx, &skill, &path)?;\n    let before = verify_expected_digest(&path, expected_digest.as_deref())?;\n    let scope = match skill.root.kind {\n        SkillRootKind::CodeWhaleProject => SkillScope::Project,\n        SkillRootKind::CodeWhaleGlobal => SkillScope::Global,\n        _ => SkillScope::Logical,\n    };\n    let package_name = on_disk_package_name(&skill_id)?;\n    validate_owned_skill_path(ctx, &skill, &path)?;\n    install::uninstall(package_name, &skills_dir)?;\n    Ok(SkillMutationReceipt {\n        action: SkillActionKind::Remove,\n        name: skill_id.canonical_name,\n        scope,\n        safe_target_path: safe_display_path(&path, Some(ctx.workspace), ctx.home),\n        before_digest: before,\n        after_digest: None,","sourceCodeStart":927,"sourceCodeEnd":963,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/skills/mutation.rs#L927-L963","documentation":"remove_skill() only removes skills whose source_kind is SkillSourceKind::CodeWhaleManaged. The library deliberately refuses to delete skills it did not create (user-authored, imported, or external skills), even if they sit under a writable root, to avoid destroying assets outside its management contract. The check runs after resolving the audited skill and confirming its root is writable-owned.","triggerScenarios":"Calling remove_skill (or remove_and_trust_require_managed_owned / remove_managed_skill / remove_uses_on_disk_dir_not_canonical_name via execute_sync) with a skill_id that resolves to a skill whose source_kind is not CodeWhaleManaged — e.g. a user-authored or imported skill.","commonSituations":"Developers try to programmatically clean up a directory of mixed skills and hit a skill that was hand-created on disk rather than installed through Codewhale; or a skill was created by an older tool version that marked source_kind differently.","solutions":["Only call remove_skill on skills created/installed by Codewhale itself; check skill.source_kind == SkillSourceKind::CodeWhaleManaged first","If the skill is user-authored, delete it manually from its skill directory instead of through this API","Reinstall the skill through a Codewhale-managed flow so it is marked CodeWhaleManaged, then remove it","If the skill should be managed but is not, fix its source metadata/registration rather than forcing removal"],"exampleFix":"// before\nctx.remove_skill(skill_id, digest)?; // panics on user-authored skill\n// after\nif skill.source_kind == SkillSourceKind::CodeWhaleManaged {\n    ctx.remove_skill(skill_id, digest)?;\n} else {\n    std::fs::remove_dir_all(&skill.path)?; // manual removal for non-managed skills\n}","handlingStrategy":"validation","validationCode":"fn is_managed(skill: &Skill) -> bool { skill.source_kind == SkillSourceKind::CodeWhaleManaged }","typeGuard":"fn is_managed_skill(s: &Skill) -> bool { matches!(s.source_kind, SkillSourceKind::CodeWhaleManaged) }","tryCatchPattern":null,"preventionTips":["Filter skill listings to CodeWhaleManaged before offering remove actions","Handle non-managed skills with a separate manual-deletion flow","Log source_kind when removal fails to speed diagnosis"],"tags":["rust","skills","validation","permissions"],"backgroundTag":"unsupported-operation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}