From e2462592447a7699e1205ef9be14f74636bf294b Mon Sep 17 00:00:00 2001 From: Phil Haack Date: Thu, 23 Jul 2026 16:38:05 -0700 Subject: [PATCH 1/3] feat(skills): support disable-model-invocation skill frontmatter Parse the disable-model-invocation frontmatter field into SkillInfo, preserve it through manifest saves (previously editing a skill silently stripped it), emit it from serializeSkillMarkdown, and surface it in the skills UI as a badge plus an edit toggle. Generated-By: PostHog Code Task-Id: b9824961-d68a-4ac2-b272-7053ecc0e497 --- packages/shared/src/skills.ts | 13 ++++- packages/ui/src/features/skills/SkillCard.tsx | 7 +++ .../src/features/skills/SkillDetailPanel.tsx | 9 ++++ .../features/skills/SkillManifestEditor.tsx | 30 +++++++++++- .../skills/parse-skill-frontmatter.test.ts | 40 +++++++++++++++- .../skills/parse-skill-frontmatter.ts | 20 ++++++-- .../src/services/skills/schemas.ts | 4 ++ .../src/services/skills/skill-discovery.ts | 5 +- .../src/services/skills/skills.test.ts | 47 +++++++++++++++++++ .../src/services/skills/skills.ts | 13 ++++- .../skills/write-skill-frontmatter.test.ts | 32 ++++++++++++- 11 files changed, 208 insertions(+), 12 deletions(-) diff --git a/packages/shared/src/skills.ts b/packages/shared/src/skills.ts index 540b92eba5..08be3205ae 100644 --- a/packages/shared/src/skills.ts +++ b/packages/shared/src/skills.ts @@ -11,6 +11,12 @@ export interface SkillInfo { editable: boolean; /** Size of SKILL.md in bytes (context-cost signal). */ skillMdBytes: number; + /** + * Frontmatter `disable-model-invocation: true`: the agent never invokes the + * skill on its own — only an explicit user invocation (slash command or + * composer skill tag) runs it. + */ + disableModelInvocation?: boolean; } export interface SkillFileEntry { @@ -44,13 +50,18 @@ export interface ExportedSkill { * sandbox, so it must not drift between hosts. */ export function serializeSkillMarkdown( - meta: { name: string; description: string }, + meta: { + name: string; + description: string; + disableModelInvocation?: boolean; + }, body: string, ): string { const frontmatter = [ "---", `name: ${serializeSkillScalar(meta.name)}`, `description: ${serializeSkillScalar(meta.description)}`, + ...(meta.disableModelInvocation ? ["disable-model-invocation: true"] : []), "---", ].join("\n"); diff --git a/packages/ui/src/features/skills/SkillCard.tsx b/packages/ui/src/features/skills/SkillCard.tsx index 5f896404a9..f3cd49f79f 100644 --- a/packages/ui/src/features/skills/SkillCard.tsx +++ b/packages/ui/src/features/skills/SkillCard.tsx @@ -92,6 +92,13 @@ export function SkillCard({ {skill.repoName} )} + {skill.disableModelInvocation && ( + + + Manual + + + )} } /> diff --git a/packages/ui/src/features/skills/SkillDetailPanel.tsx b/packages/ui/src/features/skills/SkillDetailPanel.tsx index 6be4fd58e3..0011942ee8 100644 --- a/packages/ui/src/features/skills/SkillDetailPanel.tsx +++ b/packages/ui/src/features/skills/SkillDetailPanel.tsx @@ -3,6 +3,7 @@ import { DownloadSimple, FilePlus, Folder, + HandTap, LockSimple, PencilSimple, Trash, @@ -287,6 +288,14 @@ export function SkillDetailPanel({ Read-only )} + {skill.disableModelInvocation && ( + + + + Manual-only + + + )} {skill.source === "codex" && (