docs: assume plugin capabilities by default

Signed-off-by: barlind <tobias@barlind.se>
This commit is contained in:
barlind 2026-06-03 10:41:28 +02:00 committed by Bret Mogilefsky
parent 7d0021d04a
commit 35863b8886
No known key found for this signature in database
12 changed files with 22 additions and 22 deletions

View File

@ -12,7 +12,7 @@ These rules apply only when editing files under `plugins/**`. They encode the co
## Manifest
- **`plugin.json` is required** and must validate against [`schema/plugin.schema.json`](../../schema/plugin.schema.json). Required fields: `id`, `name`. The `id` must match the parent directory name (the loader keys discovery by directory; drift breaks plugin lookup).
- **Capability-aware plugins declare intent** with `standards: ["capability-pipelines.v1"]` and redaction-safe `capabilities` / `ui` metadata. Treat these declarations as the plugin's primary contract with Slopsmith.
- **Plugins declare capability intent** with `standards: ["capability-pipelines.v1"]` and redaction-safe `capabilities` / `ui` metadata. Treat these declarations as the plugin's primary contract with Slopsmith.
- **License must come from the curated allowlist** if the plugin is intended for the curated list. See [`CONTRIBUTING.md`](../../CONTRIBUTING.md) "Plugin licensing".
- **`type: "visualization"`** requires a `script` field exporting `window.slopsmithViz_<id>`. See [`docs/plugin-visualization-contracts.md`](../../docs/plugin-visualization-contracts.md).

View File

@ -1,6 +1,6 @@
---
name: plugin-scaffold
description: Scaffold a new capability-aware Slopsmith plugin skeleton. USE WHEN the user asks to create a new plugin, scaffold a plugin, bootstrap a plugin, new visualization plugin, new overlay plugin, new settings-only plugin, plugin starter, plugin skeleton. Args needed - plugin slug (snake_case) and type (visualization / overlay / settings-only / routes-only). Generates plugins/<id>/ with plugin.json, capability-pipelines metadata, screen.js, and optional routes.py / settings.html / Playwright test stub matching the requested type.
description: Scaffold a Slopsmith plugin skeleton with capability-pipelines metadata. USE WHEN the user asks to create a new plugin, scaffold a plugin, bootstrap a plugin, new visualization plugin, new overlay plugin, new settings-only plugin, plugin starter, plugin skeleton. Args needed - plugin slug (snake_case) and type (visualization / overlay / settings-only / routes-only). Generates plugins/<id>/ with plugin.json, capability-pipelines metadata, screen.js, and optional routes.py / settings.html / Playwright test stub matching the requested type.
---
# plugin-scaffold

View File

@ -14,7 +14,7 @@ This file customizes GitHub Copilot Chat and Copilot inline suggestions for the
- **No frontend frameworks.** Vanilla JS, Canvas, Tailwind classes. Do not suggest React/Vue/Svelte additions.
- **Plugin backend logging.** Suggest `context["log"]`, never `print()`.
- **Plugin Python imports.** For cross-file backend plugins, suggest `context["load_sibling"]("module_name")` instead of bare `from module_name import X`.
- **Capability metadata.** For new plugin integrations, suggest `standards: ["capability-pipelines.v1"]` and redaction-safe `capabilities` / `ui` metadata as the primary contract.
- **Capability metadata.** For plugin integrations, suggest `standards: ["capability-pipelines.v1"]` and redaction-safe `capabilities` / `ui` metadata as the primary contract.
- **DCO/license headers.** When creating a new file in the main repo, no license header is needed (the LICENSE file at root governs). Plugin authors should add an SPDX-License-Identifier comment to their plugin's source files; the `license` field in `plugin.json` must match the allowlist in [`CONTRIBUTING.md`](../CONTRIBUTING.md).
## Validation

View File

@ -34,7 +34,7 @@ jobs:
python -m pip install --upgrade pip
pip install -r requirements-test.txt
- name: Validate every in-tree plugin.json against capability-aware schema
- name: Validate every in-tree plugin.json against capability schema
run: |
python - <<'PY'
import glob, json, sys

View File

@ -119,7 +119,7 @@ Slopsmith supports two:
## Plugin authoring — see [`docs/PLUGIN_AUTHORING.md`](docs/PLUGIN_AUTHORING.md)
Plugins are the primary extension point. Each lives in `plugins/<name>/` with a `plugin.json` manifest. Curated plugins must be AGPL-3.0 or AGPL-compatible — see [`CONTRIBUTING.md`](CONTRIBUTING.md) for the allowlist. Manifest is validated in CI against [`schema/plugin.schema.json`](schema/plugin.schema.json), including `capability-pipelines.v1` metadata for native capability declarations.
Plugins are the primary extension point. Each lives in `plugins/<name>/` with a `plugin.json` manifest that declares its `capability-pipelines.v1` participation. Curated plugins must be AGPL-3.0 or AGPL-compatible — see [`CONTRIBUTING.md`](CONTRIBUTING.md) for the allowlist. Manifest is validated in CI against [`schema/plugin.schema.json`](schema/plugin.schema.json), including capability metadata.
Topic | Doc
--- | ---
@ -140,7 +140,7 @@ Tuning the note_detect plugin | [`docs/note-detect-tuning.md`](docs/note-detect-
1. **`load_sibling` for cross-file backend plugins.** Bare `from extractor import X` in `routes.py` collides across plugins because Python caches by module name in `sys.modules`. Use `context["load_sibling"]("extractor")` — gets a per-plugin namespaced module. Full explanation: [`docs/plugin-sibling-imports.md`](docs/plugin-sibling-imports.md).
2. **Capability declarations are the integration map.** New plugin behavior should be visible in `standards`, `capabilities`, and `ui` metadata before runtime code hydrates. If the domain you need is missing, document it as a capability gap instead of adding another private global contract.
2. **Capability declarations are the integration map.** Plugin behavior should be visible in `standards`, `capabilities`, and `ui` metadata before runtime code hydrates. If the domain you need is missing, document it as a capability gap instead of adding another private global contract.
3. **Highway flex layout.** `#highway` has `flex:1` in the player. Hiding it with `display:none` removes the flex child and `#player-controls` floats to the top. If you must hide the highway, add `margin-top: auto` to the controls div.
@ -169,7 +169,7 @@ python -c "import json,glob,jsonschema; s=json.load(open('schema/plugin.schema.j
- **No frontend frameworks.** Vanilla JS, fetch API, Tailwind classes. Don't add React/Vue/Svelte.
- **Backend logging.** Plugin `routes.py` must use `context["log"]`, never `print()`. See [`docs/plugin-logging.md`](docs/plugin-logging.md).
- **Plugin Python imports.** Multi-file backends use `context["load_sibling"]("<module>")`, not bare `from <module> import`. See [`docs/plugin-sibling-imports.md`](docs/plugin-sibling-imports.md).
- **Capability metadata.** New plugin integrations should declare `standards: ["capability-pipelines.v1"]` plus redaction-safe `capabilities`/`ui` metadata as the primary integration contract.
- **Capability metadata.** Plugin integrations declare `standards: ["capability-pipelines.v1"]` plus redaction-safe `capabilities`/`ui` metadata as the primary integration contract.
- **Spec-kit owns `.specify/` and `specs/`.** Don't modify those without explicit instruction; the `/speckit-*` skills own that surface.
## Tool-specific surfaces (optional reading)

View File

@ -8,7 +8,7 @@ Claude Code memory file. This repo's canonical project orientation lives in [`AG
The rest of this file is content that *only* makes sense for Claude Code (other AI tools have their own incompatible automation mechanisms). Skills, subagent, rule, and settings live under [`.claude/`](.claude/):
- [`.claude/skills/plugin-scaffold/`](.claude/skills/plugin-scaffold/SKILL.md) - generates a capability-aware plugin skeleton.
- [`.claude/skills/plugin-scaffold/`](.claude/skills/plugin-scaffold/SKILL.md) - generates a plugin skeleton with capability-pipelines metadata.
- [`.claude/skills/plugin-validate/`](.claude/skills/plugin-validate/SKILL.md) - validates `plugin.json` against `schema/plugin.schema.json` locally before push.
- [`.claude/skills/speckit-*/`](.claude/skills/) - spec-kit skills (auto-generated from `.specify/`; don't edit manually).
- [`.claude/rules/plugin-author.md`](.claude/rules/plugin-author.md) - glob-scoped to `plugins/**`; encodes the contracts from `docs/PLUGIN_AUTHORING.md` so suggestions don't drift from them.

View File

@ -16,7 +16,7 @@ plugins/my_plugin/
└── requirements.txt Optional — pip deps auto-installed on load
```
Start every new plugin by describing its Slopsmith-facing behavior in the manifest. A plugin with no behavior beyond metadata can be this small:
Start every plugin by describing its Slopsmith-facing behavior in the manifest with `standards: ["capability-pipelines.v1"]`, native `capabilities`, and redaction-safe `ui` metadata. A plugin with no app-facing behavior beyond metadata can still be this small:
```json
{
@ -26,7 +26,7 @@ Start every new plugin by describing its Slopsmith-facing behavior in the manife
}
```
Any plugin that participates in app behavior should also declare `standards: ["capability-pipelines.v1"]`, native `capabilities`, and redaction-safe `ui` metadata. Capability declarations are the source of truth for diagnostics, the Capability Inspector, and migration tooling.
Capability declarations are the source of truth for diagnostics, the Capability Inspector, and plugin tooling. Treat missing capability metadata as an intentional exception for metadata-only or transitional plugin manifests.
## Topics
@ -49,7 +49,7 @@ Any plugin that participates in app behavior should also declare `standards: ["c
## General guidelines
- Wrap your plugin code in an IIFE: `(function () { 'use strict'; ... })();`
- Declare `standards: ["capability-pipelines.v1"]` and native `capabilities` when your plugin participates in a Slopsmith capability domain.
- Declare `standards: ["capability-pipelines.v1"]` and native `capabilities` for the plugin's Slopsmith-facing behavior.
- Use `ui` / `ui_contributions` for plugin-owned UI surfaces so the host can attribute them in diagnostics and support bundles.
- Use `localStorage` for user-facing settings, prefixed with your plugin id.
- Prefer native capability commands, events, and provider registration over private globals. If a domain you need is not active yet, document the gap in the PR instead of baking in a new private integration.

View File

@ -51,7 +51,7 @@ Backend route metadata should support a declared capability domain. A generic `b
Plugins that call `context["register_library_provider"](...)` are attributed to the loading plugin id in `/api/library/providers` as `owner_plugin_id`. The browser library capability module at [static/capabilities/library.js](../static/capabilities/library.js) owns the `library` domain as a `provider-coordinator`: it refreshes `/api/library/providers`, registers the built-in `local` provider as `core.library.local`, and registers plugin-backed providers under their `owner_plugin_id` when one is known. Provider manifests should still declare the `library` capability so diagnostics and the bundled inspector can show intended relationships before the backend route code runs.
Route-only external plugins that participate in library workflows without registering a browsable provider should declare requester/observer intent instead of provider ownership when they adopt this contract in their own repositories. This PR documents the generic shape only: such plugins use `library` requester/observer `requests` and `observes` declarations and do not appear as providers, owners, or separate `backend.routes` domains.
Route-only external plugins that participate in library workflows without registering a browsable provider declare requester/observer intent instead of provider ownership when they adopt this contract in their own repositories. This PR documents the generic shape only: such plugins use `library` requester/observer `requests` and `observes` declarations and do not appear as providers, owners, or separate `backend.routes` domains.
```json
{

View File

@ -100,7 +100,7 @@ A plugin that registers a remote client or generated library source declares its
## Library Requester And Observer
A route-only wrapper that uses the library capability without registering a browsable provider should declare requester/observer intent instead of provider ownership. This is a generic manifest shape for external plugins to adopt in their own repositories; it does not make the wrapper part of this PR's delivered domain set.
A route-only wrapper that uses the library capability without registering a browsable provider declares requester/observer intent instead of provider ownership. This is a generic manifest shape for external plugins to adopt in their own repositories; it does not make the wrapper part of this PR's delivered domain set.
```json
{
@ -149,7 +149,7 @@ Native audio-mix fader providers should register a stable participant id and fad
## Audio Input And Monitoring Requester
Plugins that need live instrument input should declare requester/observer intent and let the host expose redaction-safe source identity. Diagnostics must not contain raw device labels, stable hardware ids, or audio buffers.
Plugins that need live instrument input declare requester/observer intent and let the host expose redaction-safe source identity. Diagnostics must not contain raw device labels, stable hardware ids, or audio buffers.
```json
{
@ -299,7 +299,7 @@ The Stems plugin remains the provider/owner of actual stem playback state. `core
## Playback Requester And Observer
Plugins that need to inspect or coordinate song transport should declare `playback` requester/observer intent and use the capability dispatch surface. Raw media handles stay private to core; diagnostics expose only pseudonymous targets, sanitized timing, route, loop, requester, observer, and recent outcome summaries.
Plugins that need to inspect or coordinate song transport declare `playback` requester/observer intent and use the capability dispatch surface. Raw media handles stay private to core; diagnostics expose only pseudonymous targets, sanitized timing, route, loop, requester, observer, and recent outcome summaries.
```json
{
@ -347,6 +347,6 @@ if (state.status !== 'idle') {
Some domain names are reserved for expected future contracts, but they are not registered in the runtime graph yet. For example, `ui.player-panels` is documented as a likely panel-host surface, but Slopsmith does not currently expose a capability command for panel contributions. See [capability-roadmap.md](capability-roadmap.md) for the PR1 domain set and deferred-domain checklist.
Plugins should not declare future expansion domains until the corresponding host workflow ships. For current integrations, prefer active domains such as `library`, `playback`, `audio-mix`, `audio-input`, `audio-monitoring`, or `stems` intent matching the recipes above.
Do not declare future expansion domains until the corresponding host workflow ships. For current integrations, use active domains such as `library`, `playback`, `audio-mix`, `audio-input`, `audio-monitoring`, or `stems` intent matching the recipes above.
Invalid capability metadata is excluded from the capability graph. The `library` workflow is native in PR1 and does not use compatibility shim metadata. Unsupported `capability-pipelines` versions are reported as incompatible and their runtime handlers must not execute.

View File

@ -65,9 +65,9 @@ Plain semver string. Advisory only — the plugin loader does not consume this.
Advisory metadata for plugin authors. Not consumed by the loader.
### `standards` (string[], optional)
### `standards` (string[], expected)
Versioned contracts the plugin participates in. New plugins should declare `"capability-pipelines.v1"` when they include native `capabilities`, `ui`, or related metadata.
Versioned contracts the plugin participates in. Plugin manifests are expected to declare `"capability-pipelines.v1"` for Slopsmith-facing behavior and metadata. Omit it only for metadata-only or transitional manifests with no capability participation yet.
Declare `"plugin-runtime-idempotent.v1"` only when repeated script hydration cannot duplicate wrappers, listeners, timers, DOM roots, diagnostics contributors, jobs, media nodes, or capability participants.
@ -143,9 +143,9 @@ Example:
Contribution ids must be stable and unique per plugin. Keep metadata redaction-safe: no settings values, DOM handles, local paths, callbacks, or private payloads.
### `capabilities` (object, optional)
### `capabilities` (object, expected for app-facing behavior)
Native `capability-pipelines.v1` declarations keyed by capability domain. They describe what the plugin owns, provides, requests, observes, or emits before the runtime script hydrates.
Native `capability-pipelines.v1` declarations keyed by capability domain. They describe what the plugin owns, provides, requests, observes, or emits before the runtime script hydrates, and are the default way plugin behavior is made visible to Slopsmith.
```json
{

View File

@ -77,7 +77,7 @@
"label": { "type": "string", "minLength": 1 },
"screen": { "type": "string", "pattern": "^[a-z][a-z0-9_-]*$" }
},
"description": "Optional navigation metadata. New plugin UI should also declare stable ui contributions."
"description": "Optional navigation metadata. Plugin UI declares stable ui contributions for attribution."
},
"screen": {
"type": "string",

View File

@ -143,7 +143,7 @@ def test_in_tree_manifest_id_matches_directory(manifest_path: str) -> None:
def test_capability_manifest_metadata_validates(schema: dict) -> None:
"""Capability-aware manifests should validate alongside runtime loader fields."""
"""Capability-declared manifests should validate alongside runtime loader fields."""
manifest = {
"id": "capability_example",
"name": "Capability Example",