feat(policy): support native PolicyPlugin exports from module files#141
Merged
digitarald merged 3 commits intoMay 10, 2026
Merged
Conversation
Allow policy modules to export a native PolicyPlugin object (with detectors, hooks, and recommenders) instead of being limited to the PolicyConfig DSL. Changes: - isNativePlugin() type guard with validation of meta fields - validateNativePlugin() with thorough hook/array/type checking - loadPolicy() returns PolicyConfig | PolicyPlugin union - loadPluginChain() detects and adds native plugins directly - readiness auto-enables engine path when native plugins are present - pathToFileURL fix for Windows dynamic import Tests: 671 passing (34 new tests for type guard, validation, and loader) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- normalizeNativePlugin now unconditionally forces sourceType/trust instead of conditional defaults, preventing plugins from claiming misleading sourceType (e.g. 'builtin') when loaded from modules - Add missing onError validation test - Add isNativePlugin test for ambiguous object with both name and meta - Add direct loadPolicy() test for native plugin return path - Update loadPolicy JSDoc to reflect normalization behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds support for policy module files (and npm specifiers) to export a native PolicyPlugin object directly, enabling full engine pipeline behavior (detectors/hooks/recommenders) beyond the PolicyConfig DSL.
Changes:
- Extend policy loading to detect/validate native
PolicyPluginexports and normalizemeta.sourceType/meta.trust. - Update loader/readiness flow to incorporate native plugins into the engine path and expose new type-guard/validation utilities.
- Add/expand tests covering native plugin detection, validation, normalization, and loader/engine integration.
Show a summary per file
| File | Description |
|---|---|
src/services/__tests__/policy.test.ts |
Adds helper to assert PolicyConfig loads, plus a direct native-plugin .mjs load test. |
src/services/__tests__/policy-loader.test.ts |
Adds integration tests for native plugin loading/normalization and engine execution. |
src/services/__tests__/policy-engine-types.test.ts |
Adds unit tests for isNativePlugin and validateNativePlugin edge cases. |
packages/core/src/services/readiness/index.ts |
Skips native plugins in DSL resolution and auto-enables engine path when native plugins are present. |
packages/core/src/services/policy/types.ts |
Introduces isNativePlugin and validateNativePlugin for detection and load-time validation. |
packages/core/src/services/policy/loader.ts |
Updates plugin chain loader to accept native plugin exports directly. |
packages/core/src/services/policy/index.ts |
Re-exports isNativePlugin / validateNativePlugin from the policy public API. |
packages/core/src/services/policy.ts |
Updates loadPolicy() to return `PolicyConfig |
Copilot's findings
- Files reviewed: 8/8 changed files
- Comments generated: 2
Comment on lines
+273
to
+276
| obj.afterRecommend; | ||
| if (!hasHooks) { | ||
| throw new Error( | ||
| `Native plugin "${source}" is invalid: must implement at least one hook (detectors, afterDetect, beforeRecommend, recommenders, or afterRecommend)` |
Comment on lines
211
to
214
| if (jsonOnly) { | ||
| throw new Error( | ||
| `Policy "${source}" rejected: only JSON policies are allowed from agentrc.config.json. Module policies (.ts/.js) must be passed via --policy.` | ||
| ); |
github-actions Bot
added a commit
that referenced
this pull request
May 11, 2026
- Extract resolveNativePlugin() helper in policy.ts to deduplicate the repeated validateNativePlugin + normalizeNativePlugin call pair - Remove redundant meta spread in loadPluginChain (loadPolicy already normalizes sourceType/trust via normalizeNativePlugin before returning) - Replace options parameter reassignment in runReadinessReport with a local shadow boolean variable for clearer intent Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
github-actions Bot
added a commit
that referenced
this pull request
May 11, 2026
Add documentation for the native PolicyPlugin export feature introduced in #141, which allows .ts/.js/.mjs module files and npm packages to export a full PolicyPlugin object instead of being limited to the PolicyConfig DSL. - docs/dev/plugins.md: Add native plugin authoring section with a complete TypeScript example showing detectors, hooks, and recommenders. Update authoring API list from two to three options. - docs/concepts.md: Mention native plugin support in the Policies overview and add a TypeScript policy example to the code block. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced May 11, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Supersedes #115 — merges the original PR by @yxbh and adds review-driven improvements.
Allow policy modules to export a native
PolicyPluginobject (with detectors, hooks, and recommenders) instead of being limited to thePolicyConfigcriteria DSL.Changes from #115 (original)
packages/core/src/services/policy/types.tsisNativePlugin()type guard,validateNativePlugin()with thorough hook/array/type checkingpackages/core/src/services/policy/index.tspackages/core/src/services/policy.tsloadPolicy()returnsPolicyConfig | PolicyPluginunion,pathToFileURLfix for Windowspackages/core/src/services/policy/loader.tsloadPluginChain()detects and adds native plugins directlypackages/core/src/services/readiness/index.tsReview improvements (this PR)
Hardened
normalizeNativePlugin: Changed from conditional defaults (??) to unconditional forced values forsourceType: "module"andtrust: "trusted-code". Previously a plugin could claimsourceType: "builtin"andnormalizeNativePluginwould preserve it — now it's overwritten consistently with the loader's security enforcement.Added missing
onErrorvalidation test:validateNativePluginvalidatesonErrorbut had no test coverage for this path.Added
isNativePluginedge case test: Objects with both root-levelnameandmeta(ambiguous shape) are correctly classified asPolicyConfig, not native plugins.Added direct
loadPolicy()native plugin test: VerifiesloadPolicy()returns a properly normalizedPolicyPluginwhen given a.mjsnative export — previously only tested throughloadPluginChain().Updated JSDoc to reflect the unconditional normalization behavior.
Why
The
PolicyConfigDSL (criteria.add/disable/override) is great for simple checks but can't express:afterDetecthooks (SignalPatch)Native
PolicyPluginexports unlock the full 5-stage engine pipeline for external policy authors.Testing
Remaining items for follow-up
validateNativePlugindoesn't validate detectorkindfield (intentional — runtime flexibility)