# perk provider-selection supported set — the THIRD parsed cross-plane contract
# (sibling of registry.yaml and bindings.yaml).
#
# Authored once here, bundled into each build artifact (wheel -> perk/_shared/,
# npm tarball -> shared/), and parsed directly by both planes at runtime: the
# Python reader is perk/substrate/providers.py, the TS reader is extension/substrate/providers.ts. No
# codegen step — both planes read this same file.
#
# This is the SUPPORTED SET (the full catalog of providers perk knows how to wire),
# distinct from the per-repo SELECTION (the flat `[providers]` table in .pi/perk.toml,
# which is just a pointer into this catalog). Because both planes read this with their
# full YAML readers, it can carry nested structure — notably the Pi `package_filter`
# object — that the narrow-TOML config reader cannot.
#
# Vocabulary — each provider entry:
#   id      — the stable provider id. NOT the cache.plan-ref `provider` string:
#             that field is the ISSUE BACKEND (the stamped `backend_id`, e.g.
#             "github"), not the seam id — see contracts.md §8.10 / §8.21.
#   seam    — `plan` | `todo` | `askuser` | `footer` | `web` (the five seams; see
#             pluggability-taxonomy.md for the scope fence).
#   package — the foreign Pi package spec added to .pi/settings.json `packages`
#             (e.g. "npm:@tombell/pi-plan"); `null` for perk's own bundled reference
#             provider (nothing to add — perk produces the contract natively). NOT
#             universal: the `web` seam's reference provider (`pi-web-access`) is itself
#             a FOREIGN package because perk owns no native web implementation — its
#             `default: true` entry carries a non-null `package` (the documented exception).
#   adapter — the perk-owned shim module that bridges the foreign surface to the
#             artifact boundary (cache.plan-ref / perk:checkpoint); `null` for the
#             reference provider.
#   default — exactly ONE `true` per seam: the behavior-preserving no-config pick.
#   package_filter — optional Pi object-form filter (extensions/skills/… arrays)
#             merged into the foreign package's `packages` entry to enable only the
#             conflicting surface. perk's own package is NEVER filtered (it defers at
#             runtime instead — adapter-architecture.md Invariant 2).
#
# Validation split (mirrors bindings.yaml): the shape-only loaders (perk/substrate/providers.py,
# extension/substrate/providers.ts) check schema_version, id uniqueness, seam membership, and
# exactly-one-default-per-seam. Cross-checks — does the repo's `[providers]` selection
# name a provider that exists / has the right seam? — are `doctor`'s job, NOT the
# loaders. The Python plane is the authoritative validator.
#
# Status (Node 2.1 → 3.2): this file ships the substrate (the three reference entries +
# foreign entries per seam), and ALL THREE seams now have a REAL foreign provider. The PLAN
# adapter landed at Node 2.3: `tombell-plan` is a REAL, selectable plan provider —
# `planAdapterTombell` bridges `@tombell/pi-plan`'s free-form prose surface to perk's
# canonical `plan_save` → `cache.plan-ref` contract, and perk VACATES the plan surface at
# REGISTRATION time (not just handler-time) under a foreign plan selection so the foreign
# `/plan`/`Ctrl+Alt+P`/`--plan` are the sole registrants (Pi suffixes duplicate command
# names). The TODO adapter landed at Node 3.2: `juicesharp-todo` is a REAL, selectable todo
# provider — `todoAdapterJuicesharp` carries perk's implement-progress discipline onto
# `@juicesharp/rpiv-todo`'s checklist overlay (injection-only, active-workflow-gated), and
# perk's own checkpoints simply DEFER at runtime (Node 3.1) — NO registration-time vacating,
# because the todo seam has no command-name collision (`/checkpoints` vs the overlay's own
# command). The DEFAULT path (the reference providers) is the hard guarantee.
#
# The ASKUSER seam is an INTERFACE seam (no durable artifact to bridge): its stable contract is
# the tool NAME `ask_user_question` plus its non-terminating-answer semantics. `juicesharp-ask-user`
# (`@juicesharp/rpiv-ask-user-question`) registers a tool with the IDENTICAL name, and tools
# (unlike commands) do NOT get `:N` suffixes — a same-named tool replaces/warns by extension load
# order. So the adapter is VACATE-ONLY (`adapter: null`, no shim, no injected context): under a
# foreign askuser selection perk's `registerAskUser` registers NOTHING at REGISTRATION time,
# leaving exactly one `ask_user_question` standing. Under the default (`perk-ask-user`) the foreign
# package is never installed, so perk's tool is the sole registrant.
#
# The FOOTER seam is the SECOND INTERFACE seam (no durable artifact to bridge), mirroring askuser
# but with INSTALL-SITE (runtime) vacating rather than registration-time vacating: perk installs
# its own footer (`installPerkFooter`) inside the `session_start` event handler, so under a foreign
# `[providers] footer` selection perk simply does NOT call `installPerkFooter` (a runtime guard at
# that single install site, keyed off `ctx.cwd`), leaving the foreign footer (`pi-powerline-footer`,
# `pi-bar`, or `@tombell/pi-status`) as the sole footer surface. `adapter: null`, no shim: for
# `pi-powerline-footer`/`pi-bar` perk's objective/checkpoints progress reaches the foreign footer
# automatically via the already-publishing composed `perk` `setStatus` slot (both render extension
# statuses), so the bridge is automatic; `@tombell/pi-status` is the exception (it does NOT render
# extension statuses — see the `pi-status-footer` note below).
# Fail-safe: any config-read error resolves to the reference id → perk installs its footer (the
# default path is the hard zero-change guarantee).
#
# Two more footer outcomes round out the catalog so the footer is governed EXCLUSIVELY by
# `[providers] footer` (no footer outcome ever needs a manual `packages` edit):
#   - `pi-status-footer` (`npm:@tombell/pi-status`) is vacate-only like the two above, BUT — unlike
#     `powerline-footer`/`pi-bar-footer` — pi-status does NOT render extension statuses, so perk's
#     objective/checkpoints progress is NOT shown in the footer when it is selected. This is an
#     accepted limitation (it matches what pi-status already does today); perk does not build a
#     status-bridge adapter for it (it is a genuine interface seam).
#   - `pi-default` (`package: null`) is the "install nothing / leave pi's stock built-in footer"
#     option: perk vacates (gate false), convergence adds no package, so pi's own footer stands.
#
# The WEB seam is the THIRD INTERFACE seam (no durable artifact to bridge), but with a genuine
# novelty: it is the FIRST seam whose `default: true` provider has a NON-NULL `package`. perk owns
# no native web-research implementation, so the behavior-preserving reference (`pi-web-access`,
# zero-config Exa search + content fetch + the bundled `librarian` skill) is itself a foreign npm
# package. Selection simply SWAPS which web package the provider-convergence installs — `adapter:
# null`, no shim, and there is NO perk surface to vacate at registration time because perk registers
# NO web tools of its own. The read-only allowlist statically carries the UNION of all known web
# tool names (inert when absent); perk does NOT normalize tool names across providers. `librarian`
# is pi-web-access-specific (it depends on `fetch_content`'s GitHub-clone path) and is accepted as
# lost under a foreign web selection. Fail-safe: any config-read error resolves to `pi-web-access`,
# keeping today's behavior exactly.
#
# There is NO review seam: the two surface-named review doors (`/pr-review-terminal` — the hunk
# terminal TUI; `/pr-review-browser` — the plannotator browser UI) are the selection (the command
# IS the surface pick). The hunk CLI converges unconditionally (init/doctor's best-effort
# `review-cli` install/verify); the plannotator package rides the plan seam's `plannotator-plan`
# entry.

schema_version: 1

providers:
  - id: perk-plan            # perk's own planMode/planSave over toolGating
    seam: plan
    package: null            # null ⇒ perk's bundled reference provider (no foreign package)
    adapter: null            # null ⇒ no shim needed; perk produces the contract natively
    default: true            # the behavior-preserving no-config pick for the plan seam
  - id: perk-checkpoints     # perk's own checkpoints
    seam: todo
    package: null
    adapter: null
    default: true            # the behavior-preserving no-config pick for the todo seam
  - id: perk-ask-user        # perk's own ask_user_question tool (extension/doors/askUser.ts)
    seam: askuser
    package: null
    adapter: null
    default: true            # the behavior-preserving no-config pick for the askuser seam

  # --- foreign entries ---
  - id: tombell-plan         # REAL plan provider (Node 2.3) — planAdapterTombell bridges it
    seam: plan
    package: "npm:@tombell/pi-plan"   # the foreign Pi package to add to `packages`
    adapter: "planAdapterTombell"     # the perk-owned shim bridging surface → cache.plan-ref
    default: false
    # No `package_filter`: `@tombell/pi-plan`'s sole extension is its root `index.ts` (not under
    # `extensions/`), so omitting the filter ("load all of that type") loads exactly that one
    # extension. The `package_filter` field stays in the vocabulary for future providers.
  - id: plannotator-plan   # REAL plan provider — planAdapterPlannotator bridges its browser review
    seam: plan
    package: "npm:@plannotator/pi-extension"   # the foreign Pi package to add to `packages`
    adapter: "planAdapterPlannotator"          # the perk-owned shim bridging plan_review → its event API
    default: false
    # AUGMENT posture (contrast with tombell-plan's REPLACE posture): plannotator does not replace
    # perk's plan surface — perk's `/plan` command, authoring injection, and read-only gate STAY
    # registered; perk skips only the two real registration collisions (`--plan` flag and the
    # `Ctrl+Alt+P` shortcut, both of which plannotator also registers — duplicate flag/shortcut
    # registration is the known potentially-fatal Pi behavior). The bridge is the model-callable
    # `plan_review` tool (planAdapterPlannotator) → plannotator's `plannotator:request` plan-review
    # event flow (its browser review UI). Saving stays the human-run `/plan-save`.
    # No `package_filter`: `@plannotator/pi-extension`'s `pi.extensions` is `["./"]` (the sole
    # extension is the package root), so omitting the filter loads exactly that one extension.
  - id: juicesharp-todo      # REAL todo provider (Node 3.2) — todoAdapterJuicesharp bridges it
    seam: todo
    package: "npm:@juicesharp/rpiv-todo"   # the foreign Pi package to add to `packages`
    adapter: "todoAdapterJuicesharp"       # the perk-owned shim carrying progress discipline onto it
    default: false
    # No `package_filter`: `@juicesharp/rpiv-todo` is a single-concern checklist overlay, so omitting
    # the filter ("load all of that type") loads its bundled extension. The smoke's manual half is the
    # gate that no perk surface collides; a targeted `extensions` filter is a follow-up if one ever does.
  - id: juicesharp-ask-user  # REAL askuser provider — VACATE-ONLY (interface seam, no adapter)
    seam: askuser
    package: "npm:@juicesharp/rpiv-ask-user-question"   # the foreign Pi package to add to `packages`
    adapter: null            # VACATE-ONLY: the foreign tool shares the exact name `ask_user_question`,
                             # so perk's `registerAskUser` registers NOTHING under this selection —
                             # there is no durable artifact to bridge (interface seam), and the
                             # foreign tool self-documents via its own `promptGuidelines`.
    default: false
    # No `package_filter`: the verified manifest is `{"extensions": ["./index.ts"]}`, so omitting the
    # filter ("load all of that type") loads exactly that one extension — the same reasoning as the
    # tombell-plan / juicesharp-todo entries.
  - id: perk-footer          # perk's own footer (extension/surfaces/surfaces.ts installPerkFooter)
    seam: footer
    package: null
    adapter: null
    default: true            # the behavior-preserving no-config pick for the footer seam
  - id: powerline-footer     # REAL footer provider — VACATE-ONLY (interface seam, no adapter)
    seam: footer
    package: "npm:pi-powerline-footer"   # the foreign Pi package to add to `packages`
    adapter: null            # VACATE-ONLY: the footer produces no durable artifact (interface seam),
                             # and pi-powerline-footer already renders perk's `perk` setStatus slot in
                             # its extension_statuses segment, so the bridge is automatic (no shim).
    default: false
    # No `package_filter`: load the package's sole footer extension ("load all of that type").
  - id: pi-bar-footer        # REAL footer provider — VACATE-ONLY (interface seam, no adapter)
    seam: footer
    package: "npm:pi-bar"   # the foreign Pi package to add to `packages`
    adapter: null            # VACATE-ONLY: pi-bar replaces pi's footer and "keeps extension statuses
                             # visible", so perk's `perk` setStatus slot appears automatically — no shim.
    default: false
    # No `package_filter`: load the package's sole footer extension ("load all of that type").
  - id: pi-status-footer     # REAL footer provider — VACATE-ONLY (interface seam, no adapter)
    seam: footer
    package: "npm:@tombell/pi-status"   # the foreign Pi package to add to `packages`
    adapter: null            # VACATE-ONLY: the footer produces no durable artifact (interface seam).
                             # UNLIKE powerline/pi-bar, pi-status does NOT render extension statuses,
                             # so perk's objective/checkpoints progress is NOT shown in the footer
                             # under this selection (an accepted limitation — matches pi-status today;
                             # no status-bridge adapter is built).
    default: false
    # No `package_filter`: load the package's sole footer extension ("load all of that type").
  - id: pi-default           # "install nothing" footer provider — leaves pi's stock built-in footer
    seam: footer
    package: null            # null ⇒ perk adds NO package; pi's own built-in footer stands.
    adapter: null            # VACATE-ONLY: perk's footer-install gate is false (resolved id ≠
                             # perk-footer), so perk skips installPerkFooter; nothing else to add.
    default: false
  - id: pi-web-access        # web seam DEFAULT — the FOREIGN reference provider (perk owns no native web impl)
    seam: web
    package: "npm:pi-web-access"   # NON-NULL default package: the novelty — perk has no native web provider
    adapter: null            # VACATE-ONLY interface seam: no durable artifact, and perk registers NO web
                             # tools, so there is no perk surface to vacate. Selection just swaps the package.
    default: true            # the behavior-preserving no-config pick (zero-config Exa search + `librarian`)
    # No `package_filter`: `pi-web-access`'s sole extension is its root `./index.ts` (verified via
    # `npm view pi-web-access pi`), so omitting the filter loads exactly that one extension.
  - id: ollama-web-search    # REAL web provider — VACATE-ONLY (interface seam, no adapter)
    seam: web
    package: "npm:@ollama/pi-web-search"   # the foreign Pi package to add to `packages`
    adapter: null            # VACATE-ONLY: web is an interface seam (no artifact); perk registers no web
                             # tools, so nothing to vacate. Tools: `ollama_web_search`/`ollama_web_fetch`
                             # (needs a local Ollama daemon). Divergent names — perk allowlists the union.
    default: false
    # No `package_filter`: verified manifest is `{"extensions": ["./index.ts"]}`, so omitting the
    # filter loads exactly that one extension.
  - id: juicesharp-web-tools # REAL web provider — VACATE-ONLY (interface seam, no adapter)
    seam: web
    package: "npm:@juicesharp/rpiv-web-tools"   # the foreign Pi package to add to `packages`
    adapter: null            # VACATE-ONLY: interface seam, no artifact; perk registers no web tools.
                             # Tools: `web_search`/`web_fetch` (needs an API key; default provider Brave;
                             # registers a `/web-tools` command — no perk collision).
    default: false
    # No `package_filter`: verified manifest is `{"extensions": ["./index.ts"]}`, so omitting the
    # filter loads exactly that one extension (the juicesharp single-extension convention).
