Skip to content

[RFC]: Skill identity in manifest.yaml — composite name vs category + skill_name #101

Description

@rosspeili

Summary

Skillware currently uses three different notions of "skill identity" that can disagree:

  1. Filesystem / loader pathskills/<category>/<skill_name>/ and SkillLoader.load_skill("category/skill_name")
  2. CLI registry ID — derived from folder path in skillware list, not from manifest fields
  3. 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 /_
New contributors / AI agents guess wrong Template uses name: my-awesome-skill, category: utility

Why 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 list builds ID as {parent_folder}/{skill_folder} — also path-derived.

Tool adapters: All to_*_tool() methods read manifest.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: category exists 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. Optional category must match the first segment if present.

Loader change: On load, assert manifest["name"] == f"{folder_category}/{folder_skill_name}" (warn or fail).

Pros Cons
Minimal manifest schema change Contributors must compose strings correctly
Matches how most skills already work category field is redundant with name
Tool adapters unchanged Still two fields that can disagree
Easy doc fix after RFC Does not fix legacy short names without migration

Migration: Update wallet_screeningfinance/wallet_screening, pdf_form_filleroffice/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.name becomes deprecated (computed at load time and injected into bundle) or optional override with validation.

Pros Cons
No string-format mistakes in one field Schema + loader change required
New categories work naturally — no central enum Must migrate all 8 skills + template
Single composition point in code Docs, tests, examples all need updates
Can validate both fields against folder path Breaking change if external code reads raw YAML
Aligns mentally with skillware list path model Need deprecation story for name

Variant B1 — Strict: Drop name from manifest; always derive. Simplest long-term.

Variant B2 — Soft migration: Keep name optional; 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.

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.

Pros Cons
Zero engineering cost Drift continues
Agents and contributors keep hitting mismatches
#12 and adapter work stay ambiguous

Cross-cutting concerns (all options)

Provider tool naming

Provider Behavior today
Gemini, Claude Raw manifest["name"] (slashes allowed)
OpenAI, DeepSeek Sanitized (finance/wallet_screeningfinance_wallet_screening)
Ollama Docs reference manifest name; matching is manual

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

Relationship 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

  1. Discuss options A–E in this issue (maintainers + contributors).
  2. Pick one option (or B2/C1 hybrid) and record the decision in a short ADR or CONTRIBUTING section.
  3. Follow-up implementation issues (separate from this RFC):
    • Loader changes + tests
    • Migrate legacy manifests (wallet_screening, pdf_form_filler)
    • Update templates/python_skill/ and CONTRIBUTING
    • Update docs/usage/agent_loops.md provider table
  4. Cancel / replace doc-only Issue 3 — template work happens after RFC merge.

Open questions for commenters

  1. Should manifest.name be removed, derived, or kept as optional override?
  2. Should mismatch between manifest and folder path fail hard or warn during transition?
  3. Is display/title needed in manifest, or is card.json enough?
  4. Should provider tool names always equal registry ID, or allow a separate tool_name field for sanitized APIs?
  5. Does [Feat]: Implement Skill Library Mapping and Simplified Import Mechanism #12 subsume implementation of the chosen option, or should this RFC spawn a dedicated [Feat] issue?

Drawbacks

Why we might defer or reject change

  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    core frameworkChanges to loader, env, or base classes.discussionOpen discussion for RFCs and proposals.help wantedExtra attention is needed
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions