Add RFC-0011: Agent Registry - #39
Conversation
First draft covering the introductory material and user journeys: record-level registry for AI agents with Agent/AgentVersion entities, composition (BOM) with definitional anchors, A2A card as canonical-when-present payload, protocol-typed access bindings, and agent-centric traces and evaluations via a new trace destination. Detailed design and later sections are TBD. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plugins are referenced as composed units and expand through their RFC-0008-recorded members for cross-registry queries, so blast-radius lookups find agents that consume a skill via a plugin. Previously held as an open question; resolved by team direction and confirmed by the registry UI prototype's "Link plugin" flow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Source provenance now covers Git repos, OCI images, and archives via the typed source pointers RFC-0008 defines, matching how agents are actually distributed, instead of Git-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Agent versions are registry-minted serial numbers, per the policy from the earlier registries: adopt the artifact's inherent version when its format defines one, mint serial numbers when it does not. No standard agent artifact defines one; an A2A card's provider-defined version string is preserved as metadata, not adopted as identity. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A version's source provenance is now a list of typed pointers, so an
agent built from a Git repo and shipped as an OCI image records both,
and source entries join the queryable axes ("which agents ship image
X?"). Deliberate divergence from RFC-0008's one-source-per-version
rule, with the rationale (agents have no content digest to reconcile
per-source duplicates) stated in Open questions.
Prompted by Ann Marie's review question.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An Agent chooses its version scheme at creation: monotonic (registry-assigned serial numbers, the default when no version is supplied), semver, or freeform, with possible autodetection from the first registration. Keeps the simple path as simple as the Skill Registry while letting provider-versioned agents keep their own versioning. Proposed by Matthew Prahl in review discussion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The agent's endpoint is the card's system of record: registration imports descriptive metadata (card name seeds display_name) and creates the a2a binding, the UI renders the card read-only by fetching through the binding, and no card payload is persisted. This deliberately departs from the RFC-0004/0008 canonical-payload pattern. Endpoint-only registrations become interface-only records with no definitional anchor, marked as such. The canonicity open question is replaced by whether registration and lifecycle events should capture card copies as audit evidence. Direction from design-doc review comments, confirmed by Bill. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both evaluate sketches now pass agent_version alongside agent_id; version-to-version eval comparison (J3) needs the version captured at evaluation time. From design-doc review feedback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The case for capturing card copies as decision evidence was weak: no customer signal, promotion decisions rest on eval evidence, and registration already imports the card's claim surface into registry fields. The open question is now solely about how thin an interface-only record may be. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two sentences in the versioning journey: the choice is the same judgment developers make for any software, the registry enforces no rule, and the consequence is that version comparison exists only within one agent. From design-doc review discussion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| destination today, and evaluation and trace-search APIs gain agent | ||
| identity alongside experiment identity. Traces and eval results | ||
| appear on the agent's registry page, filterable by version. The | ||
| change is additive: under the hood an agent owns a default |
There was a problem hiding this comment.
I believe you want a default experiment per agent-version rather than a default experiment per agent.
There was a problem hiding this comment.
This is now an explicit open question in the draft ("Is the default experiment per agent or per agent-version?") with both positions stated; reviewer input is welcome. The draft's current position is per agent: the version is recorded on every trace and evaluation run as metadata, so per-version filtering and comparison work within one experiment, and monitoring an agent's behavior across upgrades stays in one place. Whichever default is chosen, users who want the other behavior can override it per deployment, so the open question is which default serves most users best.
(From Bill Murdock with assistance with Claude Code.)
| the cause, cross-referencing the BOM diff from the previous | ||
| journey. | ||
|
|
||
| Backward compatibility is preserved by construction: an agent owns a |
There was a problem hiding this comment.
Here again it would be a default experiment ID per agent-version rather than per agent. The version would be a required argument for this to work.
There was a problem hiding this comment.
Same resolution as the thread above: this is now an open question in the draft with both positions stated. One note on "the version would be a required argument": that requirement is specific to the per-version model, and it is part of the cost weighed in the open question. Under the draft's current per-agent position, the destination resolves from the agent alone, and the version is a label recorded on traces and evaluation runs rather than an input to destination resolution; the latest draft spells out that separation in the trace journey.
(From Bill Murdock with assistance from Claude Code.)
| to that experiment's ID. Where MLflow already accepts a typed | ||
| destination or location (trace destinations, `search_traces` | ||
| locations), agent identity becomes a new accepted value; where it | ||
| does not (`evaluate`), `agent_id` is new, optional surface. Existing |
There was a problem hiding this comment.
The agent_id and agent_version constitutes two values where you used to pass one value, so you can't just pass an agent_id and silently map it to the experiment_id. I think this will probably require more API changes than this paragraph suggests.
There was a problem hiding this comment.
The latest draft addresses this in two ways. First, destination resolution takes one value: the agent maps to its default experiment, and the version is not part of that mapping (it is recorded on traces and evaluation runs as metadata). Needing both values to resolve a destination is a cost specific to the per-version model, which the new open question weighs. Second, fair point that the API surface was understated: the trace journey now spells out the pieces, including a public get_default_experiment_id lookup that takes only the agent, and the backward-compatibility paragraph is explicit about where agent identity becomes a new accepted value for existing parameters versus where it is new optional surface (evaluate).
(From Bill Murdock with assistance from Claude Code.)
There was a problem hiding this comment.
Thanks. That makes sense, now that everything is consistent.
|
|
||
| - **Should agent-centric traces and evaluations be a separate RFC?** | ||
| The experiments bridge (`agent_id` resolving to a default | ||
| experiment) touches tracing APIs, evaluation APIs, and UI surface |
There was a problem hiding this comment.
agent_id + agent_version resolving to a default experiment...
There was a problem hiding this comment.
The granularity of that mapping is now its own open question ("Is the default experiment per agent or per agent-version?") with both positions stated. The sentence here describes the draft's current per-agent position and would change if the per-version position wins out.
(From Bill Murdock with assistance from Claude Code.)
|
|
||
| 1. Log traces against the agent instead of an experiment: | ||
| ```python | ||
| mlflow.genai.set_active_agent("acme/billing-agent", version=3) |
There was a problem hiding this comment.
I think you should keep this as two API calls rather than one convenience API, for maintainability. Pseudocode:
replace
mlflow.genai.set_active_agent("acme/billing-agent", version=3)
with
mlflow.genai.set_active_experiment(mlflow.genai.get_default_experiment_id("acme/billing-agent", version=3))
where mlflow.genai.get_default_experiment_id("acme/billing-agent", version=3) returns an experiment ID.
Then if, for example, you have a single agent that has many different users using it in different namespaces and they need different experiment IDs, you can just get the experiment ID using a different lookup rather than using the default for the agent-version, and only one line of code needs to change.
If you don't keep the API calls separate, I think people will be confused as to whether they are using the experiment ID for their specific agent deployment vs. the default experiment ID for all agents with the same version.
As Bill pointed out offline, there are a couple of different uses cases here that we need to keep separate. Keeping the API calls separate lets us support all of them:
- Scale-out copies (one deployment, many replicas serving one user base): all replicas share the same deployment config, so they share a destination and their traces aggregate, which is what I would want there.
- Copies that differ in configuration: under the RFC those are different registered versions, so they already get separate default experiments.
- Identical copies with different owners or user bases: the deployments should then override the default experiment.
There was a problem hiding this comment.
The latest draft adopts something along these lines: the trace journey now defines the lookup as a public API (get_default_experiment_id) and defines set_active_agent as convenience over exactly the two pieces you sketch, setting the destination via that lookup plus recording the agent and version as trace metadata. A deployment that needs a different experiment swaps only the lookup line, as you describe. Two notes: the convenience wrapper is kept because the metadata half still needs declaring even when the destination is overridden, and the lookup takes only the agent under the draft's current per-agent position; whether it should take a version as well is exactly the new granularity open question.
(From Bill Murdock with assistance from Claude Code.)
| scorers=[correctness_scorer], | ||
| agent_id="acme/billing-agent", | ||
| agent_version=3) | ||
| ``` |
There was a problem hiding this comment.
Here as well, I recommend keeping the experiment ID lookup separate rather than bundling it into one convenience API.
There was a problem hiding this comment.
Same resolution as the sibling thread: the lookup is now a public API, and the convenience wrapper is documented as exactly that lookup plus the metadata recording, so the two remain separable.
(From Bill Murdock with assistance from Claude Code.)
The journey no longer claims the diff reveals what broke and then
walks it back. The investigator is framed from the start as someone
other than the change author, the diff is a shared record of
declared changes ("what differs in the declarations for two
versions"), and it gives an investigation its starting facts rather
than answers. From design-doc review discussion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New J3 paragraph: the default experiment is a default, not a router. Deployments log wherever their own configuration points; scale-out replicas aggregate by sharing config; deployments needing separation override the destination (destinations, not tags, because permissions are experiment-scoped). Proposes, as not yet settled, that such deployments notify the registry so the experiment ID is recorded on their access binding. Sync bullet gains trace-location link upkeep. From the deployment/experiment-mapping review discussions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One sentence in the J3 deployment paragraph: a version is an analysis dimension recorded on every trace, not an access boundary, and per-version experiments would break the longitudinal view across upgrades. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The RFC keeps its per-agent position but now acknowledges the fork as an open question with both sides stated, since a reviewer holds the per-version position and the author is not settled. Whichever default is chosen, the other camp overrides per deployment, so the question is which behavior makes the better default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The API sketches implied the version participates in choosing the default experiment. Now stated explicitly in the Summary, basic example, and trace journey: a destination identifies the agent only and resolves to its one default experiment; the version is recorded on every trace and evaluation run as metadata. set_active_agent is defined as convenience over two separable pieces, with get_default_experiment_id exposed as a public agent-only lookup (partially adopting Ann Marie's two-call review suggestion), and deployment overrides swap only the destination piece. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cut redundancy that accreted across incremental revisions: rules stated in multiple places (server-never-fetches, card-not-persisted, default-experiment mechanics) now appear once where they matter most, the blast-radius rationale is consolidated, and digressions are trimmed. No design content changed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Summary is now a summary: opening, lineage, a one-paragraph tour of the positions, and RFC relationships. The full position statements move intact to a Design positions subsection under Detailed design, where they seed the eventual full design. No content changed beyond the pointer sentences. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
aakankshaduggal
left a comment
There was a problem hiding this comment.
Two inline comments on BOM coverage — asking whether these are RFC-scope or could be deferred.
Generated using Claude Code under Aakanksha's supervision.
| otherwise. Alternatives include structured | ||
| `{registry, name, version}` objects. Relatedly: should the BOM | ||
| also be able to reference other agents, to represent multi-agent | ||
| systems? |
There was a problem hiding this comment.
On the open question about agent-to-agent BOM references: curious whether this could be deferred as an implementation detail rather than an RFC-level concern.
The blast-radius journey assumes the BOM captures meaningful dependencies, but agent-to-agent delegation (especially via A2A) is arguably the highest-impact dependency an agent can have. Without an agents axis, search_agent_versions can't answer "which agents delegate to the compromised one?"
Could a lightweight agents soft-reference axis (same pattern as the other BOM axes) close this gap, or does this need its own design treatment?
| - **AgentVersion**: an immutable snapshot of the agent's composition, | ||
| its **bill of materials (BOM)**: skill references, agent plugin | ||
| references (a plugin is referenced as a composed unit and expands | ||
| through its registered members for queries), MCP server |
There was a problem hiding this comment.
The BOM references agent plugins and Journey 6 describes expanding through plugin members for blast-radius queries. Under merged RFC-0008, plugin membership is skills-only — MCP server and subagent membership requires RFC-0010 (PR #27).
Is this worth noting as a dependency, or is the plugin expansion behavior an implementation detail that doesn't need to be settled here?
| There is no user source repository: the agent is the harness plus | ||
| its configuration, so the configuration snapshot serves as the | ||
| definitional anchor. `config_snapshot` names a file or directory on | ||
| the caller's local disk; the client reads it and uploads the |
There was a problem hiding this comment.
How does this get uploaded if MLflow is not serving artifacts and the agent is not associated with an experiment to inherit its artifact location?
| skills=["skills:/runbook-triage/2"], | ||
| mcp_servers=["mcp-servers:/acme.internal/pagerduty/1.2.0"], | ||
| models=["claude-sonnet-5"], | ||
| config_snapshot="./opencode.json", |
There was a problem hiding this comment.
Could we remove this and just rely on Git, zip, and OCI? I'm worried about Mlflow suddenly being a arbitrary packaging system and potentially secrets management...
| mlflow.genai.register_agent( | ||
| name="acme/oncall-helper", | ||
| description="On-call assistant run in OpenCode.", | ||
| harness="opencode", |
There was a problem hiding this comment.
Could we rename this to runtime? I worry that harness is too limiting.
| mlflow.genai.register_agent( | ||
| name="acme/oncall-helper", | ||
| description="On-call assistant run in OpenCode.", | ||
| harness="opencode", |
There was a problem hiding this comment.
I worry about this being entirely free form and getting variations of spelling of the same meaning. Could we have a hybrid approach where if it's a variation of a well known harness or framework like OpenCode or open-code we can reject it? Alternatively, we can add a concept of available harnesses at the workspace level (common ones preenabled) and this becomes an enum.
| harness_version="0.5.3", | ||
| skills=["skills:/runbook-triage/2"], | ||
| mcp_servers=["mcp-servers:/acme.internal/pagerduty/1.2.0"], | ||
| models=["claude-sonnet-5"], |
There was a problem hiding this comment.
Similar comment to https://github.com/mlflow/rfcs/pull/39/changes#r3917690676. We probably need a way to have this be a list that is configurable at the workspace and/or server level. We can preload several in a similar way that MLflow does cost calculations or how it populates the AI Gateway endpoints from different vendors.
| ## Trace and evaluate against the agent | ||
|
|
||
| ```python | ||
| mlflow.genai.set_active_agent("acme/billing-agent", version=3) |
There was a problem hiding this comment.
How does it work if you use "agent-as-a-tool" pattern where a tool call can invoke a distinct agent?
| First, it sets the trace destination to the agent's one default | ||
| experiment, equivalent to calling `mlflow.set_experiment` on the | ||
| result of | ||
| `mlflow.genai.get_default_experiment_id("acme/billing-agent")`, |
There was a problem hiding this comment.
I think we should be bolder and use the Agent Registry to start phasing out the term “experiment” for GenAI traces and evaluations. Users could create either an experiment or an agent, with largely the same UX for now, aside from the registry-specific functionality and agent-centric labeling. What do you think, @B-Step62?
| 1. Register the agent, supplying identity, provenance, and | ||
| composition: | ||
| ```python | ||
| mlflow.genai.register_agent( |
There was a problem hiding this comment.
What about prompts? It seems good to track system prompts in the prompt registry.
| composition: | ||
| ```python | ||
| mlflow.genai.register_agent( | ||
| name="acme/billing-agent", |
There was a problem hiding this comment.
Should agents use the same {workspace, organization, name} coordinates as skills instead of embedding the organization in a DNS-style name? Consistency across the registries seems valuable if we are not constrained by an existing standard.
| endpoint. These combine freely; a first-party A2A agent registers | ||
| with both source and endpoint. Only a registration with an | ||
| endpoint and no anchor produces an interface-only record (see | ||
| below). Composition (the BOM) is required when an anchor is |
There was a problem hiding this comment.
What exactly is required here?
| out, because an embedded copy is invisible to cross-registry | ||
| queries and can drift from the declared references. | ||
|
|
||
| Composition is required wherever it is knowable, because the BOM is |
There was a problem hiding this comment.
This feels more like detailed design and rationale than part of the user journey. Could we move it to the BOM or interface-only design section and state only the registration requirement here? “Required wherever it is knowable” is also ambiguous and difficult to enforce. I think the actual rule is that anchored records must declare composition, while interface-only records may declare it as partial or undeclared.
| is limited to values that tell a caller something actionable: `a2a` | ||
| and `mcp` are self-describing (an Agent Card at the well-known | ||
| path; the MCP handshake), so URL plus protocol is enough to | ||
| connect. Labels like REST or gRPC name a transport without telling |
There was a problem hiding this comment.
Does the agent binding need a "read me" or "how to connect" field for the other cases? Otherwise, the user or agent will have no idea how to use this agent.
There was a problem hiding this comment.
Also, perhaps, a JSON schema or OpenAPI doc could be a more programmatic approach.
| links (see the trace journey) calls for platform-side glue (for | ||
| example a Kubernetes controller) pushing to the registry APIs | ||
| this RFC defines. Deferred. | ||
| - **Auto-discovery of composition.** BOMs are developer-asserted in |
There was a problem hiding this comment.
I see that trace-based composition discovery and drift detection are listed as out of scope, but I think we may be missing an important user journey here. A user should be able to select traces from an experiment, infer the observed skills, MCP servers, and models, review the proposed BOM, and register it as a draft agent version. Once registered, MLflow could also flag when traces associated with that version use undeclared components or different component versions. Is this intentionally deferred from the MVP, including the user-initiated workflow?
There was a problem hiding this comment.
That discovery would be complex. Could it be a separate focused RFC?
There was a problem hiding this comment.
A separate RFC works for me!
|
|
||
| 1. Log traces against the agent instead of an experiment: | ||
| ```python | ||
| mlflow.genai.set_active_agent("acme/billing-agent", version=3) |
There was a problem hiding this comment.
We probably need a header like we do for experiment ID for OTel traces.
| ``` | ||
| `set_active_agent` is convenience over two separable pieces. | ||
| First, it sets the trace destination to the agent's one default | ||
| experiment, equivalent to calling `mlflow.set_experiment` on the |
There was a problem hiding this comment.
If we do end up going with an agent being associated with an experiment, I don't know if it's a good idea to let the user override the experiment to send traces to. It may be confusing as the user has no way of knowing where all the agent's traces are located (e.g. in the default experiment or across multiple?)
| The default experiment is a default, not a router. A running agent | ||
| logs traces to whatever destination its own deployment | ||
| configuration sets; the registry is not in the call path. When | ||
| nothing is set, traces land in the agent's default experiment, |
There was a problem hiding this comment.
Is the agent's default experiment per agent version or per agent? Can it be updated?
| other deployments of the same agent (a different owner or user | ||
| base) overrides the destination in its own configuration; because | ||
| permissions are experiment-scoped, separation is done with | ||
| destinations, not trace tags. Versions share the agent's experiment |
There was a problem hiding this comment.
This is getting too implementation specific for user journeys.
| Automating the setup and upkeep of these links at deploy time | ||
| belongs to the deferred registry synchronization glue. | ||
|
|
||
| No endpoint is needed for any of this when the developer has the |
There was a problem hiding this comment.
This probably should be its own user journey?
| natural follow-ons; their exclusion here is sequencing, not | ||
| rejection. | ||
|
|
||
| - **Runtime state.** Health, liveness, deployment status, scaling, |
There was a problem hiding this comment.
Do we want to allow URLs from the access endpoint to the dashboard URL of the system that serves the agent? I think this could be useful in RHOAI.
| results should surface them alongside matches: "3 agents declare | ||
| the compromised skill; 12 more have undeclared composition." | ||
|
|
||
| ## Out of scope |
There was a problem hiding this comment.
Could we add a new command such as uvx mlflow@latest agent register (already an existing uvx mlflow@latest agent setup) that scans the source code and registers the skills, MCP registries, and agent? Then it'd add the MLflow lock files/coordinates files.
There was a problem hiding this comment.
That seems like it could be its own smaller RFC, couldn’t it?
There was a problem hiding this comment.
I think it could be kept at a high level here. No need for implementation details.
| - **Automated notifications.** The blast-radius journey ends with the | ||
| registry naming owners; notifying them is left to the organization | ||
| in the MVP. | ||
| - **Agent-to-agent runtime discovery.** A programmatic "find me an |
There was a problem hiding this comment.
Doesn't an A2A access endpoint do this though? The agent can search for agents with A2A and grab the URL and continue.
|
|
||
| **The registry is record-level, not runtime-aware.** It stores what | ||
| an agent is, not whether it is running, healthy, or scaled. Runtime | ||
| state belongs to the serving platform, which can join its own |
There was a problem hiding this comment.
Have you considered at least storing an agent's capabilities if the agent was registered via an A2A card?
| ("which agents use skill X?") answerable as registry queries | ||
| without constraining registration order. | ||
|
|
||
| **The BOM is a component inventory, not a complete recipe.** Its |
There was a problem hiding this comment.
Let's just make sure we have an API that exports the agent's BOM as JSON. In other words, just the agent definition but with the skills, MCP servers, prompts, and models all resolved, not pointers. This could be useful for other systems integrating with MLflow.
| the live card from the endpoint's well-known path, and the registry | ||
| follows suit. Registering from an endpoint imports the card's | ||
| descriptive metadata (description, capabilities, and its free-form | ||
| name, which seeds the mutable MLflow-managed `display_name`) into |
There was a problem hiding this comment.
Do we want display name here? I think @B-Step62 had objections to that for skill registry.
| generally), and recording that URL lets the registry drive tracing | ||
| and evaluation for agents whose code the user cannot run. But | ||
| endpoints change independently of composition, and agent versions | ||
| are immutable. Following RFC-0004's `MCPAccessBinding` model, |
There was a problem hiding this comment.
This was renamed to "access endpoint" right?
| per deployment, so the question is which behavior makes the better | ||
| default, not which is possible. | ||
|
|
||
| - **How thin may an interface-only record be?** A black-box A2A |
There was a problem hiding this comment.
I think as thin as possible but encourage a description so there is some human/agent readable field for what this agent is.
| should the registry require anything more of it before such a | ||
| record can be promoted to `active`? | ||
|
|
||
| - **Should agent-centric traces and evaluations be a separate RFC?** |
| prefer a narrower registry RFC, the journey splits cleanly along | ||
| the RFC-0008/0009 seam. | ||
|
|
||
| - **Do endpoint records belong in MLflow at all?** The access binding |
There was a problem hiding this comment.
I'd like MLflow to be the glue for all different systems that define and serve agents. MLflow should be an authoritative source but a pointer to them like the A2A endpoint. Making this more customizable without persisting runtime data makes MLflow very valuable here.
| answers there" belongs to the platform, and that without endpoints | ||
| the registry cannot trace or evaluate agents whose code the user | ||
| cannot run. This boundary needs explicit review. A related | ||
| sub-question: when an agent is exposed as an MCP server, should an |
| them, going beyond the source-centric design the journeys otherwise | ||
| follow: a harness reference axis in the BOM (an external | ||
| identifier, like external model references), an immutable | ||
| configuration snapshot stored as a version artifact to serve as the |
There was a problem hiding this comment.
As mentioned in a previous comment, I think this configuration is better stored in Git or another external system and not MLflow.
| - Does configuration-as-artifact belong in this RFC or a | ||
| follow-on? | ||
|
|
||
| - **Should a version record multiple sources?** This RFC says yes: a |
First draft of RFC-0011: Agent Registry, a follow-on to RFC-0004 (MCP Server Registry) and RFC-0008 (Skill Registry).
This draft deliberately covers only the introductory material and user journeys, in the style of the RFC-0009 and RFC-0010 drafts (#37, #27). Detailed design, drawbacks, alternatives, and adoption strategy are TBD.
What the draft contains:
AgentandAgentVersionentities. Each version snapshots a composition (BOM: skill, MCP server, model, and proposed harness references) plus at least one definitional anchor (source provenance, configuration snapshot, or A2A Agent Card).MCPAccessBinding) carrying a URL plus protocol (a2a,mcp,other), never fields on immutable versions.MlflowAgentLocationtrace destination), lifecycle management, and cross-registry blast-radius queries.Authored by Bill Murdock with assistance from Claude Code.
🤖 Generated with Claude Code