Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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: |
Expand Down
91 changes: 90 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -63,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
Expand Down
12 changes: 12 additions & 0 deletions plugin_config.packages.example.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
Loading