Skip to content

Feat: adding capabilities and Common Message Format to plugin framework#8

Open
terylt wants to merge 4 commits intomainfrom
feat/capabilities_cmf
Open

Feat: adding capabilities and Common Message Format to plugin framework#8
terylt wants to merge 4 commits intomainfrom
feat/capabilities_cmf

Conversation

@terylt
Copy link
Contributor

@terylt terylt commented Mar 20, 2026

Summary

As the plugin framework grows to support multi-tenant deployments, security-sensitive
workloads, and diverse authentication methods, plugins increasingly need access to
contextual metadata — who is making the request, what security labels apply, which
HTTP headers were sent, what agent is orchestrating the call. Today this metadata is
either unavailable to plugins or scattered across payload fields (like the
now-deprecated headers). Extensions solve this by providing a single, structured
envelope of contextual metadata that travels alongside every hook invocation. But not
every plugin should see everything — a logging plugin doesn't need the user's security
clearance, and no plugin should be able to forge identity claims. Capabilities govern
this: each plugin declares what it can read and write, and the framework enforces
those boundaries automatically. Together, extensions and capabilities give plugin
authors rich context while giving platform operators fine-grained control over what
each plugin can access and modify.

  • Introduces a typed Extensions system (cpex/framework/extensions/) with optional
    metadata slots — security (subject, labels, classification, objects, data), HTTP
    headers, agent context, MCP metadata, provenance, request context, LLM parameters, and
    custom fields — that flow through the plugin pipeline as structured, frozen Pydantic
    models
  • Implements a capability-based access control tier system with three mutability
    levels:
    • Immutable (request, provenance, subject, objects, data, classification) — plugins
      can read with the right capability but never modify
    • Monotonic (security labels) — plugins can append but never remove; enforced via
      superset validation on merge
    • Mutable (HTTP headers, agent, custom) — plugins with write capabilities can freely
      modify
  • Build-up filtering (filter_extensions) constructs a new Extensions from empty,
    copying in only the slots the plugin's declared capabilities grant access to — secure
    by default, new slots are hidden unless explicitly included
  • Selective merge (merge_extensions) controls what the manager accepts back from
    plugins: immutable slots silently ignored, monotonic slots validated for superset,
    mutable slots accepted — no costly before/after diff needed
  • SlotName enum and FIELD_* constants in constants.py provide a single source of truth
    for all slot registry keys and Pydantic field names, preventing typo-induced
    duplicates
  • Optional third-argument dispatch — plugins opt into receiving extensions by adding
    an extensions parameter to their hook method; the signature is inspected once at
    registration time and stored as a boolean on HookRef, with a single branch at
    dispatch. All 30+ existing 2-param plugins work unchanged with zero overhead.
    Extensions are filtered per-plugin via filter_extensions(extensions,
    plugin.capabilities) at the dispatch site
  • Extensions are passed separately from the payload — the payload stays immutable and
    shared across all plugins (zero copies unless a plugin modifies it); only the small
    Extensions object is filtered/copied per-plugin. This maps directly to Rust's
    Arc + per-plugin stack value pattern
  • Adds the Common Message Format (CMF) — frozen Message and MessageView models for
    multi-modal conversations, with message hooks (message_pre_invoke,
    message_post_invoke) for pipeline processing
  • Adds deprecation warnings on redundant headers fields across HTTP, agent, and tool
    payloads (superseded by extensions.http.headers), using
    warnings.warn(DeprecationWarning) which fires once per call site

Test plan

  • python -m pytest tests/ -x -q --tb=short — all 1159 tests pass
  • Verify existing 2-param plugins work unchanged (no extensions argument required)
  • Verify 3-param plugins receive filtered extensions based on declared capabilities
  • Verify tier enforcement: immutable slots ignored on merge, monotonic validated for
    superset, mutable accepted
  • Verify filter_extensions builds up from empty — undeclared capabilities produce None
    slots
  • Verify merge_extensions silently drops immutable slot changes and rejects label
    removal
  • Verify deprecation warnings fire once per call site (no log spam)

@terylt terylt force-pushed the feat/capabilities_cmf branch from 7e41bd8 to 5768444 Compare March 20, 2026 17:42
@terylt terylt changed the base branch from main to feat/cmf March 20, 2026 17:53
Teryl Taylor added 4 commits March 20, 2026 12:01
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
@terylt terylt force-pushed the feat/capabilities_cmf branch from 5768444 to ac6fdde Compare March 20, 2026 18:05
@terylt terylt changed the base branch from feat/cmf to main March 20, 2026 18:06
@araujof araujof marked this pull request as ready for review March 20, 2026 18:18
@araujof araujof self-requested a review as a code owner March 20, 2026 18:18
@araujof araujof self-assigned this Mar 20, 2026
@araujof araujof added enhancement New feature or request framework labels Mar 20, 2026
@araujof araujof added this to the 0.1.0 milestone Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants