Skip to content

RFC-0008 and RFC-0009: Skill Registry and Harness Integration#10

Closed
jwm4 wants to merge 3 commits into
mlflow:mainfrom
jwm4:add-skill-registry-rfc
Closed

RFC-0008 and RFC-0009: Skill Registry and Harness Integration#10
jwm4 wants to merge 3 commits into
mlflow:mainfrom
jwm4:add-skill-registry-rfc

Conversation

@jwm4

@jwm4 jwm4 commented Apr 23, 2026

Copy link
Copy Markdown

Summary

Two companion RFCs for adding a governed Skill Registry to MLflow:

RFC-0008 (Skill Registry): A metadata-first registry for AI agent capabilities (skills, subagents, hooks). Stores metadata and typed source pointers (Git, OCI, ZIP, MLflow artifacts). Provides lifecycle management, usage analytics via MLflow traces (mlflow.skill_context()), and federated discovery. Skill bundles group related capabilities into versioned units that map to agent harness plugins, with cross-registry references to MCP servers (RFC-0004).

RFC-0009 (Harness Integration): Adds mlflow skills install to generate harness-specific manifests and place files in the correct directories. Adapters for Claude Code, Codex CLI, and Cursor. Bundle import for onboarding existing plugins into the registry. Trace instrumentation via install-time manifests and harness hooks.

Related Issues

This PR is from Bill Murdock with assistance from Claude Code.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds RFC-0005 proposing a new governed, metadata-first Skill Registry for MLflow, including versioning, lifecycle/publish-state governance, typed source pointers (Git/OCI/ZIP), and first-class skill groups.

Changes:

  • Introduces the Skill Registry conceptual model (skills, skill versions, tags, aliases) and publish-state lifecycle.
  • Defines skill groups with versioned membership snapshots, plus associated tags/aliases.
  • Specifies proposed DB schema (12 tables) and API surfaces (REST, Python SDK, CLI, UI).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
published skills, not the process of writing them.
- **Skill format specification.** The registry is format-agnostic. It
does not define or enforce what a skill looks like (SKILL.md, plugin
manifests, etc.).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we consider MLflow artifact storage as a first-class source type here? That would give us a natural UI upload flow and keeps the door open for more MLflow-native packaging/optimization later, even if Git and OCI stay the main paths.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. We've added mlflow as an explicit future source type in the "Source type extensibility" section — it would allow storing skill content directly in MLflow artifact storage, providing a natural UI upload flow. It's deferred from the initial implementation to keep the registry metadata-first, but can be added as a follow-up without breaking changes. The adoption strategy's "Follow-up" section also calls this out.

This comment was posted by Claude Code under the supervision of Bill Murdock.

Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
RETIRED = "retired"


class SkillSourceType(StrEnum):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we line this lifecycle up more closely with the MCP registry RFC in PR 12 (#12)? Right now this introduces draft, published, deprecated, and retired plus a separate skill-level status, which makes the cross-registry pattern feel less consistent unless there’s a strong skill-specific reason to diverge.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fully aligned — replaced the 4-state publish lifecycle (draft/published/deprecated/retired) with RFC-0004's 3-state model using status (active/deprecated/deleted). SkillStatus is now the only lifecycle enum. Parent entity status (Skill.status, SkillGroup.status) is derived from the latest version rather than set independently.

This comment was posted by Claude Code under the supervision of Bill Murdock.

does not perform scans. Scanning tools are separate.
- **Agent harness integration.** How a specific agent harness (Claude
Code, Codex, Cursor, etc.) installs or loads skills from the registry
is outside this RFC. The registry provides the metadata; harness

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want one short paragraph on external skill conventions we expect to interoperate with? Even if the registry stays format-agnostic, it would help to say whether we’re aligning with existing Claude/Cursor/GitHub-style skill packaging or deliberately avoiding standardization for now.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — fully aligned with RFC-0004. Version lifecycle now uses status with three states (active, deprecated, deleted), matching MCPStatus. New versions default to active. Skill.status and SkillGroup.status are now read-only, derived from the latest version's status. Also added latest_version_alias on both Skill and SkillGroup, following RFC-0004's pattern for deterministic "latest" resolution. Store interface switched from AbstractSkillRegistryStore with @abstractmethod to SkillRegistryMixin with raise NotImplementedError, matching MCPServerRegistryMixin.

(Comment from Claude Code under the supervision of Bill Murdock.)

Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
#### SkillVersion

A versioned record containing a typed source pointer, publish state,
and tags.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially expected aliases to live on SkillVersion, but after checking MLflow model registry, the existing pattern is that aliases are owned by the top-level entity and point to a version. If the goal is consistency with MLflow and PR 12 (#12), I think this design is fine. It may just be worth making that pattern more explicit in the text.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aligned — set_skill_alias takes (name, alias, version) and sets the alias on the Skill entity, pointing to a specific version. Same pattern for set_skill_group_alias. This matches the MCP RFC's approach where aliases are owned by the parent entity rather than the version.

This comment was posted by Claude Code under the supervision of Bill Murdock.

)
```

## Create a skill group with a versioned membership snapshot

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the justification for skill groups? Why not just using tags on skills

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a "Why groups instead of tags?" section to the RFC. The key reasons: (1) groups pin specific member versions for reproducibility, (2) groups have their own lifecycle and aliases independent of member status, (3) groups can reference capabilities across registries (skill registry + MCP registry), (4) groups map naturally to the "plugin" concept in agent harnesses, and (5) tags are flat key-value pairs that can't express ordered, versioned membership.

This comment was posted by Claude Code under the supervision of Bill Murdock.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick terminology update: "skill groups" have been renamed to "skill bundles" in the latest revision, and the section is now titled "Why bundles instead of tags?" The reasoning in my earlier reply still applies, just with the updated name.

This comment was posted by Bill Murdock with assistance from Claude Code.

trace data back to a governed skill record to understand adoption
across an organization.

### Use cases

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add explicit JTBDs per persona (developer, admin etc.)? It would make it easier to evaluate which parts of the data model are required

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — replaced the abstract use case bullets with three end-to-end persona flows: a platform administrator (registers, scans, groups, aliases, deprecates), a developer (searches, resolves alias, pulls), and a security engineer (queries scan tags, deprecates failed versions, tracks compliance). These ground the data model in concrete user workflows.

This comment was posted by Claude Code under the supervision of Bill Murdock.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The persona flows have been updated in the latest revision to reflect the new entity model. "Skill groups" are now "skill bundles," and the platform administrator scenario now references subagents explicitly (e.g., bundling a code-review skill with a security-auditor subagent and a GitHub MCP server). The three personas and their workflows are otherwise unchanged.

This comment was posted by Bill Murdock with assistance from Claude Code.

Comment thread rfcs/0005-skill-registry/0005-skill-registry.md Outdated
@jwm4

jwm4 commented Apr 27, 2026

Copy link
Copy Markdown
Author

Update: Review Feedback Round 1

Pushed changes addressing the straightforward review feedback: YAML frontmatter, mermaid ER diagram, field renames (source_urlsource, content_hashcontent_digest), type consistency fixes, simplified SkillGroupVersionMembership, corrected examples/filter docs, fixed delete semantics, and editorial trimming throughout.

Still open

Structural:

  • Whether source_type should be part of the version primary key, or if versions should be (name, version) with sources underneath (plus dependent items: last_registered_version ambiguity, get_latest_skill_version semantics)
  • Lifecycle alignment with the MCP registry RFC (PR Add RFC 0004: MCP Registry #12): publish states, latest_version_alias pattern, alias ownership text
  • Skill groups vs. tags
  • Security scan tracking: free-form tags vs. structured metadata

Scope:

  • MLflow artifact storage as a source type
  • Install/pull story
  • Publish-state permission boundaries
  • External skill format conventions paragraph

Content:

  • Merge "Use cases" with "The problem" or add explicit JTBDs per persona

(Comment from Claude Code under the supervision of Bill Murdock.)

@jwm4

jwm4 commented Apr 27, 2026

Copy link
Copy Markdown
Author

Status update (2026-04-27)

Changes since last update

RFC-0005 (Skill Registry):

  • source_type removed from version PK. Version uniqueness is now (name, version). source_type and source are optional fields on SkillVersion. Cascaded through entities, DB schema, store interface, REST API paths, all examples, and CLI. (Addresses mprahl's comment about source_type in the version identity.)
  • pull added to RFC-0005. mlflow skills pull provides harness-agnostic content fetching from registered sources. Pull semantics section covers single-skill and group-level pull, source resolution, and content integrity verification.
  • Expanded scope to four capability kinds. The registry now tracks skills (SKILL.md), agents (agent .md), MCP servers (JSON config), and hooks (harness-specific) under the mlflow skills namespace. Added SkillKind enum and kind field to the Skill entity.
  • Group-level source support. SkillGroupVersion can optionally have its own source_type, source, and content_digest for monolithic distribution (e.g., a single OCI image containing a complete plugin).
  • Source optionality. source on SkillVersion is optional — members sourced exclusively via a group-level artifact don't need individual sources.

RFC-0006 (Skill Registry Harness Integration) — new:

  • Companion RFC covering mlflow skills install for harness-specific manifest generation and file placement.
  • Defines HarnessAdapter interface with concrete adapters for Claude Code, Codex CLI, Cursor, and Antigravity.
  • Covers marketplace.json generation for marketplace-aware harnesses.
  • Includes cross-harness landscape table covering 13 agent harnesses.

Resolved review comments (newly replied)

Still open

  • Align lifecycle with MCP registry RFC PR Add RFC 0004: MCP Registry #12
  • Security scans as structured metadata vs. tags
  • JTBDs per persona (serena-ruan)
  • Skill groups justification — why not just tags? (serena-ruan)
  • MLflow artifact storage as a source type
  • External skill conventions paragraph
  • Publish-state permission boundary
  • latest_version_alias pattern from MCP RFC
  • Alias ownership pattern — make explicit in text
  • Merge use cases with problem section / make more concrete

(Comment from Claude Code under the supervision of Bill Murdock.)

@jwm4 jwm4 changed the title RFC-0005: Skill Registry RFC-0005 and RFC-0006: Skill Registry and Harness Integration Apr 27, 2026
@jwm4
jwm4 marked this pull request as draft April 28, 2026 18:50
@jwm4

jwm4 commented Apr 28, 2026

Copy link
Copy Markdown
Author

Also, I've converted this to draft given all the open issues listed above.

@jwm4

jwm4 commented Apr 29, 2026

Copy link
Copy Markdown
Author

Status update (2026-04-29)

Changes since last update

RFC-0005 (Skill Registry):

  • Lifecycle aligned with MCP RFC (PR Add RFC 0004: MCP Registry #12). Replaced 4-state publish lifecycle (draft/published/deprecated/retired) with RFC-0004's 3-state status (active/deprecated/deleted). Parent entity status is now derived from the latest version, not set independently.
  • latest_version_alias added. Both Skill and SkillGroup support latest_version_alias, matching the MCP RFC pattern. Resolution logic: alias if set, otherwise most recent creation_timestamp.
  • Cross-registry membership. SkillGroupVersionMembership can now reference either the skill registry or the MCP registry (RFC-0004) via a registry field discriminator. Uses application-layer enforcement rather than conditional database FKs.
  • Dual MCP guidance. Added guidance that the MCP registry is the default home for MCP servers; kind=mcp-server in the skill registry is reserved for embedded configs bundled with a skill group.
  • SDK namespace. Moved from mlflow.skills.* to mlflow.genai.skills.* for consistency with sibling registries (Prompt Registry, MCP Registry).
  • Pull clarified as client-side. Removed pull from the store mixin and REST API. mlflow skills pull is a client-side operation that reads the source pointer from the registry and fetches locally.
  • MLflow artifact storage. Added mlflow as an explicit future source type in the extensibility section, deferred from initial implementation.
  • Store interface aligned. Changed from AbstractSkillRegistryStore with @abstractmethod to SkillRegistryMixin with raise NotImplementedError, matching the MCP RFC pattern.

RFC-0006 (Harness Integration):

  • Marketplace expanded. Moved from Alternatives into Detailed Design with full endpoint spec, response format, configuration, and limitations.
  • Store/SDK namespace aligned with RFC-0005 changes.

Still open (deferred to future pass)

  • Merge "Use cases" with "The problem" or add end-to-end user flows
  • Security scans: structured metadata vs. tags
  • Publish-state (now status) permission boundaries
  • JTBDs per persona (serena-ruan)

(Comment from Claude Code under the supervision of Bill Murdock.)

@jwm4

jwm4 commented Apr 29, 2026

Copy link
Copy Markdown
Author

Status update (2026-04-29, part 2)

The four items listed as "still open" in the previous update are now all addressed:

  • Use cases restructured as end-to-end persona flows (platform admin, developer, security engineer) instead of abstract bullets
  • Security scan tracking expanded with a structured scan.{type}.{field} tag namespace convention, documented fields, examples, and UI rendering guidance
  • Status permission boundaries defined via a new Permissions section mapping operations to MLflow's READ/EDIT/MANAGE levels (status transitions and alias management require MANAGE)
  • JTBDs per persona addressed by the persona-based use cases above

All review comments from mprahl, serena-ruan, and Copilot now have replies. I don't have further edits planned at this time. The RFC is ready for another round of review.

(Comment from Claude Code under the supervision of Bill Murdock.)

rfc_pr: https://github.com/mlflow/rfcs/pull/10
---

# RFC: Skill Registry

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Bill Murdock — Reading through the RFC and the proposed API, one thing struck me: given that the registry already supports kind=[skill, agent, mcp-server, hook], should we consider a more generic name than "skills" / "skill groups"?

The data model is already kind-agnostic — a Skill entity with kind=agent is conceptually an asset that happens to be an agent, not a skill. Calling the registry an Asset Registry (or Capability Registry) and using create_asset() / create_asset_group() instead of create_skill() / create_skill_group() would better reflect what the API actually does and avoid the naming tension where "skill" is both a specific kind and the umbrella term for all kinds.

The REST paths and CLI would follow naturally: mlflow assets create, mlflow asset-groups create-version, etc.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

I'd like to also propose bundles. It satisfies the generic 'kind-agnostic' semantics of assets, while also implying plurality even in the singular term (skill-group and bundle both imply grouping of some asset).

I also agree that having an independent name (assets/bundles/capabilities) greatly improves function discoverability in the SDK

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, if none of the names appeal, I'd suggest at least in the CLI dropping skill-groups in favor of skills with a --group flag. Something like:

mlflow skills pull --group pr-workflow --alias production

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to @etirelli here, the umbrella term should not be a skill. Currently in the RFC the skill that is a kind/skill is more consistent with the industry's usage of the term, but the top level usage of the word skill would be very confusing.

My preference is asset registry or capability registry, or something equally broader.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after further discussion last week, +1 to using the term bundle or skill bundle as per @khaledsulayman 's suggestion above.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved. Rather than renaming the umbrella term, we split the single Skill(kind=...) entity into three separate types: Skill, Subagent, and Hook. Each has full lifecycle (versions, aliases, tags, status). SkillGroup is renamed to SkillBundle with typed member lists, following the "skill bundle" suggestion from this thread. The registry is still "Skill Registry" and the SDK namespace stays mlflow.genai.skills.*. See commit d16abe0.

Bill Murdock, with assistance from Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopted. SkillGroup is now SkillBundle throughout both RFCs. See commit d16abe0 for the full restructuring.

This comment was posted by Bill Murdock with assistance from Claude Code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopted a variant of this: the CLI now uses --bundle instead of --group, following the SkillGroup-to-SkillBundle rename. So mlflow skills pull --bundle pr-workflow --alias production.

This comment was posted by Bill Murdock with assistance from Claude Code.

Add a Skill Registry to MLflow: a governed, metadata-first registry for
AI agent capabilities. The registry stores metadata and typed source
pointers (to Git repos, OCI registries, ZIP archives, etc.) rather
than artifacts directly. It provides enterprise governance on top of

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we support both approaches? The user would either set pointers to external storage (Git, OCI, ZIP) or store assets directly in MLflow's internal artifact store.

The reason: source pointers are the right default for customers who already manage assets in Git or other systems. But for customers who don't have that infrastructure in place, or who already use MLflow to store models and want their agent capabilities alongside them, or who operate in airgapped or restricted environments where reaching external sources isn't practical — the ability to store assets directly in the registry would be a better fit.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The latest revision adds source_type="mlflow" as a first-class source type in the initial implementation. Content is stored as a directory tree of individual files in MLflow's artifact store, consistent with how model artifacts are stored. Users can choose external source pointers (Git, OCI, ZIP) or direct artifact storage depending on their environment. This covers the airgapped and "capabilities alongside models" use cases you described.

-- This comment was posted by Claude Code under the supervision of Bill Murdock.


### Out of scope

- **Artifact storage.** The registry stores metadata and source

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given that mlflow already has an "artifact store" to store models and traces, I think the proposal could just embrace it and support it as an option, as per my previous comment.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the same change. See reply to your earlier comment.

-- This comment was posted by Claude Code under the supervision of Bill Murdock.

permissions.
- **Alias management requires MANAGE.** Aliases like `production`
control which version downstream consumers resolve to. Changing an
alias has the same blast radius as a status transition.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the impact and blast radius of alias management, should alias changes be auditable?

Currently, last_updated_by / last_updated_timestamp on the parent Skill captures that something changed, but doesn't record alias-specific history (which alias, what it pointed to before, who changed it, when). For enterprise governance scenarios — "who promoted this to production and when?" or "what was production pointing to yesterday before the incident?" — an alias change log would be valuable.

This could be as lightweight as an append-only skill_alias_history table (alias, old_version, new_version, changed_by, timestamp), or even just emitting an event that external audit systems can consume. Worth considering for the initial design, since retrofitting audit onto alias mutations is harder than including it upfront.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added. Every alias mutation (set or delete) now appends a record to an append-only history table with the alias name, old version, new version, who changed it, and when. This covers "who promoted this to production?" and "what was production pointing to before the incident?" queries.

The design includes:

  • SkillAliasHistory and SkillGroupAliasHistory entities
  • skill_alias_history and skill_group_alias_history database tables (append-only, no updates or deletes through the API)
  • get_skill_alias_history() and get_skill_group_alias_history() store methods
  • REST endpoints at /{name}/aliases/history and /{name}/aliases/{alias}/history

History is recorded automatically by the store on every alias mutation. No separate API call needed.

-- This comment was posted by Claude Code under the supervision of Bill Murdock.

cross-registry concern that applies equally to skills, MCP servers,
and other AI asset registries. It is expected to be solved at the
platform level across all MLflow registries rather than piecemeal in
each one.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cross-workspace visibility can be managed at the infrastructure level (e.g., Kubernetes RBAC in OpenShift AI), so deferring that is reasonable. However, the RFC should consider supporting export/import of assets between workspaces — or at minimum, a move/duplicate operation. Use case: a platform team develops and tests assets in a staging workspace or even on a staging instance, then promotes them to a production workspace or instance. Without export/import, they'd need to re-register everything manually, including versions, tags, aliases, and group memberships. Even a simple mlflow skills export --name code-review --output bundle.json / mlflow skills import --input bundle.json --workspace production would cover this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use case. We'd like to follow the other MLflow registries on this. Neither the model registry nor the MCP registry (RFC-0004) has export/import yet, and we want to stay consistent rather than designing a serialization format in isolation. If export/import lands as a cross-registry capability in MLflow, the skill registry should adopt the same approach.

Added a mention in the adoption strategy's follow-up section. The data model is fully serializable, so this can be built on top of the existing API without schema changes.

-- This comment was posted by Claude Code under the supervision of Bill Murdock.

@jwm4

jwm4 commented Apr 30, 2026

Copy link
Copy Markdown
Author

Status update (2026-04-30)

Changes since last update

RFC-0005 (Skill Registry):

  • MLflow artifact storage promoted to first-class. source_type="mlflow" is now part of the initial implementation, not a deferred follow-up. Content is stored as a directory tree of individual files in MLflow's artifact store, consistent with how model artifacts are stored. Serves users without external Git/OCI infrastructure, airgapped environments, and those wanting capabilities alongside models.
  • Alias audit trail added. Every alias mutation (set or delete) appends to an append-only history table recording the alias, old version, new version, who changed it, and when. Supports governance queries like "who promoted this to production?" Includes entities, database tables, store methods, and REST endpoints for both skills and skill groups.
  • Cross-workspace export/import noted as an explicit follow-up item. We want to follow whatever pattern the other MLflow registries adopt rather than designing a serialization format in isolation.
  • Use cases rewritten as end-to-end persona flows (platform admin, developer, security engineer).
  • Security scan tracking expanded with a structured scan.{type}.{field} tag namespace convention.
  • Permissions section added mapping operations to MLflow's READ/EDIT/MANAGE levels.

RFC-0006 (Harness Integration):

  • Minor update: source-agnostic language in examples.

Open discussion

  • Naming/scope: Whether the registry should use a more generic name than "skills" given it supports kind=[skill, agent, mcp-server, hook]. This depends on whether MLflow should have a single unified registry for all AI asset types or separate registries per asset type. Under the current plan (separate registries), "skills" is the natural name since it aligns with the ecosystem term (SKILL.md). Under a unified registry, a more generic name would be appropriate. We welcome input on this question.

All review comments from mprahl, serena-ruan, Copilot, and etirelli now have replies (except the naming question, which is under active discussion).

(Comment from Claude Code under the supervision of Bill Murdock.)

Comment on lines +453 to +456
class SkillStatus(StrEnum):
ACTIVE = "active"
DEPRECATED = "deprecated"
DELETED = "deleted"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We added back a fourth DRAFT status in the mcp registry proposal fyi. If feedback on it is positive, might be useful here too?
bef24e7

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added. The RFC now uses a 4-state lifecycle (draft, active, deprecated, deleted) aligned with the MCP Registry RFC. New versions default to draft, and activation requires MANAGE permission. See the updated status table and transitions in the latest push.

(This comment is from Claude Code under the supervision of Bill Murdock.)

schema changes since the column stores a string value. `kind` is
immutable after creation.

**MCP servers: two registration paths.** The MCP server registry

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need both paths? I can see the benefit when embedded as part of an artifact, but wanted to double check if we can provide a cleaner path like a way for an embedded mcp to be automatically registered. Sorry if this was already discussed!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. The two paths serve different ownership models:

MCP Registry (RFC-0004) is for standalone MCP servers that have their own lifecycle, versioning, and deployment bindings. Skill groups reference these via registry="mcp" in their membership. This is the recommended path for most MCP servers.

kind=mcp-server in this registry is for MCP configs that are embedded in a group-level artifact (e.g., an .mcp.json inside an OCI image containing a complete plugin bundle). These configs exist only as part of their containing artifact and do not have an independent lifecycle.

Auto-registering embedded configs into the MCP registry would create governance confusion: the embedded config's lifecycle is tied to its containing group version, but an MCP registry entry has its own independent lifecycle. If someone deprecates the group version, the auto-registered MCP entry would still appear active in the MCP registry. Keeping them separate avoids that mismatch.

In practice, we expect most MCP servers to use the MCP registry path. The kind=mcp-server path is a narrow escape hatch for bundled artifacts where separating the config from its plugin would be artificial.

(This comment is from Claude Code under the supervision of Bill Murdock.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: the kind=mcp-server path described in the previous reply has been removed. MCP servers are now handled in two ways, both cleaner than before:

  1. Standalone MCP servers are registered in the MCP registry (RFC-0004) and referenced via the mcp_servers list on SkillBundleVersion.
  2. Embedded MCP configs (e.g., .mcp.json inside a bundle-level OCI artifact) are just part of the artifact. They do not need separate registry entries or membership references.

See commit d16abe0.

Bill Murdock, with assistance from Claude Code


```python
@dataclass
class SkillGroup:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it make sense for skill group to simply be a Skill with kind=group? A skill can already be pointing to any number of things. Could potentially simplify/unify the data model a bit. Just putting it out there as an idea!

@jwm4 jwm4 May 7, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion! We discussed this on Slack and agreed to keep them separate. The main concern is naming clarity: collapsing groups into Skill with kind=group makes the "Skill" name even more confusing, since a skill group already includes not just skills but also sub-agents, hooks, and MCP configurations. People generally don't refer to a group of skills as a single "skill." With a name like "module" the composition would feel natural, but "skill" carries a more atomic connotation.

Keeping them separate also stays consistent with other MLflow registries (the MCP registry has separate server and server group entities) and avoids conditional complexity in the data model (groups have a membership table that individual skills don't need).

(This comment is from Claude Code under the supervision of Bill Murdock.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming clarity and data model complexity arguments make sense to me, but I'm a little confused about the "server group entities" analogy. What exactly does this refer to in the MCP registry rfc?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry, that was an error in the comment that I should have caught! I've crossed it out. My main point was the other one. Thank you for catching this!

@jwm4

jwm4 commented May 7, 2026

Copy link
Copy Markdown
Author

Status update (2026-05-07)

Addressed jonburdo's three review comments:

  1. DRAFT status: Added 4-state lifecycle (draft, active, deprecated, deleted) aligned with the MCP Registry RFC. New versions default to draft. Activation requires MANAGE permission.
  2. Dual MCP paths: Kept both paths. The MCP Registry (RFC-0004) is for standalone servers with independent lifecycle. kind=mcp-server in this registry is for configs embedded in group-level artifacts where separating them would be artificial.
  3. Skill groups as kind=group: Keeping groups as a separate entity. Collapsing them into Skill makes the "Skill" name more confusing since groups bundle agents, hooks, and MCP configs alongside skills. Also consistent with MCP registry's separate server/server group entities.

The naming question (etirelli's comment on "skills" vs. a more generic name) remains open pending alignment on the broader question of unified vs. separate registries in MLflow.

No further edits planned at this time. The RFC is ready for additional review.

(This comment is from Claude Code under the supervision of Bill Murdock.)

@jwm4

jwm4 commented May 12, 2026

Copy link
Copy Markdown
Author

Status update (2026-05-12)

The MCP Registry RFC (PR #12) has merged. Updated RFC-0005 to align with its final design:

Changes made:

  • latest_version resolution: Replaced latest_version_alias (which stored an alias name for indirect resolution) with latest_version (a direct version string), matching the MCP RFC pattern. Fallback now ignores draft versions, and latest is reserved as an alias name.
  • Unpublish transition: Added active -> draft status transition, matching the MCP RFC's full lifecycle. Allows pulling back a version for further review.

Reviewed and kept as-is (ahead of MCP RFC, not incompatible):

  • Alias audit history: Append-only skill_alias_history tables, requested by etirelli. The MCP RFC does not have this, but it is additive and addresses a real governance need.
  • Detailed permissions matrix: Explicit READ/EDIT/MANAGE operation mapping. The MCP RFC defers this detail.
  • CLI specification: Full mlflow skills and mlflow skill-groups command examples. The MCP RFC defers CLI design.
  • Security scan tag conventions: Documented scan.{type}.{field} tag namespace for structured scan tracking. Domain-specific to skills/hooks.

Differs by design (not a gap):

  • Content model: The skill registry is pointer-first (source references to Git, OCI, ZIP, MLflow artifacts). The MCP registry is payload-first (stores the full server_json). These serve different distribution models appropriate to their asset types.
  • Entity structure: The skill registry has two parallel hierarchies (Skill + SkillGroup). The MCP registry has one (MCPServer). Skill groups are needed because skills, agents, MCP servers, and hooks are bundled together in agent harness plugins.

(This comment is from Claude Code under the supervision of Bill Murdock.)

@khaledsulayman khaledsulayman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few questions and some naming suggestions, including:

  • register instead of create
  • bundles instead of skill-groups
  • verb-based skill status lifecycling (publish, unpublish, deprecate, delete)

Comment on lines +48 to +62
skill = mlflow.genai.skills.create_skill(
name="code-review",
description="Reviews pull requests for correctness, style, and security",
)

# Register a version pointing to a Git source
version = mlflow.genai.skills.create_skill_version(
name="code-review",
version="1.0.0",
source_type="git",
source="https://github.com/acme/agent-skills/tree/v1.0.0/code-review",
content_digest="sha256:a3f2b8c...",
)
# version.status == "draft"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*assuming the register naming from my above comment, but also works for create:

It's not clear to me why these can't be consolidated into one entrypoint. For an unregistered skill, calling mlflow.genai.skills.register() (or mlflow skills register in the CLI) without specifying a version should suffice as the current create_skill() operation, whereas specifying a version flag fulfills create_skill_version(). For already registered skills, it seems reasonable for mlflow to internally handle idempotency in the case of an existing skill/skill-version.

If I'm missing something as to why the python API should split this across two methods, I'd still push for at least having one register/create verb in the CLI, if possible.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the same change as the register naming comment above. register_skill() is now a single entrypoint that handles both skill creation and version registration with idempotency. The CLI equivalent is mlflow skills register --name X --version Y ....

(This comment is from Claude Code under the supervision of Bill Murdock.)

Comment on lines +232 to +234
mlflow skills pull-group --name pr-workflow --alias production \
--destination ./plugins/pr-workflow
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we unify pull and pull-group under a single pull command?

The harness RFC already does this for install, so it makes sense for pull to follow the same convention:

mlflow skills pull --name code-review --alias production --destination ./skills/
mlflow skills pull --group pr-workflow --alias production --destination ./plugins/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, if the skill-group naming resolves to assets or bundles:

mlflow bundles pull --name pr-workflow --alias production --destination ./plugins/

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. pull now uses --name vs --group flags, matching how RFC-0006's install already works.

(This comment is from Claude Code under the supervision of Bill Murdock.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I adopted your --group flag suggestion from the naming thread. The CLI now uses mlflow skills pull --group pr-workflow --alias production rather than a separate skill-groups command. This addresses the CLI ergonomics regardless of how the top-level naming question resolves: if the namespace stays skills, the command works as-is; if it changes to bundles or assets, the --group flag pattern carries over directly.

(This comment is from Claude Code under the supervision of Bill Murdock.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terminology update: --group is now --bundle after the entity model restructuring. The CLI is mlflow skills pull --bundle pr-workflow --alias production. Same pattern you suggested, just with the updated name.

This comment was posted by Bill Murdock with assistance from Claude Code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved: the entity is now called SkillBundle, and the CLI uses mlflow skills pull --bundle pr-workflow --alias production. Thanks for pushing on this naming question.

This comment was posted by Bill Murdock with assistance from Claude Code.

Comment on lines +559 to +586
**MLflow artifact storage (`source_type="mlflow"`).** In addition to
external source pointers, the registry supports storing skill content
directly in MLflow's artifact storage. This serves users who do not
have external Git/OCI infrastructure, who want agent capabilities
stored alongside their models, or who operate in airgapped
environments where external sources are not reachable.

Content is stored as a directory tree of individual files under an
artifact path, consistent with how MLflow stores model artifacts. For
example, a skill with a SKILL.md, scripts, and reference material is
stored as separate artifacts under a version-specific prefix:

```
skills/code-review/1.0.0/
SKILL.md
scripts/analyze.sh
scripts/lint-config.json
reference/style-guide.md
```

The `source` field contains the MLflow artifact URI (e.g.,
`mlflow-artifacts:/skills/code-review/1.0.0/`). Pull downloads the
directory tree from the artifact store. The MLflow UI can browse
individual files within a stored skill version.

The upload API accepts a local directory path and stores each file as
a separate artifact. The `content_digest` is computed over the full
directory contents at upload time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit unclear on the actual upload path here. Initially, I assumed this would be done via create_skill()/create_skill_version() by passing (..., source_type=mlflow, source=filepath), but in keeping with the semantics of git and oci, source should probably be reserved for the URI in MLflow's artifact storage.

Do we need to add an explicit skills registry API around uploads, or do we delegate it to users manually calling mlflow.log_artifacts() and maybe document that path?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The register_skill() convenience function now has a content_path parameter. When provided, it uploads the local directory to MLflow artifact storage and sets source_type and source automatically. No manual log_artifacts() call needed.

At the store layer, create_skill_version() also accepts content_path. The server stores each file as a separate artifact under a version-specific prefix (e.g., skills/code-review/1.0.0/SKILL.md) and computes the content_digest at upload time. See the "MLflow artifact storage" subsection in the data model for details.

This comment was posted by Bill Murdock with assistance from Claude Code.

Comment on lines +500 to +512
**MCP servers: two registration paths.** The MCP server registry
(RFC-0004) is the default and recommended path for registering MCP
servers. It provides deployment tracking via hosted bindings,
deduplication across skill groups, and the full MCP governance model.
Skill groups reference MCP registry entries via `registry="mcp"` in
their membership.

`kind=mcp-server` in this registry is reserved for MCP configs that
are embedded in a group-level artifact (e.g., an OCI image containing
a complete plugin with an `.mcp.json` file). These are not
independently managed and exist only as part of their containing
artifact. Standalone MCP servers should always be registered in the
MCP registry, not as skills.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies if it's already implied but should we explicitly add a guard against registering a standalone mcp server via mlflow skills <create/register> --name mcp-name --kind mcp-server --source-type git --source https://...? Such attempts should probably fail and redirect the user to mlflow mcp-servers register

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now moot. The kind field has been removed entirely. Skill, Subagent, and Hook are separate entity types with separate registration functions (register_skill(), register_subagent(), register_hook()). MCP servers are only referenced via cross-registry pointers in SkillBundleVersion.mcp_servers, not registered through the skill registry. See commit d16abe0.

Bill Murdock, with assistance from Claude Code

Comment on lines +48 to +51
skill = mlflow.genai.skills.create_skill(
name="code-review",
description="Reviews pull requests for correctness, style, and security",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: to me, create reads as authoring. Could we go with register instead? This also mimics RFC-0004's convention.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added. The RFC now provides register_skill() as a convenience function that auto-creates the parent Skill entity if needed and registers a version in one call, matching the MCP RFC's register_mcp_server() pattern. The store layer retains create_skill() / create_skill_version() for fine-grained operations, consistent with how the MCP RFC structures its store interface vs. SDK convenience layer.

(This comment is from Claude Code under the supervision of Bill Murdock.)

rfc_pr: https://github.com/mlflow/rfcs/pull/10
---

# RFC: Skill Registry

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, if none of the names appeal, I'd suggest at least in the CLI dropping skill-groups in favor of skills with a --group flag. Something like:

mlflow skills pull --group pr-workflow --alias production

status lifecycle, security scan tracking, and federated discovery.
The two approaches are complementary.

# Adoption strategy

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth adding a note about shared base extraction as per the MCP RFC? If even just to say we will coordinate with MCP registry implementation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added. The adoption strategy now includes a note about coordinating with the MCP Registry's shared base extraction effort where practical to reduce duplication. See the "Shared base extraction" bullet in the adoption strategy section.

(This comment is from Claude Code under the supervision of Bill Murdock.)

Comment on lines +1220 to +1233
def get_skill_group_version(
self, name: str, version: str,
) -> SkillGroupVersion:
raise NotImplementedError

def get_skill_group_version_by_alias(
self, name: str, alias: str,
) -> SkillGroupVersion:
raise NotImplementedError

def get_latest_skill_group_version(
self, name: str,
) -> SkillGroupVersion:
raise NotImplementedError

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same rationale as my reply to your get_skill_version consolidation suggestion: keeping separate methods to match the MCP Registry pattern. The group get methods parallel the skill get methods, which parallel the MCP server get methods.

(This comment is from Claude Code under the supervision of Bill Murdock.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same terminology update: "group get methods" are now "bundle get methods" (get_skill_bundle_version, get_skill_bundle_version_by_alias, etc.).

This comment was posted by Bill Murdock with assistance from Claude Code.

Comment on lines +304 to +309
# Search active skill versions
mlflow skills search-versions --name code-review \
--filter "status = 'active'"

# Search active groups
mlflow skill-groups search --filter "status = 'active'"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd consider a unified list command which will list all skills or skill-groups/assets/bundles unless provided --name or --group, in which case it will list the registered versions of that skill/skill-group/asset/bundle

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the ergonomics of a unified list, but I'm keeping separate search_skills() and search_skill_versions() to match the MCP Registry's pattern (search_mcp_servers() / search_mcp_server_versions()). Consistency across MLflow's registries is a priority so users who learn one API can transfer that knowledge.

In the CLI, this maps to mlflow skills search and mlflow skills search-versions. Skill groups have their own parallel commands.

(This comment is from Claude Code under the supervision of Bill Murdock.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terminology update: "skill groups" are now "skill bundles" with their own parallel commands (mlflow skill-bundles search). The rationale for keeping separate search commands is unchanged.

This comment was posted by Bill Murdock with assistance from Claude Code.

Comment on lines +371 to +372
| `POST` | `/ajax-api/3.0/mlflow/skills/{name}/install` | Install a single capability for a harness |
| `POST` | `/ajax-api/3.0/mlflow/skill-groups/{name}/install` | Install a skill group for a harness |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need REST endpoints for install? Would this not be a client-side operation?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Install is now a client-side operation: the SDK resolves from the registry, pulls content, and writes harness-specific manifests locally. The only server-side endpoint is the marketplace.json GET, which harnesses query to discover available plugins.

(This comment is from Claude Code under the supervision of Bill Murdock.)


- **Skills** (SKILL.md) — reusable agent instructions
- **Agents** (agent .md) — sub-agent definitions
- **MCP servers** (JSON config) — tool server integrations

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that the MCP registry RFC has been merged, is this still in scope?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I removed kind=mcp-server from the skill registry entirely in the previous commit, in response to a similar point from Khaled. MCP servers belong exclusively in the MCP Registry (RFC-0004). Skill groups reference MCP registry entries via registry="mcp" in their membership, and harness-specific .mcp.json configs are generated at install time by RFC-0006.

-- Bill Murdock (with assistance from Claude Code)

Add a Skill Registry to MLflow: a governed, metadata-first registry for
AI agent capabilities. The registry stores metadata and typed source
pointers (to Git repos, OCI registries, ZIP archives, etc.) rather
than artifacts directly. It provides enterprise governance on top of

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you clarify this? When I first read it, it seemed like artifact repository was out of scope but later on I saw that it was.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified. The summary now says the registry stores metadata and typed source pointers, but can also store content directly via MLflow artifact storage. The primary design is metadata-first. The source_type="mlflow" section in the detailed design explains the artifact storage path.

-- Bill Murdock (with assistance from Claude Code)


The list view shows skills and skill groups in a card-based or table
layout, with name, description, latest version, status, and tags. Users
can filter by status, source type, and search by name or description. A

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be useful to track install counts and surface them in the MLflow UI. That would help enterprises understand which capabilities are actually being adopted, and it would also let end users sort or rank skills / skill groups by popularity.

🤖 Generated with Claude

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. We added install count tracking and surfacing in the UI to the adoption strategy section, enabling users to sort or rank capabilities by adoption.

-- Bill Murdock (with assistance from Claude Code)


Version strings must follow [semantic versioning](https://semver.org/)
(e.g., `1.0.0`, `2.1.0-beta.1`). `get_latest_skill_version(name)`
returns the highest semantic version among `active` versions.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just make sure this is aligned with the MCP Registry rules. Latest first resolves to the highest active but if there are no active versions, then it fallsback to the latest non deleted. We may want to do the same here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. get_latest_skill_version(name) now returns the highest active semantic version if one exists, otherwise the highest non-deleted non-active version. Same rule applied to entity-level status derivation. Both the main RFC and implementation details are aligned with the MCP Registry pattern.

(This comment is from Bill Murdock with assistance from Claude Code.)

| `version` | `String(256)` | PK, valid semantic version |
| `version_major` | `Integer` | extracted from validated semantic version |
| `version_minor` | `Integer` | extracted from validated semantic version |
| `version_patch` | `Integer` | extracted from validated semantic version |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to align with the SQL prerelease ordering approach in Jon's PR: mlflow/mlflow#23952

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Added version_prerelease_sort_key (String(512)) to both skill_versions and skill_bundle_versions tables (and noted that subagent/hook tables follow the same pattern). The sort key is a lexicographically sortable encoding of prerelease identifiers, following Jon's approach in mlflow/mlflow#23952. Release versions encode to a sentinel that sorts above all prerelease encodings, so full semver precedence resolves in SQL without application-level tie-breaking.

(This comment is from Bill Murdock with assistance from Claude Code.)

Git transport format. Implementers must decide which Git URL forms are
accepted, how repository, ref, and path are extracted, and how
reproducibility is handled when a ref is mutable. Resolving this
challenge is left to the implementer, but feasible options include the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One option is the URL is to an actual Git remote with an @<ref> suffix that can be cloned and then depend on subpath for the path within the repo.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopted this approach. For source_type="git", source is now a Git clone URL with an @<ref> suffix (e.g., https://github.com/acme/agent-skills.git@v1.0.0), and subpath identifies the path within the repository. This separates the clone target, ref, and content path into distinct fields rather than relying on hosting-provider-specific tree URL conventions. Updated all examples across both RFCs to use this format.

(This comment is from Bill Murdock with assistance from Claude Code.)

member versions may omit `source` because their content is embedded in
the bundle artifact. The optional membership `member_subpath` identifies
where the member lives inside the bundle artifact. For assembled bundles,
`member_subpath` is usually empty because the member's own `source` and `subpath`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think member_subpath being empty should be a hard requirement when the bundle has members with sources.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. For assembled bundles, member_subpath must now be null. The API rejects attempts to set member_subpath on a membership whose member version has its own source.

(This comment is from Bill Murdock with assistance from Claude Code.)

name="pr-workflow",
version="1.0.0",
skills=[
("code-review", "1.0.0"),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer not having a tuple and use specific data type to give us flexibility in the future for more fields.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Replaced all tuples with typed member refs: SkillMemberRef, SubagentMemberRef, HookMemberRef, and McpServerMemberRef. The first three carry an optional member_subpath field for monolithic bundles. Updated the dataclass, store interface, and all examples to use the new types.

(This comment is from Bill Murdock with assistance from Claude Code.)


```python
# A bundle version can include skills, subagents, hooks, and MCP servers
bundle_version = mlflow.genai.skills.create_skill_bundle_version(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you show an example where the skill bundle is the source?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added two monolithic bundle creation examples. One uses a Git source (with a comment showing how the browsable GitHub URL maps to clone URL + subpath), and one uses an OCI source. Both show member_subpath on embedded member refs. These are in the "Create a skill bundle with cross-registry references" section alongside the assembled example.

(This comment is from Bill Murdock with assistance from Claude Code.)

bundle version and any registered embedded skill versions discovered
during import. Automatic per-skill SKILL spans require the local skill
name to resolve to a registered skill version in the manifest. Users of
harnesses without hook support can still use

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might require some clarity if we are leaning in on enhancing existing MLflow autolog.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified. The RFC now explicitly recommends enhancing the MLflow autologger to recognize skill invocations using the install-time manifest and emit SKILL spans with registry coordinates. The autologger runs in the same process that owns the active trace, so it has natural access to thread-local trace context and produces correctly nested spans. Updated both the main RFC-0009 text and the implementation details to lead with this approach, with hook-based correlation and other strategies listed as fallbacks for harnesses without in-process integration.

(This comment is from Bill Murdock with assistance from Claude Code.)

metadata. Import fails if no valid semantic version is available."""
```

Import is append-only with respect to governed versions. It must not

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should allow reimports or edits of a skill bundle version. It should be immutable after creation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. RFC-0008 already has an explicit immutability contract: "The member lists and source fields of a bundle version are immutable after creation." The import section in RFC-0009 now references that contract directly and states that import must not overwrite any existing version. If the target (name, version) already exists, import fails with a conflict.

(This comment is from Bill Murdock with assistance from Claude Code.)

"name": "imported-plugin",
"version": "1.0.0",
"scope": "project",
"mode": "monolithic",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This is probably not needed as the MLflow client should likely be querying the server to validate the information in the lock file.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Removed registry_uri and workspace from the lock file format. The registry URI and workspace now come from the MLflow client configuration, so the same lock file works across environments. Lock replay still contacts the registry to verify version status.

(This comment is from Bill Murdock with assistance from Claude Code.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call on the pip lock pattern. Updated: registry_uri is now optional in the lock file. If specified at lock time, replay uses it; if omitted, replay falls back to the MLflow client configuration. This lets users choose between full determinism and cross-environment portability.

(This comment is from Bill Murdock with assistance from Claude Code.)

Comment on lines +398 to +421
For harnesses where in-process integration is not available, other
approaches may be feasible. These are not exhaustive; the implementer
may choose another approach if it satisfies the same trace-parenting
requirements.

- **Explicit trace correlation for hook commands.** Harness hooks may
pass trace context to external commands through stdin, environment
variables, or a temporary context file. That context could include a
trace ID, parent span ID, or opaque MLflow correlation token. Hook
commands would use this context to create SKILL spans under the
correct parent and would need a way to preserve span lifecycle state
between start and end events.

- **Invocation event annotation.** Instead of opening and closing live
spans from hook commands, hooks can emit timestamped skill invocation
events containing registry coordinates and any available trace
correlation data. MLflow can then attach those events to traces or
materialize derived SKILL spans during ingestion or display.

- **Harness-native extension.** If a harness exposes an in-process
extension or plugin API for skill invocation events, the installer
can configure that extension to call the MLflow tracing SDK directly.
This has similar trace-context advantages to autologger
instrumentation while using the harness's native extension surface.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can likely be removed since we probably don't want to speculate on implementation details here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed. The "Other harnesses" section was speculative and didn't add anything beyond what the "Automatic skill-span instrumentation challenge" section already covers.

(This comment is from Bill Murdock with assistance from Claude Code.)

@mprahl mprahl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few comments but this looks good!

```json
{
"harness": "claude-code",
"locked_at": "2026-05-17T21:00:00Z",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm personally on the fence on whether or not to rely on the client configuration or to put the MLflow server URL and workspace here for easy mlflow install (just need to provide auth).

@HumairAK what do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Pip lock, it seems like you can specify it optionally. Per @mprahl for NPM it seems it's more opinionated and always includes it.

I personally prefer the Pip lock approach and making this optional and let the user decide what level of determinism they want. The way pip does it is:

You specify the index at lock time the same way you do with normal pip operations:

pip lock -i https://my-registry/simple ...
pip lock --extra-index-url https://another-registry/simple ...
or via PIP_INDEX_URL / PIP_EXTRA_INDEX_URL

I think we can take a similar approach here.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jwm4
jwm4 force-pushed the add-skill-registry-rfc branch from 5088cc7 to 2dfb845 Compare June 26, 2026 13:30

@mprahl mprahl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! A lot of hard work went into this RFC and I think this will be a critical feature for MLflow!

Comment on lines +30 to +32
- **Subagents**: sub-agent definitions that can be invoked by a
parent agent
- **Hooks**: event-triggered actions (harness-specific)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are not skills, we should not mix them under the name of skill registry and skills modules.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We went back and forth a lot on the terminology and we want something generic enough to convey an agent capability that includes these subtypes.

Do you have any alternative naming suggestions @B-Step62 ? My personal preference is "agent capabilities" or similar.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some precedent in the industry for "skills" as an umbrella term - e.g. Claude Code plugins created via claude plugin init are saved to ~/.claude/skills. I agree with your point in another comment about having one CLI with a --type or --kind flag. Personally, I like the discoverability of "Skills." They are the first-class entity that people search for, while subagents, hooks, and mcp-server references are mainly expected to be used in conjunction with them.

If we feel strongly about wanting something more generic, I lean towards "assets." Anecdotally, I've heard it used to describe the collective, similar to "agent capabilities," but I slightly prefer one-word naming, especially for CLI verbage.

- **Subagents**: sub-agent definitions that can be invoked by a
parent agent
- **Hooks**: event-triggered actions (harness-specific)
- **Skill bundles**: versioned, governed units that group related

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • If this maps to plugin, why don't we name it "plugin"? We don't prefer inventing an extra concept that increases cognitive load to users.
  • Why do we treat MCP server particularly as a part of skill bundle? This feels like just a logical group that bundles any sort of assets the proposal is adding. Also calling MCP server as "skill bundle" is confusing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll let @jwm4 chime in more here, but my recollection is that "plugin" is vendor specific and this was trying to use more generic terminology.

On the MCP server part, I'm kind of leaning towards not including it here and tackling that cross-registry integration with a future agents registry.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vendor-specific issue is a factor, but really my main concern about having a "plugin registry" in MLflow is that I would expect users to see this as a registry for MLflow plugins, which are unrelated. One of the things I like about the names "skill registry" and "skill bundle" is that most of the time the main content in these things are skills, so if a user comes in with the question "where do I find the skills?", I'd like the name of this capability to make it extremely clear and intuitive to understand that this is the place to look for the skills. However, I definitely recognize that that desire has come at the cost of now being confusing when you look more closely at it and see that it is skills plus other stuff so I think "Agent Capabilities" as Matt proposes in the other thread would be a fine conclusion here. Maybe the registry is called "Agent Capabilities Registry" and the bundles are called "Agent Capability Bundles"? I think the words "context" or "prompting" would also be fine to include in some naming scheme somehow (e.g, "Context Registries" and "Context Bundles" or "Context Plugins" or whatever). Personally, I still would prefer to have skill in the name somehow, because I still worry about the user trying to find the skills and not knowing where to look. But I also want to try to keep these names as concise as possible so I wouldn't want something like "Skills and Related Capabilities Plugin Registry" because it's just too wordy.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to this comment, I'd research a bit more about existing standard or spec for bundling these concepts rather than defining a new one. I see the vendor neutral benefit, but defining our own spec means that we lock users down to MLflow as a vendor, unless we commit to evangelize and push this to be an industry standard like OpenTelemetry. Considering the number of players in the industry and how influential some of vendors are, I'm not very optimistic for that direction.

Comment on lines +52 to +60
mlflow skills register --name code-review --version 1.0.0 \
--source https://github.com/acme/agent-skills.git@v1.0.0 \
--subpath code-review
mlflow subagents register --name security-auditor --version 1.0.0 \
--source https://github.com/acme/agent-skills.git@v1.0.0 \
--subpath security-auditor
mlflow hooks register --name pre-commit-scan --version 1.0.0 \
--source https://github.com/acme/agent-skills.git@v1.0.0 \
--subpath pre-commit-scan

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Learning different CLI for different types of entities is hectic. We also don't like to maintain many CLI modules with lots of overlapping functionality and configurations.

Can we instead have a single CLI with type argument?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds reasonable to me. Once we settle on a name / scope for the overall registry, it should be relatively simple to have a single command like mlflow agentic-capability register --type skill ... (or whatever we settle on in place of agentic-capability).

3. Transition the bundle version from draft to active:
```bash
mlflow skill-bundles update-version --name pr-workflow \
--version 1.0.0 --status active

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "active" mean for skill? It sounds like just a special kind of tags or alias.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the goal here is to align with the MCP registry statuses. The benefit of having a status on a skill is to still have lineage tracking to traces and version history but you can mark a skill version as deprecated without having to delete it.

1. Install the bundle for a harness
([RFC-0009](../0009-skill-harness-integration/0009-skill-harness-integration.md)):
```bash
mlflow skills install-bundle --name pr-workflow --alias production \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People often install a set of skills from github directory using a single command gh skills install repo/name. In order to do this through MLflow, do users need to define bundle themselves? It can be a major overhead for adopting MLflow.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main goal here is to have a single command that's compatible with all the different source types that we support (GitHub, OCI, .zip file URLs, stored in MLflow). That way users can pull skill content from the registry without having to pay much attention to whether it's coming from GitHub, OCI, etc. We're seeing a lot of arguments out there about OCI in particular as a better data layer for highly managed content than GitHub, so we really want to at least be compatible with OCI and GitHub. The other source types are more debatable, but if we're going to have multiple source types anyway, including those two seems reasonable to me. Storing the skills in MLflow itself was not part of the original proposal, but it was requested in an earlier review of this RFC and it didn't seem like an unreasonable request to me.

```
2. Install v1.0.0 and run it on a set of test inputs. Traces are
recorded in MLflow under experiment A.
3. Install v2.0.0 and run it on the same test inputs. Traces are

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine it is a common scenario to test the performance between with and without a skill, or a different set of skills. Do we have a plan for supporting that use case?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That as a first class experience would likely be better though an agents registry (e.g. agent v1 used the skill but agent v2 did not).

I think this is still possible with separate evaluation runs and so we should include that as a user journey.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this is an important scenario. As Matt requested, I've added a new user journey ("Compare agent performance with and without a skill") that walks through this: run the agent without the skill as a baseline, install the skill, run again, evaluate both with the same scorers, and compare side-by-side. The same pattern works for comparing different skill sets.

As Matt notes, a first-class experience for managing which skills are active per agent configuration would benefit from a future agents registry.

4. Use `mlflow.genai.evaluate()` with a `make_judge` scorer that
uses the `{{ trace }}` template variable to score both sets of
traces against quality criteria (correctness, helpfulness, safety).
5. Compare the evaluation results side by side in the MLflow UI to

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do users manage lineage between the MLflow metadata of the loaded skill and the evaluation result?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intended lineage path is through the trace: evaluation operates on traces, and skill lineage is recorded on SKILL spans via the {workspace, name, version} coordinates. So an evaluation result can be related back to the loaded skill by following the associated trace and inspecting its SKILL span(s).

To me, the RFC does not currently make that workflow explicit enough. If the expectation is that users traverse trace -> spans -> skill coordinates, we should document that clearly. Otherwise, a more first-class lookup/linkage mechanism may be worth adding. cc @jwm4

@jwm4 jwm4 Jul 9, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a new user journey ("Trace skill lineage to evaluation results") to the RFC that makes this explicit. The lineage path flows through traces:

  1. Skill invocations produce SKILL spans with {workspace, name, version} registry coordinates.
  2. mlflow.genai.evaluate() produces results linked to traces via trace_id.
  3. Trace.search_spans(span_type="SKILL") retrieves the skill version from any traced evaluation result.
  4. mlflow.search_traces() with span-level filters finds all traces involving a specific skill version.

The current approach is two-step (query traces by skill attributes, then retrieve evaluation results). I also added a note as a phase 3 follow up to do richer integration such as filtering evaluation results directly by skill version.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does trace records lineage to skills in MLflow? Once the skill is pulled from MLflow, it doesn't contain metadata about MLflow.

In my old prototype I tried to resolve this by saving a special metadata file during pull and make MLflow tracing look at that. However, this does not always work because users may not use MLflow SDK for tracing. For example, Claude Code support Otel tracing as beta, and once it is fully supported we may migrate to that. At that point, the tracing logic is not owned by us hence the file based approach doesn't work.

- **MCP server hosting.** MCP server deployment and runtime management
are covered by the MCP Server Registry (RFC-0004) and the MCP
Gateway.
- **Prompts.** MLflow already has a Prompt Registry for versioned

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is not a strong distinction between two in the industry. Custom agent frameworks like pydantic AI, Google ADK, Claude Agent SDK support skills and MCPs. Also managed harness still inputs prompts. The boundary is merely whether a harness is owned by framework or users, not about what primitive they use.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me the biggest distinction between a skill and a prompt is that a skill includes some mechanism to invoke it. I think the common practice for skills is:

  1. Skills can be invoked directly by the user (e.g., /create-cookie-recipe).
  2. Skills can be invoked via the model using a skill tool.

The skill format includes meta-data controlling both of these (whether one of these or both of these is allowed, the description of the skill that the model uses to decide whether to invoke it).

Another key distinction between a skill and a prompt is that a skill is typically a directory containing both the SKILL.md and some additional content (typically scripts, templates, and resources), where the SKILL.md file is the prompt that gets loaded up when the skill invoked and the other content is only accessed progressively when directed by that prompt. For example, a skill could have a resources directory with many resource files, each handling a specific situation that sometimes arises and collectively, they might be all too big to put into a single prompt because they would exceed the context window, but the skill never needs to know all of them at once. It only needs to know the one that's relevant to the particular situation that it finds itself in.

Now, of course, a regular prompt in the prompt registry could also provide instructions to load some resource or invoke some script under certain circumstances. But those resources and scripts need to be delivered, managed, and governed separately because they're not part of the prompt itself. Skills address this limitation.

Anyway, I'm not sure what the consequences for this document are. Is there something in this bullet point that you would like revised?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry my wording was vague - the question is not distinction between prompt and skills, but harness-based agents vs. custom agentic code. IIUC the claim here is that the skills are for the former (e.g. claude code) and prompts are for the latter (e.g. langgraph). However, the mapping is not that distinct so audience overlaps.

The indication to the design is that I don't think we should treat prompt as an exception from the "general assets registry" concept.


# Summary

Add harness-specific installation to the MLflow Skill Registry

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be missing something, but isn't installation of skill just copying files into the target machine with specific location prefix? It is what gh skills install command does. What problem are we trying to solve with this proposal above that?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I addressed this in an earlier response, but I want to put the answer here too for anyone looking at this thread in isolation:

My main goal here is to have a single command that's compatible with all the different source types that we support (GitHub, OCI, .zip file URLs, stored in MLflow). That way users can pull skill content from the registry without having to pay much attention to whether it's coming from GitHub, OCI, etc. We're seeing a lot of arguments out there about OCI in particular as a better data layer for highly managed content than GitHub, so we really want to at least be compatible with OCI and GitHub. The other source types are more debatable, but if we're going to have multiple source types anyway, including those two seems reasonable to me. Storing the skills in MLflow itself was not part of the original proposal, but it was requested in an earlier review of this RFC and it didn't seem like an unreasonable request to me.

@HumairAK HumairAK Jul 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me like the skills in gh skills install are primarily about installing Agent Skills, not full “plugin bundles.” Where as harness-integration RFC defines a plugin as an installable package that can bundle skills, custom agents, hooks, and MCP server configurations.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't realize that. Thank you for clarifying, @HumairAK ! It does seem like another important differentiator in addition to the multi-source support.

@B-Step62 B-Step62 Jul 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand there is some extension, but I'm not sure if we should step into the "plugin bundles" concept in this RFC. It is non trivial complexity to define such standard "bundle" for many different downstream agents and respective mapping logic between them. I feel it's too premature for MLflow to take that responsibility.

Also curious if you have looked at https://github.com/microsoft/apm, which sounds like solving the similar problem here. We could adopt an existing spec like this and just store them as a pure artifact rather than inventing a new one.

@jwm4 Btw this PR is getting super long, even Github UI takes me minutes to load comments😅 Can we at least split two RFCs into separate PRs? The general rule of thumb is one PR for one RFC.

@B-Step62

B-Step62 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Thanks for the proposal, @jwm4 @mprahl. Honestly, it feels broader in scope than the original skill management problem. If the intent is to cover a wider range of assets than skills, I'm supportive for the direction itself, but in that case the design should work backward from that broader goal rather than extend the mechanics built for skills. I'd also stress extensibility, since a year from now the industry could easily have five more concepts we'll want to fit into this.

shared artifact (used with OCI and ZIP). The optional `content_digest`
field enables integrity verification.

#### Subagent and Hook

@TomeHirata TomeHirata Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Afaik, there's no standard schema for subagents and hooks. What kind of format will we use for these, and do we think we can have a unified schema to support multiple harnesses?

@mprahl mprahl Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the proposed schema is generic/vendor neutral, but the actual contents may not be, so it may be worthwhile to distinguish what vendor format the hook is in and let each harness determine if they support that format.

Thoughts @jwm4?

lifecycle patterns. The store interface, REST API, and SDK expose
parallel operations for each type.

#### SkillBundle

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, it's a bit odd to call it as "skill" bundle while it contains subagents and hooks

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can consolidate the naming discussions to https://github.com/mlflow/rfcs/pull/10/changes#r3533636917.

cross-registry reference handling for all entity types are in
[implementation-details.md](implementation-details.md#skill-entity).

#### Aliases and tags

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now MLflow has too many tag and alias tables, can we define a canonical table with generic fields like Tag(entity_type="skill_version", entity_id="1", key="team", value="db")?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually prefer separate tag and alias tables to allow database indexes to be lean. Using generic EAV tables causes scale issues with large tables on joins.

I think we can consider consolidating it for this registry but I'd like to not make this a generic tags table of all future entities.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also prefer the lean table approach Matt advocates for, but I can accept whatever the conclusion of this discussion is.

repositories. This works well for individual developers and small
teams. GitHub provides versioning, collaboration, and access control.

However, enterprises face governance challenges that Git alone does not

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember previously we discussed that this limitation of git is not strong enough to add a skill registry to MLflow. What are the new value adds and/or evidence for us to try this again? cc: @B-Step62

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TomeHirata the following section is intended to address that by outlining why Git alone is insufficient here. It would be helpful to understand which of those arguments, or any previously discussed concerns, you still find unconvincing so we can either strengthen the case or clarify the RFC.

"which skill versions are most used?" or "show me all traces where
the deprecated code-review v1.0 was loaded."

5. **No pull mechanism.** Once a user discovers a capability in the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can install skills from git (e.g., https://cli.github.com/manual/gh_skill_install)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! I didn't know about that.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think this would be a good solution for users who have their skills in GitHub. I discussed the issues with the other source types in this other thread.

servers, and hooks together. But there is no agent-neutral way to
represent these bundles for governance and discovery.

4. **No trace-to-skill linkage.** MLflow already traces agent

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this can be done even without having "registry". We can create a span for each skill invocation and store skill name as span attributes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but I think the user experience is significantly better if MLflow is aware of what the meaning of those attributes are. Otherwise, it's up to each user to define what meaning the span attributes have. The meaning would not be entirely clear to a person or agent viewing the trace such as where did this skill come from, what were the contents of the skill, did the skill change recently, etc?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Matt, and also I'm thinking head towards what we want in a future agent registry and I feel like mostly what we want is to be able to aggregate the contents of the other registries (i.e., the registry entry for an agent links to the registry entries for the models, prompts, MCP servers, skills, etc. that it uses).

@HumairAK HumairAK Jul 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this can be done even without having "registry". We can create a span for each skill invocation and store skill name as span attributes.

The value add here is that the registry turns those attributes from individual user managed metadata into a governed, versioned API. That makes the data compatible across clients, tools, teams, and organizations, and enables queries like "which registered skill version was used here?" or "show traces involving deprecated skills."

jwm4 and others added 2 commits July 9, 2026 14:02
Add a new user journey showing how evaluation results trace back
to specific skill versions through SKILL spans, with code examples
using search_traces and search_spans. Note richer evaluation-to-skill
query integration as Phase 3 follow-up work.

Addresses reviewer feedback from B-Step62 and HumairAK on PR mlflow#10.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show how to measure the impact of adding or removing a skill using
the same evaluation infrastructure as version comparison. Addresses
reviewer feedback from B-Step62 on PR mlflow#10.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jwm4

jwm4 commented Jul 10, 2026

Copy link
Copy Markdown
Author

After more discussion, we've decided to close this PR and open new ones that include a much simpler phase one to get to value sooner followed by a more complete phase two later. I will be opening those new PRs ASAP (probably some time next week).

@jwm4 jwm4 closed this Jul 10, 2026
@jwm4 jwm4 mentioned this pull request Jul 14, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.