Hur jag gör en Skill portabel mellan Claude, ChatGPT och Gemini
När flera stora AI-verktyg började stödja Skills blev den naturliga frågan för mig inte “vilket format vinner?”, utan: hur mycket av ett bra workflow kan jag göra modell- och leverantörsoberoende utan att låtsas att plattformarna är identiska?
När flera stora AI-verktyg började stödja Skills blev den naturliga frågan för mig inte “vilket format vinner?”, utan: hur mycket av ett bra workflow kan jag göra modell- och leverantörsoberoende utan att låtsas att plattformarna är identiska?
Det är lätt att gå åt två fel håll. Det ena är att skriva tre helt separata Skills och få tre divergerande sanningar. Det andra är att försöka skapa en universell SKILL.md som ignorerar skillnader i verktyg, installation, metadata och runtime. Jag vill i stället ha en portabel kärna med tunna adapters.
Det gemensamma är större än man först tror
Claude, ChatGPT och Gemini har nu alla koncept för återanvändbara on-demand-workflows. Anthropic beskriver Skills som mappar med instruktioner, scripts och resurser. OpenAI beskriver Skills som återanvändbara workflows med instruktioner, exempel och kod. Gemini CLI beskriver Agent Skills som självständiga kataloger med specialiserad expertis, procedurer och resurser.
Det ger en gemensam abstraktion:
Det betyder inte att zip-filen alltid kan kopieras rakt mellan systemen. Men det betyder att domänlogiken kan designas portabelt.
Jag delar Skillen i core och adapter
Min favoritstruktur är ungefär:
Core-filerna beskriver arbetet. Adapter-entrypointen beskriver hur just den plattformen ska ladda och exekvera det.
Om workflowet säger:
ska den logiken vara densamma oavsett om det är Claude, ChatGPT eller Gemini som exekverar. Skillnader i hur filer hittas eller scripts körs ligger i adapterlagret.
Portabilitet börjar med ett leverantörsoberoende output contract
Om outputen är “skriv ett bra svar” blir varje implementation plattformsspecifik. Om outputen däremot har ett tydligt kontrakt blir det lättare att testa samma beteende över flera modeller.
Även när slutleveransen är Markdown kan mellanartefakter följa samma schema. Då kan jag köra samma eval-set mot flera runtimes.
Det här är särskilt viktigt för agentsystem. En downstream-komponent ska inte behöva veta vilken leverantör som producerade handoffen.
Frontmatter är en adapterfråga
Metadatafälten och deras exakta regler kan skilja sig över tid. Därför vill jag inte låta hela core-workflowet bero på ett specifikt frontmatter-schema.
Adapter-filen kan exempelvis innehålla plattformens aktuella name och description, medan core bara beskriver:
Vid build/package-tid kan man sedan mappa detta till rätt format. Det gör också migrering enklare om en leverantör ändrar metadataregler.
Tool capability måste deklareras explicit
Portabilitet faller ofta på verktyg. En Skill kan anta:
- filesystem,
- shell,
- Python,
- web access,
- connectors,
- browser,
- code execution.
Om core-workflowet i praktiken kräver shell men adapter B saknar shell är Skillen inte portabel bara för att instruktionerna går att läsa.
Jag lägger därför till en capability manifest:
Sedan kan varje adapter säga hur capabilityn uppfylls eller att ett visst mode inte stöds.
Separera logik från tool syntax
Core ska helst säga:
Hämta den aktuella primärkällan och lagra URL + retrieval timestamp.
Inte:
Kör exakt verktyg
foo_search_querymed parameter X.
Tool syntax hör hemma i adapter eller runtime-instruktion. Annars blir varje ändring i verktygsnamn en ändring i domänlogiken. Det här är samma mönster som i vanlig software architecture: business logic ska inte vara hårdkopplad till transportlagret.
Scripts är ofta den mest portabla delen
Ironiskt nog kan ett litet Python-script vara mer portabelt än en stor prompt, förutsatt att runtime har Python.
Om jag exempelvis har:
som läser en JSON-fil och validerar required fields är beteendet identiskt oavsett vilken modell som skapade filen. Därför försöker jag flytta kritisk determinism till scripts där det går.
Portabiliteten blir då:
Det minskar skillnaderna mellan modeller utan att låtsas att deras resonemang är identiskt.
Evals är den verkliga portabilitetstesten
Att tre plattformar kan läsa Skillen betyder nästan ingenting. Frågan är om de klarar samma testfall.
Jag använder därför samma eval-set:
Sedan kör jag:
Jag jämför inte ordval. Jag jämför kontrakt:
- stoppade de på samma hard-fail?
- bevarade de fakta?
- laddade de rätt referens?
- producerade de required fields?
- försökte någon modell improvisera förbi en blocker?
Det är där verklig portabilitet syns.
Jag undviker leverantörsspecifika personlighetsregler i core
En annan sak jag försöker hålla utanför core är modellkompensation som “Claude gör ofta X, så säg alltid Y”. Sådana regler åldras snabbt.
Om en viss modellversion har en stabil svaghet kan adapterlagret innehålla en temporär kompensation. Men core ska uttrycka det önskade beteendet i sig. Det gör att Skillen kan överleva modelluppgraderingar bättre.
Skill, project context och agent är inte samma sak överallt
Plattformarna har olika närliggande koncept. Claude Code har exempelvis CLAUDE.md, Skills och subagents. Gemini CLI skiljer mellan GEMINI.md som persistent context och Skills som on-demand expertise. ChatGPT har Skills men även andra arbetsytor och app-/connectorbegrepp.
Jag försöker därför portera capabilityn, inte filnamnens semantik.
Frågan är:
Sedan mappar varje adapter svaren till plattformens mekanismer.
Source policy bör vara helt gemensam
Källhierarkier, säkerhetsregler och fidelity-regler är ofta perfekta core-komponenter.
Exempel:
Det finns ingen anledning att ha tre varianter av den policyn. Om de divergerar är det ett governance-problem.
Versionera core och adapters separat
Jag skulle inte sätta ett enda versionsnummer på allt.
En metadataförändring i Gemini ska inte tvinga core till ny minor version. En ändring i evidence policy ska däremot bumpa core och testas i alla adapters. Det här gör release notes mycket mer begripliga.
Bygg en compatibility matrix
För Skills som verkligen ska leva på flera plattformar vill jag ha en enkel matris:
| Capability | Claude | ChatGPT | Gemini CLI |
|---|---|---|---|
| On-demand skill loading | Ja | Ja | Ja |
| Filesystem-based local skill | Ja, Claude Code | beror på surface | Ja, CLI |
| Scripts/code resources | Ja | Ja i stödda surfaces | Ja |
| Project-local context | CLAUDE.md | surface-specific | GEMINI.md |
| Isolated subagents | Claude Code | runtime-dependent | runtime-dependent |
Tabellen speglar läget vid tidpunkten då jag skrev den här artikeln och är en färskvara: feature-stödet hos Claude, ChatGPT och Gemini CLI ändras, så matrisen ska uppdateras mot aktuell officiell dokumentation innan man litar på den. Det är exakt den typen av faktum som inte bör hårdkodas i core för alltid.
Packaging bör vara en build step
Om samma source tree ska leverera tre Skill-paket skulle jag skapa ett litet build-script:
Scriptet:
- kopierar core resources,
- lägger på rätt adapter-entrypoint,
- tar bort unsupported assets,
- kör target-specifik validator,
- kör gemensamma eval fixtures,
- paketerar artefakten.
Då är inte “portabilitet” ett manuellt copy-paste-projekt.
Säkerhet måste också testas per runtime
Samma Skill kan ha olika blast radius beroende på vilka verktyg användaren har kopplat in. En read-only research-skill i en miljö kan få skrivaccess i en annan om adapterlagret är slarvigt.
Jag kräver därför en target-specifik permission review:
Core säger principen om least privilege. Adaptern implementerar den.
Vad jag inte försöker standardisera
Jag accepterar att vissa saker ska skilja sig:
- modellval,
- tool syntax,
- package/install-flöde,
- UI metadata,
- debugging-kommandon,
- vissa capability constraints.
Att försöka abstrahera bort allt skapar ofta ett eget mini-framework som är mer komplicerat än tre små adapters.
Min regel är: standardisera domänbeteende och testbar output, inte hela runtime.
Min portabilitetsmodell
I praktiken ser den ut så här:
När core ändras kör jag regressioner på alla targets. När en adapter ändras behöver jag bara verifiera att den fortfarande uppfyller samma core-contract.
Den viktigaste lärdomen
En portabel Skill är inte en fil som råkar gå att öppna i tre verktyg. Det är ett leverantörsoberoende arbetskontrakt som har verifierats i tre runtimes.
Det är den abstraktionen jag tror är värd att investera i. Modeller, tool names och installationsflöden kommer att ändras. Ett bra evidence policy, ett tydligt output contract, bra evals och korrekt stop behavior har betydligt längre livslängd.
En konkret core-spec
Om jag bygger en portabel article-fact-checker kan core se ut så här:
Claude-adaptern kan säga var Skillen ska ligga i filsystemet. ChatGPT-adaptern kan paketera samma resources enligt dess Skill-surface. Gemini-adaptern kan ange workspace/user-scope och CLI-installation. Men invariants ändras inte.
Hur jag hanterar en capability som bara finns i en target
Säg att en runtime kan spawn:a isolerade subagents och en annan inte kan det. Jag bygger inte in “subagent” i corekravet. Core säger:
Claude-adaptern kan implementera det med subagent. En annan runtime kan implementera det genom separata körningar och serialiserade artifacts. Samma mål, olika mekanism. Det är den nivå av abstraktion jag vill åt.
Fallbacks ska vara deklarerade, inte improviserade
Om web access saknas kan adaptermanifestet säga:
Inte “använd modellens kunskap i stället”. Det är en kritisk skillnad. Portabilitet får inte innebära att säkerhetsnivån sjunker på en svagare runtime.
Gemensamma evals, target-specifika evals
Jag delar testbiblioteket i två delar:
Core-evals måste passera överallt. Target-evals bevisar att adaptern använder plattformen korrekt. Då vet jag om ett fel ligger i domänlogiken eller integrationen.
Hur jag skulle migrera en Claude-first Skill
Om Skillen redan finns för Claude börjar jag med att extrahera allt som egentligen är leverantörsoberoende: regler, source policy, output schema, evals och scripts. Sedan lämnar jag bara Claude-specifik routing och runtimeinformation i Claude-adaptern.
Därefter bygger jag ChatGPT- och Gemini-adapters mot samma core. Jag kopierar alltså inte Claude-mappen två gånger och redigerar. Copy-paste skapar tre forks. Extraction skapar en produkt med tre distributionsytor.
Det finns en gräns för portabilitet
Vissa Skills är genuint bundna till ett ekosystem. En Skill som handlar om Claude Codes hook-system eller en ChatGPT-specifik connectorfunktion bör få vara target-specific. Jag försöker inte göra den universell bara för arkitektonisk elegans.
Portabilitet är mest värdefull när domänkunskapen är dyr: legal review, research policy, financial analysis, content QA, translation standards. Där vill jag inte skriva om kärnlogiken varje gång en ny modell eller surface blir relevant.
Localization av själva Skillen är separat från portabilitet. En Skill kan vara portabel mellan runtimes men ändå behöva olika språk. Jag försöker hålla machine-facing contracts på ett stabilt språk och lokalisera user-facing text separat. Annars kan en svensk adapter råka byta statusnamn eller schemafält och därmed göra outputen mindre portabel. Domänspråk för användaren och protokollspråk mellan komponenter är två olika designfrågor.
Observability över targets. När samma capability körs i flera runtimes vill jag kunna jämföra latency, tokenkostnad, blocker-rate och eval failures. Inte för att utse en universell vinnare, utan för att se vilken target som passar vilken uppgift. Om Gemini exempelvis är billigare för en viss extraction men Claude klarar evidence-conflict bättre kan model/router-lagret utnyttja det. Portabiliteten skapar då valfrihet i drift, inte bara backup.
Secrets och connectors får aldrig ligga i core. Core-resurser ska inte innehålla API-nycklar, mailboxadresser eller target-specifika connector-id:n. Adaptern eller deploymentmiljön injicerar sådant via säkra konfigurationsmekanismer. Det gör core lättare att dela och minskar risken att en Skill-zip råkar bära credentials till en annan runtime.
Distribution till team. När en Skill ska användas av fler än mig själv behöver jag även en distributionspolicy. Vilken version är godkänd? Vem kan uppdatera core? Hur testas en ny adapter? Kan användare installera en egen modifierad kopia? Plattformarna har olika organisationsfunktioner, men governancefrågorna är desamma. Jag vill kunna peka på en source repository/tag och säga “det här är den version vi kör”.
När jag skulle välja att inte porta. Om en capability bygger direkt på en target-specifik feature och inte har dyr domänlogik skulle jag inte abstrahera. En Claude Code Skill som bara automatiserar ett Claude-specifikt debugflöde kan få vara Claude-only. Portabilitet har en kostnad i adapters, CI och dokumentation. Jag betalar den kostnaden när den skyddar värdefull metodik eller ger verklig routingfrihet — inte för att allt ska se framework-agnostic ut på ett arkitekturdiagram.
Hur jag undviker lowest-common-denominator-design
Portabilitet får inte göra Skillen sämre på alla plattformar. Core definierar minimumkontraktet, men en adapter får gärna använda target-specifika styrkor så länge outputen fortfarande följer samma interface. Claude-adaptern kan använda isolerade subagents. En CLI-runtime kan använda lokala scripts effektivt. En annan surface kan ha bättre connectorer. Det viktiga är att extra capability inte ändrar sanningsreglerna eller gör handoffen inkompatibel.
Feature flags för target-funktioner. När capability skiljer sig mycket använder jag feature flags i adaptern:
Workflowet kan då välja en stödd väg i stället för att upptäcka begränsningen mitt i körningen. Samma manifest är också användbart i CI och dokumentation.
Hur en router kan utnyttja portabla Skills. När flera runtimes klarar samma core-contract kan routing ske på uppgiftens egenskaper: kostnad, latens, context size, verktygsbehov eller kvalitet på ett eval-set. Då kan en billigare modell köra standardfallen och en starkare target ta konflikter eller komplex research. Portabel metodik gör model routing säkrare eftersom ett byte av modell inte samtidigt betyder ett byte av hela arbetsprocessen.
Det är egentligen där jag ser den största affärsnyttan. Jag vill inte vara låst till en frontiermodell bara för att all metodik råkar ligga inbakad i dess promptformat. Om workflow, evals och contracts är separerade kan modeller konkurrera om exekveringen medan metodiken förblir min.
Vad jag skulle standardisera organisatoriskt. Om flera team bygger portabla Skills skulle jag standardisera core-contract, source policy, versionering och eval-format centralt men låta domänteamen äga själva workflowet. Då kan säkerhets- och distributionsregler vara konsekventa utan att ett centralt AI-team behöver förstå varje affärsprocess. Portabilitet blir då även en governancefördel: samma minimikrav följer med capabilityn oavsett vilken runtime som exekverar den.
Det gör också leverantörsbyten mindre dramatiska: vi byter exekveringslager, inte hela den metodik som verksamheten har byggt upp. Det är den ekonomiska poängen med portabel AI-infrastruktur.
Samtidigt behåller jag möjligheten att utnyttja en leverantörs unika styrkor. Portabilitet betyder alltså inte identiska implementationer; det betyder gemensamma kontrakt, jämförbara evals och samma kvalitetsgolv.
Källor
- Anthropic — Agent Skills
- OpenAI — Skills in ChatGPT
- OpenAI Academy — Using skills
- Gemini CLI — Agent Skills
Hur jag skulle testa adapters i CI
Jag vill att en ändring i core automatiskt kör samma fixtures mot alla targets. Det behöver inte börja med full end-to-end automation. Redan en statisk validator kan kontrollera att required core-filer finns, att target-entrypointen refererar till rätt resurser och att inget unsupported tool nämns.
Sedan kan ett runtime-test köra ett litet golden set och skriva normaliserade resultat:
Det är mycket mer användbart än att manuellt läsa tre snygga outputs och säga att Skillen “verkar portabel”.
Portabilitet betyder också portabel failure
Jag vill särskilt testa att plattformarna misslyckas på samma säkra sätt. Om source ledger saknas ska alla tre blockera. Om användaren ber om fabricerad first-hand experience ska alla tre vägra lägga till den. Om ett script inte kan köras ska adaptern rapportera capability failure, inte ersätta valideringen med en gissning. Samma failure semantics är minst lika viktiga som samma happy path.
Min produktionschecklista för A015
Den fullständiga checklistan jag kör innan en metod som den här får kallas produktionsklar beskriver jag i checklistan för att gå från research paper till fungerande AI-Skill — den gäller på samma sätt här, för portabilitet mellan Claude, ChatGPT och Gemini.