Skip to content

Configuration

Asterios Raptis edited this page May 19, 2026 · 3 revisions

Configuration

PluginForge uses a YAML-based configuration system with three layers:

  1. App Config - Global application settings
  2. Plugin Config - Per-plugin settings
  3. i18n - Multilingual strings

Missing config files are never an error - they produce empty defaults.

App Config

Path:config/app.yaml

app:
name: "MyApp"version: "1.0.0"description: "My application"default_language: "de"plugins:
entry_point_group: "myapp.plugins"enabled:
- "export"
- "analytics"disabled:
- "experimental"

Fields

FieldDescription
app.nameApplication name
app.versionApplication version. Hosts that want min_app_version enforcement (v0.6.0) typically pass this value through to PluginManager(app_version=...); PluginForge does not read it automatically.
app.default_languageDefault language for i18n (default: "en")
plugins.entry_point_groupEntry point group for plugin discovery
plugins.enabledList of enabled plugin names (if set, only these are loaded)
plugins.disabledList of disabled plugin names (always takes precedence)

Enable/Disable Logic

  • If enabled is set, only listed plugins are loaded
  • disabled always takes precedence over enabled
  • If neither is set, all discovered plugins are loaded

Reloading Config

Config is loaded once at startup. Two reload paths since v0.6.0:

pm.reload_config() # reloads app.yaml and clears i18n cache; active plugins NOT notifiedpm.refresh_config() # v0.6.0: reloads app.yaml AND notifies active plugins via on_config_changedpm.refresh_config(new_dict) # v0.6.0: replace snapshot directly + notify

Use reload_config() when only the i18n cache needs refreshing and plugins do not need to react. Use refresh_config() for live config updates where plugins should react (cache invalidation, reconnects, etc.). For a full restart: deactivate_all() + discover_plugins(). See PluginManager#refresh_config and Lifecycle#live-config-refresh-v060 for the full flow.

Plugin Config

Path:config/plugins/{plugin_name}.yaml

Each plugin can have its own config file. The contents are passed to plugin.init() and available via plugin.config.

# config/plugins/export.yamlformats:
- epub
- pdfpandoc_path: "/usr/bin/pandoc"pdf_engine: "xelatex"

Access in the plugin:

classExportPlugin(BasePlugin):
name="export"defactivate(self) ->None:
self.formats=self.config.get("formats", ["pdf"])
self.pandoc=self.config.get("pandoc_path", "pandoc")

Config Schema Validation

Plugins can declare expected types for their config values:

classExportPlugin(BasePlugin):
name="export"config_schema= {
"pandoc_path": str,
"toc_depth": int,
"default_format": str,
}

If a config value has the wrong type (e.g. toc_depth: "abc" instead of toc_depth: 2), the plugin is skipped during initialization with a clear error message in pm.get_load_errors(). Missing keys are not an error.

i18n Config

Path:config/i18n/{lang}.yaml

See i18n for details.

Config Merge Logic

App-Config (config/app.yaml)
+ Plugin-Config (config/plugins/{name}.yaml) -> plugin.config
+ i18n (config/i18n/{lang}.yaml) -> pm.get_text()

The app config is available on each plugin via plugin.app_config. The plugin config via plugin.config. i18n is accessed separately through PluginManager.get_text().

Security

Plugin names and language codes are validated before being used to construct file paths. Names containing path separators (/, ..) are rejected with InvalidPluginNameError. See Security for details.

API

load_yaml(path) -> dict

Load any YAML file. Returns empty dict if file is missing or invalid.

load_app_config(config_path) -> dict

Load the main app config.

load_plugin_config(config_dir, plugin_name) -> dict

Load config from {config_dir}/plugins/{plugin_name}.yaml. Validates the plugin name.

load_i18n(config_dir, lang) -> dict

Load i18n strings from {config_dir}/i18n/{lang}.yaml. Validates the language code.

Clone this wiki locally