Skip to content

Hoist _meta onto CustomizationBase so every customization type carries provider metadata uniformly #316

Description

@colbylwilliams

Summary

_meta exists on exactly one customization type. AgentCustomization has a _meta slot ("Additional provider-specific metadata for this custom agent. Mirrors the MCP _meta convention"); no other customization type does. So a host with provider-specific metadata for a plugin, directory, skill, rule, hook, prompt, or MCP server has no escape hatch, while an agent does — an asymmetry with no obvious justification.

This proposes hoisting _meta onto the shared CustomizationBase so every customization type carries one uniformly, and dropping the now-redundant per-type declaration on AgentCustomization.

Current state in the spec

types/channels-session/state.ts:

interface CustomizationBase {
  id: string;
  uri: URI;
  name: string;
  icons?: Icon[];
  range?: TextRange;
  // no _meta
}

export interface AgentCustomization extends ChildCustomizationBase {
  type: CustomizationType.Agent;
  description?: string;
  model?: string;
  tools?: string[];
  disableModelInvocation?: boolean;
  disableUserInvocation?: boolean;
  _meta?: Record<string, unknown>; // the ONLY customization type with _meta
}

Every other customization — PluginCustomization, DirectoryCustomization, SkillCustomization, PromptCustomization, RuleCustomization, HookCustomization, McpServerCustomization, and ClientPluginCustomization — extends a base that has no _meta, so none of them can carry provider-specific metadata.

Proposal

Move _meta from AgentCustomization up to CustomizationBase, so all customization types inherit it:

interface CustomizationBase {
  id: string;
  uri: URI;
  name: string;
  icons?: Icon[];
  range?: TextRange;
  /**
   * Additional provider-specific metadata for this customization.
   * Mirrors the MCP `_meta` convention. Optional and opaque to the
   * protocol; producers and consumers agree on its contents
   * out-of-band.
   */
  _meta?: Record<string, unknown>;
}

export interface AgentCustomization extends ChildCustomizationBase {
  type: CustomizationType.Agent;
  description?: string;
  model?: string;
  tools?: string[];
  disableModelInvocation?: boolean;
  disableUserInvocation?: boolean;
  // _meta now inherited from CustomizationBase
}

Every customization type then has the same provider-specific escape hatch, matching the _meta convention already established elsewhere in AHP state.

Note this is deliberately the generic fallback, not a substitute for first-class fields: data that has a natural native home should still get a typed field (see the version-on-PluginCustomization companion ask), and _meta is reserved for genuinely provider-specific data with no first-class AHP field. Making the slot available uniformly just means a host isn't forced to drop such data for every type except agents.

Relationship to existing issues

  • Add a _meta slot to SystemNotificationResponsePart for machine-readable trigger metadata #307 (_meta on SystemNotificationResponsePart) is the parallel precedent for adding a _meta slot where a type lacks one; this generalizes that across the whole customization family instead of a one-off.
  • Companion ask: a native version field on PluginCustomization (filed separately). That one intentionally does not use _meta — a plugin version is a first-class attribute — so the two are complementary: native fields where a concept fits, _meta as the uniform fallback everywhere else.

Backwards compatibility

Purely additive and wire-compatible. Moving _meta from AgentCustomization to CustomizationBase leaves the key, shape, and semantics unchanged, and AgentCustomization still exposes _meta (now by inheritance). Every other customization type simply gains the optional slot; existing producers/consumers are unaffected until they populate or read it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions