From 5e17a5294177098327fc67bcf1c5c72bae7076f1 Mon Sep 17 00:00:00 2001 From: BIN Zhang Date: Mon, 16 Mar 2026 01:18:18 +0800 Subject: [PATCH 1/2] feat: validate plugin config examples with matrix --- .github/workflows/validate.yml | 26 ++++++++++++++++++++++++-- README.md | 4 +++- plugin_config.packages.example.json | 12 ++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 plugin_config.packages.example.json diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7f03da7..c9e27a6 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -6,8 +6,13 @@ on: pull_request: jobs: - validate: + validate-plugin-config: runs-on: ubuntu-latest + strategy: + matrix: + config_file: + - plugin_config.example.json + - plugin_config.packages.example.json steps: - name: Checkout repository @@ -25,7 +30,24 @@ jobs: - name: Validate plugin config example run: | - python validation/scripts/validate_plugin_config.py + python validation/scripts/validate_plugin_config.py "${{ matrix.config_file }}" + + validate: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + + - name: Setup Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 + with: + python-version: "3.11" + + - name: Install POP CLI + run: | + python -m pip install --upgrade pip + pip install -e ".[schema]" - name: Validate all example POP objects run: | diff --git a/README.md b/README.md index 8246efa..a70682a 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,9 @@ external plugin packages. By default, the runtime looks for a local `plugin_config.json` file at the repository root if present. An example template is available at [`plugin_config.example.json`](plugin_config.example.json), and the config shape is defined by -[`plugin_config.schema.json`](plugin_config.schema.json). +[`plugin_config.schema.json`](plugin_config.schema.json). A second example, +[`plugin_config.packages.example.json`](plugin_config.packages.example.json), +shows the variant where package names and package search paths are listed separately. The example config is also validated in CI so schema drift is caught during PR review. For temporary overrides, you can also point discovery at external plugin diff --git a/plugin_config.packages.example.json b/plugin_config.packages.example.json new file mode 100644 index 0000000..13e65ba --- /dev/null +++ b/plugin_config.packages.example.json @@ -0,0 +1,12 @@ +{ + "$schema": "./plugin_config.schema.json", + "plugin_paths": [], + "plugin_packages": [ + "pop_demo_plugins", + "pop_extra_plugins" + ], + "plugin_package_paths": [ + "./plugins/pop_demo_plugins", + "./plugins/pop_extra_plugins" + ] +} From 90f008b1c38791af6ce28fd66ad428acdc40dfc9 Mon Sep 17 00:00:00 2001 From: Bin Zhang <138868899+joy7758@users.noreply.github.com> Date: Mon, 16 Mar 2026 01:25:48 +0800 Subject: [PATCH 2/2] docs: expand plugin extension tutorial (#25) --- README.md | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/README.md b/README.md index a70682a..aadf154 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,93 @@ install the optional schema dependency: pip install "pop-persona[schema]" ``` +### Plugin Extension Tutorial + +The demo registry loads definitions from three extension surfaces: + +- `STAGE_HANDLER_DEFINITIONS` for stage handlers +- `PERSONA_DEFINITIONS` for builtin or external persona registry entries +- `TASK_TYPE_DEFINITIONS` for task-type metadata and stage routing + +Discovery order is: + +1. builtin `demos` modules +2. packages from `plugin_config.json` or `POP_PLUGIN_CONFIG_FILE` +3. package names and search paths from `POP_PLUGIN_PACKAGES` and `POP_PLUGIN_PACKAGE_PATHS` + +Environment variables act as an override layer on top of file-based config. + +#### Config Shape 1: `plugin_paths` + +Use this when each plugin package is easiest to describe as a single +`path` plus `package_name` pair. + +```json +{ + "$schema": "./plugin_config.schema.json", + "plugin_paths": [ + { + "path": "/tmp/pop_demo_plugins", + "package_name": "pop_demo_plugins" + } + ], + "plugin_packages": [], + "plugin_package_paths": [] +} +``` + +This is the shape shown in +[`plugin_config.example.json`](plugin_config.example.json). + +#### Config Shape 2: `plugin_packages` + `plugin_package_paths` + +Use this when package names and import search paths need to be managed +separately. + +```json +{ + "$schema": "./plugin_config.schema.json", + "plugin_paths": [], + "plugin_packages": [ + "pop_demo_plugins", + "pop_extra_plugins" + ], + "plugin_package_paths": [ + "./plugins/pop_demo_plugins", + "./plugins/pop_extra_plugins" + ] +} +``` + +This is the shape shown in +[`plugin_config.packages.example.json`](plugin_config.packages.example.json). + +#### Field Notes + +- `plugin_paths`: Array of either plain path strings or objects with `path` and optional `package_name`. +- `plugin_packages`: Import package names to scan for `*_DEFINITIONS` exports. +- `plugin_package_paths`: Filesystem paths added to `sys.path` before plugin package imports. +- `path`: A relative path is resolved from the config file directory; an absolute path is used as-is. +- `package_name`: Optional for `plugin_paths` entries, but required if the path alone is not enough to identify the package to import. + +#### How To Add A Plugin Package + +1. Create a Python package that exposes one or more of: + `STAGE_HANDLER_DEFINITIONS`, `PERSONA_DEFINITIONS`, `TASK_TYPE_DEFINITIONS`. +2. If a persona definition points to a JSON file, keep the JSON inside the + plugin package and set `package_name` on the `PersonaDefinition` so the + runtime can resolve the relative file path correctly. +3. Add the package to `plugin_config.json`, or point the runtime at it with + `POP_PLUGIN_CONFIG_FILE`, `POP_PLUGIN_PACKAGES`, and `POP_PLUGIN_PACKAGE_PATHS`. +4. Run the demo against a task that references the new `task_type`. + +Example: + +```bash +POP_PLUGIN_CONFIG_FILE=/tmp/pop_demo_plugins/plugin_config.json \ +python demos/persona_workflow_demo.py --task-input /tmp/content_strategy_task.json +``` + ## Persona Layer Diagram ```mermaid