Skip to content

Plugin manifest format, registry, and enabled-plugins config #33

Description

@verkligheten

Parent Epic

Part of #32 — Plugin system: toggleable internal subsystems

Blocks #35 (declarative surfaces) and #36 (hooks + allow-entries). Independent of all other sub-issues.

Task

Define the plugin manifest format and a registry that loads enabled manifests, plus the enabled-plugins list in user config. This sub-issue adds the mechanism only — it wires nothing into install or render yet, so dist cannot change.

Location

  • agent_notes/plugins/NEW package root
  • agent_notes/plugins/<name>/plugin.yamlNEW manifest per plugin (none created here; format defined + validated by a fixture)
  • agent_notes/registries/plugin_registry.pyNEW
  • agent_notes/domain/plugin.pyNEW Plugin dataclass
  • agent_notes/services/user_config.py — add enabled_plugins read/default helper
  • tests/unit/registries/test_plugin_registry.pyNEW

Changes

Manifest format

name: cost-report            # unique; matches directory name
description: <one line>
default: on | off            # enabled when user config has no explicit choice
skills:   [<skill-name>, ...]     # names in data/skills/
agents:   [<agent-name>, ...]     # names in data/agents/
rules:    [<rule-name>, ...]      # names in data/rules/
includes: [<include-name>, ...]   # shared include names (data/agents/shared/<name>.md)
hooks:    [{event: Stop, command: "...", requires: stop_hook}]
allow:    ["Bash(agent-notes cost-report)", ...]

requires on a hook or allow-entry names a backend.supports(...) capability; the entry is installed only when the backend has it. This is how the manifest composes with the existing capability axis (epic finding 2) rather than fighting it.

Plugin dataclass + registry

  • Plugin holds the parsed manifest fields.
  • plugin_registry.load() globs plugins/*/plugin.yaml, parses each, validates required fields (name, description, default), and rejects a manifest whose name != directory name.
  • registry.enabled(user_config) returns the plugins that are on: explicit user choice wins; otherwise default.

User config

  • enabled_plugins key in ~/.config/agent-notes/config: a {name: bool} map, absent by default.
  • Helper: enabled_plugin_names(config, registry) -> set[str].

Not in this sub-issue

No manifest files, no installer/render wiring, no CLI. Those are #35, #36, #34. Keeping this pure means the equivalence gate is trivially satisfied.

Verification

uv run pytest tests/unit/registries/test_plugin_registry.py -v
uv run pytest tests/ -v

Dist: byte-identical. This sub-issue adds unreferenced code; nothing in the build path calls it yet.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions