Skip to content

Plugin SDK

BoardReadyOps plugins let teams add rules, adapters, vendor profiles, report formats, and notifiers without forking the core repository. Plugins are normal Node.js packages or local JavaScript files that export a BoardReadyOpsPlugin object.

The SDK package exists in this repository under packages/plugin-sdk. It is used by the checked-in example through the pnpm workspace and is not published as a standalone npm package yet; npm view @boardreadyops/plugin-sdk currently returns 404. Use a local workspace or file dependency until a release publishes that package.

corepack pnpm --filter boardreadyops-plugin-custom-rule install

Define the plugin with definePlugin:

import { definePlugin } from "@boardreadyops/plugin-sdk";

export default definePlugin({
  name: "boardreadyops-plugin-custom-rule",
  version: "1.0.0",
  rules: [
    {
      meta: {
        id: "plugin.hello-world",
        title: "Plugin hello world",
        description: "Demonstrates a third-party rule plugin.",
        rationale: "Plugin rules can run with the same project context as built-in rules.",
        defaultSeverity: "info",
        appliesTo: ["project"],
        configKeys: [],
        kicadVersions: ["9", "10", "future"],
        tags: ["plugin"],
      },
      async run(context) {
        return [
          {
            ruleId: "plugin.hello-world",
            severity: "info",
            message: "Hello from a BoardReadyOps plugin.",
            project: context.projects[0]?.projectFile,
            resource: { path: context.projects[0]?.projectFile ?? ".", kind: "project" },
            confidence: "definite",
          },
        ];
      },
    },
  ],
});

The same example is available in examples/plugin-custom-rule/.

The generated API reference for exported SDK types and extension points is available in Plugin SDK API. Regenerate it with corepack pnpm run api:docs after changing packages/plugin-sdk/src/index.ts; corepack pnpm run gc fails when the checked-in API reference is stale.

Loading Plugins

Declare explicit plugins in boardreadyops.yml:

version: 1
plugins:
  - "@boardreadyops/plugin-altium-import"
  - "@boardreadyops/plugin-eagle-compat"
  - "./local-rules/custom-fab-check.js"

BoardReadyOps also auto-discovers installed packages named @boardreadyops/plugin-* or boardreadyops-plugin-*, and local JavaScript plugins under ./local-rules/*.js. The SDK package itself, @boardreadyops/plugin-sdk, is ignored during auto-discovery because it provides types and definePlugin, not a runtime plugin.

Explicit config entries load first, followed by discovered package plugins and local plugins. Duplicate specifiers are ignored. Duplicate rule IDs from different plugins are reported as configuration findings.

Packaging

Use one of the supported naming conventions:

  • Scoped package: @boardreadyops/plugin-your-name
  • Unscoped package: boardreadyops-plugin-your-name
  • Local file: ./local-rules/your-check.js

A minimal package should expose an ESM entrypoint:

{
  "name": "boardreadyops-plugin-custom-rule",
  "version": "1.0.0",
  "type": "module",
  "exports": {
    ".": "./index.js"
  },
  "dependencies": {
    "@boardreadyops/plugin-sdk": "file:../boardreadyops/packages/plugin-sdk"
  }
}

The dependency path is illustrative: replace it with the relative path from the plugin package to the BoardReadyOps checkout, or with the published SDK version after @boardreadyops/plugin-sdk exists on npm. Before publishing, run the plugin's own lint, typecheck, and tests. Consumers should pin plugin versions in their package manager lockfile so CI runs the same plugin code as local development.

Trust Boundary

Plugins run in the same Node.js process as BoardReadyOps. They can read files available to the current process, run arbitrary JavaScript, and affect runtime behavior by registering rules or other extension points. Install plugins only from sources you trust, review local plugins like application code, and keep plugin dependencies updated.

BoardReadyOps validates the exported plugin shape with Zod before registering rules. Validation catches malformed metadata and missing plugin fields, but it is not a sandbox and does not restrict plugin code execution.

Plugin trust model

BoardReadyOps v1 treats plugins and local rules as trusted workspace code. The permission model is an audit and approval mechanism: it records requested capabilities, allows maintainers to deny unexpected capabilities, and prevents registration when declared permissions are not approved. It does not yet provide process-level isolation, syscall filtering, network egress control, or a JavaScript runtime sandbox.

Only install or enable plugins from sources you review and trust. In CI, prefer explicit plugin lists in boardreadyops.yml, keep dependency updates reviewed, and treat any plugin that requests fs:write, network, process, or kicad-cli as security-sensitive. Runtime plugin isolation may be added in a later major release if the extension ecosystem grows beyond trusted project-local plugins.

Current Extension Points

rules are active today and are registered into the BoardReadyOps rule registry. The SDK also reserves shapes for adapters, reportFormats, vendorProfiles, notifiers, and supplierProviders so plugin packages can expose those objects as the runtime integration points mature.

Supplier Intelligence Providers

Plugins can contribute supplierProviders to enrich BOM risk analysis with real-time or static availability, lifecycle, and compliance data. The contract is provider-neutral: BoardReadyOps core never calls a specific commercial API directly.

import { definePlugin, type SupplierIntelligenceProvider } from "@boardreadyops/plugin-sdk";

const myProvider: SupplierIntelligenceProvider = {
  id: "my-supplier-api",
  name: "My Supplier API",
  requiresNetwork: true,
  async query(input) {
    const records = new Map();
    for (const { reference, mpn } of input.components) {
      if (!mpn) { continue; }
      // Call your API here...
      records.set(mpn.toUpperCase(), {
        mpn,
        lifecycleStatus: "active",
        supplierCount: 3,
        available: true,
        trust: "verified",
        fetchedAt: new Date().toISOString(),
      });
    }
    return { records, queriedAt: new Date().toISOString() };
  },
};

export default definePlugin({
  name: "boardreadyops-plugin-my-supplier",
  version: "1.0.0",
  permissions: ["network"],
  supplierProviders: [myProvider],
});

Static supplier database

For projects without a live supplier API, use the built-in createStaticSupplierProvider to load a committed JSON database:

import { createStaticSupplierProvider } from "boardreadyops/bom/supplier";

const provider = createStaticSupplierProvider({
  dataFile: ".boardreadyops/supplier-db.json",
  name: "Project Supplier Database",
});

The database file format:

{
  "schemaVersion": 1,
  "updatedAt": "2026-06-01T00:00:00.000Z",
  "records": [
    {
      "mpn": "TPS62840DLCT",
      "manufacturer": "Texas Instruments",
      "lifecycleStatus": "active",
      "supplierCount": 5,
      "available": true,
      "alternates": ["TPS62840DLCR"],
      "restrictedSubstances": false,
      "complianceNotes": ["RoHS compliant"],
      "leadTimeWeeks": 8,
      "trust": "verified"
    }
  ]
}

Supported lifecycleStatus values: active, nrnd (not recommended for new designs), last-time-buy, eol (end of life), obsolete, unknown.

Supported trust values: verified, estimated, unverified, unknown.

The provider warns when the database is older than 90 days.

Provider trust and freshness warnings

Providers include trust and fetchedAt on each record. The buildSupplierIntelligenceSummary helper aggregates results across providers and produces per-component lifecycle warnings and a freshness status (fresh, stale, unknown). These are surfaced in the BOM risk report section for PR comments and the dashboard.

rules are active today and are registered into the BoardReadyOps rule registry. The SDK also reserves shapes for adapters, reportFormats, vendorProfiles, and notifiers so plugin packages can expose those objects as the runtime integration points mature.

Rule Packs

Rule packs are lightweight, versioned configuration bundles that enable/disable rules and set defaults for a specific release context. Unlike full plugins, rule packs do not ship rule implementations — they layer on top of the existing built-in rule set.

What a rule pack can do

  • Enable or disable any built-in rule.
  • Override the default severity of any rule.
  • Set configuration defaults for rule-specific options.
  • Declare a vendorProfile to activate when the pack is applied.
  • Declare a releaseMode (prototype, pilot, production).
  • Carry compatibility metadata to ensure the pack is only loaded by compatible BoardReadyOps versions.

YAML rule pack format

Rule packs can be written as standalone YAML files and referenced from boardreadyops.yml. The full schema is in schemas/rule-pack.schema.json at the repository root.

id: com.example.prototype-ready
name: "Prototype Ready"
version: "1.0.0"
description: >
  Enables the most important checks for a first-build prototype while silencing
  rules that are only relevant to production manufacturing.
tags:
  - prototype
compatibility:
  boardreadyopsMin: "1.8.0"
  kicadVersions:
    - "9"
    - "10"
    - "future"
rules:
  bom.missing-mpn: true
  bom.lifecycle: true
  bom.compliance:
    enabled: true
    severity: low
  manufacturing.tooling-holes: false
  manufacturing.test-points: false

TypeScript defineRulePack() helper

Rule packs can also be expressed in TypeScript when bundled inside a plugin package, giving you full type-checking via the SDK:

import { defineRulePack } from "@boardreadyops/plugin-sdk";

export const prototypeReadyPack = defineRulePack({
  id: "com.example.prototype-ready",
  name: "Prototype Ready",
  version: "1.0.0",
  description: "First-build prototype preset.",
  rules: {
    "bom.missing-mpn": true,
    "bom.lifecycle": { enabled: true, severity: "low" },
    "manufacturing.tooling-holes": false,
  },
});

Expose the pack from your plugin's rulePacks array:

import { definePlugin } from "@boardreadyops/plugin-sdk";
import { prototypeReadyPack } from "./packs/prototype-ready.js";

export default definePlugin({
  name: "boardreadyops-plugin-example",
  version: "1.0.0",
  rulePacks: [prototypeReadyPack],
});

Built-in example rule packs

The examples/rule-packs/ directory contains ready-to-copy YAML rule pack presets:

File Purpose
prototype-fab.yml First-build prototype with low friction
production-fab.yml Full production-mode checks
assembly-ready.yml Contract manufacturer assembly handoff
open-hardware.yml Open hardware community release
contract-handoff.yml Design-house-to-client delivery evidence bundle

Merge order and precedence

When multiple rule packs are active (e.g., from multiple plugins), BoardReadyOps merges their rules maps in pack registration order. Later entries win. Project-level boardreadyops.yml rule overrides always take precedence over any rule pack setting.

Versioning and deprecation

Pack authors should follow semver. A new major version signals breaking changes such as a renamed rule ID or a removed rule. When a rule ID is renamed, keep the old ID in the pack as false and the new ID as true so consumers upgrading do not silently lose coverage.

Security boundary

Rule packs are configuration only. They cannot execute arbitrary code, access the file system, or affect plugin loading. A YAML rule pack loaded from disk is parsed and validated against the JSON schema before any rules are applied. A TypeScript rule pack bundled inside a plugin inherits that plugin's trust boundary — see Plugin trust model above.