# Maintain Dynamic Plugins

> Change NeMo Relay dynamic plugin loaders, manifests, native ABI, gRPC worker protocol, or Python worker SDK. Do not use for ordinary built-in plugin configuration.

- Skill: `nvidia/maintain-dynamic-plugins` (Agent Skill)
- Install (CLI): `npx skillmds@latest add nvidia/maintain-dynamic-plugins`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nvidia/maintain-dynamic-plugins/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: Apache-2.0
- Author: NVIDIA (https://skillmd.com/u/nvidia)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/nvidia/maintain-dynamic-plugins

---


# Maintain Dynamic Plugins

Use this skill for `plugin.kind = "rust_dynamic"`, `plugin.kind = "worker"`,
`nemo-relay-plugin`, `nemo-relay-worker`, `nemo-relay-worker-proto`,
`nemo-relay-types`, and the Python `nemo-relay-plugin` package.

## Rules

- Keep the stable boundary explicit: native plugins cross a C ABI; worker
  plugins cross `grpc-v1`.
- Do not pass Rust runtime types, trait objects, futures, or allocator-owned
  strings across the native dynamic-library boundary.
- Typed native middleware futures run on the SDK-owned Tokio executor. Keep
  subscribers synchronous and preserve raw synchronous ABI registrations.
- Define closed worker transport structures in protobuf when generated clients
  must enforce their fields. Keep open application payloads lossless by using
  `JsonValue` or `JsonEnvelope` rather than `google.protobuf.Value`.
- Keep `relay-plugin.toml` dynamic records separate from generic runtime
  components. Enabled dynamic records may synthesize internal component specs;
  disabled records stay inspectable but unloaded.
- Relay 0.8 establishes the native API 1 and `grpc-v1` canonical
  `ToolExecutionResult` baseline. Require every dynamic plugin to rebuild and
  declare a `compat.relay` range that excludes versions before 0.8. Recommend
  `>=0.8.0,<1.0`; open-ended or narrower 0.8-or-newer ranges are valid.
- Treat `compat.relay` as the plugin author's compatibility assertion, not
  proof that an artifact was rebuilt. Do not add a legacy raw-result adapter.
- Relay 0.8 retains the `grpc-v1` identifier and
  `nemo.relay.worker.v1` package while changing the tool-result protobuf types;
  every worker must regenerate its bindings and rebuild. Native ABI v4 permits
  append-only host-table extensions guarded by `struct_size`; existing fields
  must remain frozen at their original offsets. Incompatible native JSON,
  reordered or replaced native fields, or incompatible worker protobuf changes
  must bump `native_api` or `worker_protocol`.
- Do not add tests under `src`; Rust tests belong in crate `tests/` trees and
  Python SDK tests belong under `python/tests`.
- Native and worker plugins are trusted extensions. Document that native plugins
  are in-process and unsandboxed; worker plugins provide process isolation but
  not a security sandbox.

## Checklist

- [ ] Manifest validation covers kind, compatibility, load contract, integrity,
      capability mismatch, and disabled-plugin behavior.
- [ ] Native loader keeps libraries alive until registered callbacks are cleared
      and deregisters plugin kinds before unload.
- [ ] Worker activation covers process launch, token auth, handshake, validation,
      declarative registration, proxy rollback, cancellation, and shutdown.
- [ ] Rust and Python SDKs expose every supported registration surface.
- [ ] Runtime helpers cover marks, scopes, continuations, and isolated scope
      stacks.
- [ ] `plugins list`, `plugins inspect`, and `plugins validate` report lifecycle
      and compatibility status without leaking secret config.
- [ ] Top-level `doctor` reports resolved dynamic plugin and host configuration
      status.
- [ ] When detailed dynamic plugin guides exist, they keep Rust native, Python
      worker, and `grpc-v1` protocol details on separate pages.
- [ ] `justfile`, Codecov, and CI package/test workflows include new plugin
      crates and packages.

## Validation

Choose checks by the changed layer:

- Manifest or shared types: test the owning Rust crate.
- Native loader or ABI: prepare plugin fixtures and run the focused native
  plugin integration test.
- Worker protocol or host: test the worker crates and regenerate or test the
  Python worker SDK only when its protocol surface changes.
- Shared runtime behavior: run the Rust suite and only binding suites whose
  observable plugin behavior changes.
- Documentation or packaging: run their targeted checks only when changed.

Canonical surface suites prepare plugin fixtures. Before a raw focused native
or worker integration test, run `just build-test-plugin-fixtures`; never compile
fixtures inside an individual test case.

## References

- `crates/core/src/plugin/dynamic/`
- `crates/plugin`
- `crates/worker`
- `crates/worker-proto`
- `crates/types`
- `python/plugin`
- `examples/rust-native-plugin`
- `docs/build-plugins`
- `examples/python-grpc-worker-plugin`

