Step 1: Create the Plugin Directory

Choose a plugin source directory (see Configuration). Create a subdirectory for your plugin:

plugins/
└── my_plugin/
    ├── manifest.yaml
    └── data/
        └── my_plugin.json

Step 2: Write the Manifest

Create a manifest.yaml with the required fields:

name: my_plugin
description: My custom enrichment data
version: 1.0.0
format: json
key: psgc_id
Field Required Description
name Yes Unique plugin identifier
description No Human-readable description
version No Plugin version
format Yes Data format: csv, json, or parquet
key Yes Join key column (typically psgc_id)
repository No GitHub URL for remote plugins
ref No Git ref (default: main)
current No Current version date for time-aware plugins
dates No List of available snapshot dates

Step 3: Add the Data File

JSON format

[
  { "psgc_id": "0731100000", "my_field": "my_value" },
  { "psgc_id": "1300000000", "my_field": "another_value" }
]

CSV format

psgc_id,my_field
0731100000,my_value
1300000000,another_value

Parquet format

A Parquet file with the same column layout.

The key column (psgc_id) is used for joining and is excluded from the output fields.

Step 4: Enable the Plugin

Add it to plugins.yaml:

plugins:
  - name: my_plugin
    enabled: true

Or enable it on the CLI with --plugin my_plugin.

Time-Aware Plugins

For versioned data, use YYYY-MM-DD/ subdirectories:

my_plugin/
├── manifest.yaml
└── data/
    ├── 2025-01-01/
    │   └── my_plugin.json
    └── 2025-07-01/
        └── my_plugin.json

Include current and dates in the manifest:

name: my_plugin
format: json
key: psgc_id
current: "2025-07-01"
dates:
  - "2025-01-01"
  - "2025-07-01"

When querying with --as-of, the loader resolves to the closest available date that is <= the requested date. When --as-of is not specified, the current date is used.

Remote Plugins

For plugins hosted on GitHub, add the repository field:

name: my_remote_plugin
format: json
key: psgc_id
repository: https://github.com/username/my-plugin-data
ref: main
current: "2026-04-13"
dates:
  - "2025-01-01"
  - "2026-04-13"

The plugin loader will: 1. Download data files from the GitHub repository 2. Cache them locally in the cache directory 3. Use the GitHub API to list available date directories for time-aware plugins

Array Plugins

Array plugins map each psgc_id to a list of objects. Each element is cross-joined with the base record during export, producing multiple rows per psgc_id.

[
  {
    "psgc_id": "1380100001",
    "data": [
      { "school_name": "Caloocan North Elementary School", "students": 1200 },
      { "school_name": "North City National High School", "students": 850 }
    ]
  }
]

Warning

Only one array plugin can be active at a time. Mixing two array plugins will raise an error.

Complete Example: Sample Elevation Plugin

This is the actual built-in sample_elevation plugin, showing a minimal CSV-based scalar plugin.

sample_elevation/manifest.yaml:

name: sample_elevation
description: SAMPLE — Average elevation above sea level (meters) by province. Not real data.
version: 0.1.0
format: csv
key: psgc_id

sample_elevation/data/sample_elevation.csv:

psgc_id,elevation_m,terrain
1300000000,16,lowland
0800000000,52,lowland
0400000000,322,upland
1400000000,1500,highland
1900000000,88,lowland

Usage:

barangay export --model flat --plugin sample_elevation --format json

Output for NCR (psgc_id: 1300000000):

{
  "name": "National Capital Region (NCR)",
  "type": "region",
  "psgc_id": "1300000000",
  "parent_psgc_id": "0000000000",
  "nicknames": null,
  "sample_elevation.elevation_m": "16",
  "sample_elevation.terrain": "lowland"
}

Complete Example: Sample Schools Plugin

This is the actual built-in sample_schools plugin, demonstrating an array plugin with time-aware data.

sample_schools/manifest.yaml:

name: sample_schools
description: SAMPLE — BEISS school records per barangay. Not real data.
version: 0.1.0
format: json
key: psgc_id
current: 2024-07-13
dates:
  - 2024-04-13
  - 2024-07-13

sample_schools/data/2024-07-13/sample_schools.json (excerpt):

[
  {
    "psgc_id": "1380100001",
    "data": [
      { "beiss_id": 10001, "name": "Caloocan North Elementary School", "classification": "Elementary", "students": 1200 },
      { "beiss_id": 10002, "name": "North City National High School", "classification": "Junior", "students": 850 },
      { "beiss_id": 10003, "name": "Caloocan City Science High School", "classification": "Senior", "students": 420 }
    ]
  }
]

Raw plugin data structure (as returned by load_plugin_data):

{
    "1380100001": {
        "data": [
            {"beiss_id": 10001, "name": "Caloocan North Elementary School", "classification": "Elementary", "students": 1200},
            {"beiss_id": 10002, "name": "North City National High School", "classification": "Junior", "students": 850},
            {"beiss_id": 10003, "name": "Caloocan City Science High School", "classification": "Senior", "students": 420}
        ]
    }
}