You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Skillware currently uses three different notions of "skill identity" that can disagree:
Filesystem / loader path — skills/<category>/<skill_name>/ and SkillLoader.load_skill("category/skill_name")
CLI registry ID — derived from folder path in skillware list, not from manifest fields
LLM tool name — taken directly from manifest["name"] in all provider adapters
Today manifest.name is sometimes the full registry ID (compliance/tos_evaluator), sometimes a short slug (wallet_screening, pdf_form_filler). There is no loader validation tying manifest fields to folder path or to each other.
This RFC asks: what should the canonical skill identity model be? Should contributors set a composite name, separate category + skill_name fields reconstructed by the loader, or should the folder path be the only source of truth?
Goal: pick one model that scales as new categories and skills are added indefinitely, without maintaining a hardcoded category list.
Motivation
Problems today
Symptom
Example
Manifest name ≠ registry path
finance/wallet_screening on disk, name: wallet_screening in manifest
CLI ID ≠ tool name
skillware list shows finance/wallet_screening; Gemini tool may be wallet_screening
Docs teach conflicting shapes
CONTRIBUTING example uses name: generic_hello; live skills use category/skill_name
Provider adapters behave differently
Gemini/Claude use raw manifest["name"]; OpenAI/DeepSeek sanitize / → _
Registry will keep growing with new categories and skill names — any design that relies on a fixed category enum or manual string concatenation in manifests will keep drifting.
Manifest may still have description, parameters, etc., but not authoritative ID fields.
Pros
Cons
Strongest guarantee: path ≡ identity
Manifest alone is incomplete (bad for copy-paste snippets)
Zero contributor ID errors in manifest
External tools that read YAML without loader see no ID
New categories/skills "just work" from folder layout
Harder to validate manifest before placing in tree
Matches how loading already works
Bigger conceptual shift for contributors
Hybrid C1: Path is canonical; loader injects registry_id into returned bundle; manifest name removed or ignored with warning.
Option D — Three fields: category, skill_name, and separate name (display)
Model: Machine ID from category + skill_name; human-facing name or title for UI/catalog only.
Pros
Cons
Clean separation of machine ID vs display label
Overlaps with description, card.json, catalog markdown
Good for pretty UIs
Third field to maintain
Most skills already use card.json for presentation
Note: Display naming may not belong in manifest at all — card.json and docs/skills/*.md may be sufficient. This RFC should decide whether a third field adds value or noise.
Option E — Status quo (do nothing)
Keep current mixed model; only improve documentation.
Any option should document registry ID vs provider tool name explicitly in docs/usage/agent_loops.md.
No hardcoded category list
All options must support arbitrary new skills/<new_category>/<new_skill>/ without updating a central enum. Category tables in CONTRIBUTING remain illustrative examples only, not validation rules.
Validation surface
Regardless of chosen option, consider CI checks (future issue):
Folder path consistent with declared identity
SkillLoader.load_skill(registry_id) succeeds
test_skill.py asserts identity via loader bundle, not hand-copied strings
#12 focuses on library mapping and simplified import. This RFC should decide what the ID string is before #12 implements import aliases or shorthand (load_skill("wallet_screening") vs full path).
Proposed decision process
Discuss options A–E in this issue (maintainers + contributors).
Pick one option (or B2/C1 hybrid) and record the decision in a short ADR or CONTRIBUTING section.
Follow-up implementation issues (separate from this RFC):
Any option except E requires migration, test updates, and doc churn across 8 skills and all usage guides.
External consumers may already depend on raw manifest["name"] in YAML (short slugs).
Deriving identity in the loader (B/C) adds framework complexity for a problem that only affects 2 legacy skills today if we only migrate + validate (Option A).
RFC discussion may delay simple doc fixes — but shipping doc fixes before deciding the model risks documenting the wrong contract twice.
Option C (path-only) makes manifest-only workflows (browsing YAML in isolation) less self-describing.
Cost of not deciding
Every new skill PR becomes a review debate about name format.
AI agents copying templates continue to produce inconsistent manifests.
Provider integration docs stay ambiguous about which string to match in tool-call responses.
Summary
Skillware currently uses three different notions of "skill identity" that can disagree:
skills/<category>/<skill_name>/andSkillLoader.load_skill("category/skill_name")skillware list, not from manifest fieldsmanifest["name"]in all provider adaptersToday
manifest.nameis sometimes the full registry ID (compliance/tos_evaluator), sometimes a short slug (wallet_screening,pdf_form_filler). There is no loader validation tying manifest fields to folder path or to each other.This RFC asks: what should the canonical skill identity model be? Should contributors set a composite
name, separatecategory+skill_namefields reconstructed by the loader, or should the folder path be the only source of truth?Goal: pick one model that scales as new categories and skills are added indefinitely, without maintaining a hardcoded category list.
Motivation
Problems today
name≠ registry pathfinance/wallet_screeningon disk,name: wallet_screeningin manifestskillware listshowsfinance/wallet_screening; Gemini tool may bewallet_screeningname: generic_hello; live skills usecategory/skill_namemanifest["name"]; OpenAI/DeepSeek sanitize/→_name: my-awesome-skill,category: utilityWhy now
Detailed Design
Current behavior (baseline)
Loading:
SkillLoader.load_skill("finance/wallet_screening")resolves by folder path under skill roots. Manifest fields are not used for discovery.CLI:
skillware listbuilds ID as{parent_folder}/{skill_folder}— also path-derived.Tool adapters: All
to_*_tool()methods readmanifest.get("name")directly:[START CODE: skillware/core/loader.py — adapter pattern]
Gemini/Claude: name = manifest.get("name", "unknown_tool")
OpenAI/DeepSeek: sanitize slashes in name → underscores
[END CODE]
Optional manifest field:
categoryexists in some skills but is not used by the loader for ID or tool naming.Design options
Option A — Keep composite
manifest.name(document + validate)Model: Contributor sets
name: "<category>/<skill_name>"manually. Optionalcategorymust match the first segment if present.Loader change: On load, assert
manifest["name"] == f"{folder_category}/{folder_skill_name}"(warn or fail).categoryfield is redundant withnameMigration: Update
wallet_screening→finance/wallet_screening,pdf_form_filler→office/pdf_form_filler; update tests and docs.Option B — Separate
category+skill_name; derive ID in loader (recommended candidate)Model: Manifest requires (or strongly conventionizes):
[START CODE: manifest fields — Option B]
category: ""
skill_name: "<skill_name>"
[END CODE]
Loader derives:
[START CODE: derived values]
registry_id = f"{category}/{skill_name}"
tool_name = registry_id # default; see Option B2 for override
[END CODE]
manifest.namebecomes deprecated (computed at load time and injected into bundle) or optional override with validation.skillware listpath modelnameVariant B1 — Strict: Drop
namefrom manifest; always derive. Simplest long-term.Variant B2 — Soft migration: Keep
nameoptional; if present, must equal{category}/{skill_name}; if absent, derive. Allows gradual migration.Option C — Folder path is the only source of truth
Model: No identity fields in manifest (or manifest identity is read-only metadata). On load:
[START CODE: derived from resolved path]
category = path.parent.parent.name
skill_name = path.parent.name
registry_id = f"{category}/{skill_name}"
[END CODE]
Manifest may still have
description,parameters, etc., but not authoritative ID fields.Hybrid C1: Path is canonical; loader injects
registry_idinto returned bundle; manifestnameremoved or ignored with warning.Option D — Three fields:
category,skill_name, and separatename(display)Model: Machine ID from
category+skill_name; human-facingnameortitlefor UI/catalog only.description,card.json, catalog markdowncard.jsonfor presentationNote: Display naming may not belong in manifest at all —
card.jsonanddocs/skills/*.mdmay be sufficient. This RFC should decide whether a third field adds value or noise.Option E — Status quo (do nothing)
Keep current mixed model; only improve documentation.
Cross-cutting concerns (all options)
Provider tool naming
manifest["name"](slashes allowed)finance/wallet_screening→finance_wallet_screening)Any option should document registry ID vs provider tool name explicitly in
docs/usage/agent_loops.md.No hardcoded category list
All options must support arbitrary new
skills/<new_category>/<new_skill>/without updating a central enum. Category tables in CONTRIBUTING remain illustrative examples only, not validation rules.Validation surface
Regardless of chosen option, consider CI checks (future issue):
SkillLoader.load_skill(registry_id)succeedstest_skill.pyasserts identity via loader bundle, not hand-copied stringsRelationship to #12
#12 focuses on library mapping and simplified import. This RFC should decide what the ID string is before #12 implements import aliases or shorthand (
load_skill("wallet_screening")vs full path).Proposed decision process
wallet_screening,pdf_form_filler)templates/python_skill/and CONTRIBUTINGdocs/usage/agent_loops.mdprovider tableOpen questions for commenters
manifest.namebe removed, derived, or kept as optional override?card.jsonenough?tool_namefield for sanitized APIs?[Feat]issue?Drawbacks
Why we might defer or reject change
manifest["name"]in YAML (short slugs).Cost of not deciding
nameformat.