# Plugin Contract ## Manifest `manifest.json` is the runtime contract consumed by Tribes: - `id` is the canonical reverse-DNS plugin identity; `slug` is the local URL/assets namespace. - `otp_app` should be vendor-prefixed and must match the Mix application name. - `entry_module` must be a loadable module ending in `.Plugin`. - `provides` declares capabilities exported by the plugin. - `requires` declares hard plugin/API contracts beyond the `host_api` foundation. - `enhances_with` declares optional host capabilities. - `migrations` should be `true` when `priv/repo/migrations` contains plugin migrations. - `children` should be `true` when the plugin starts its own supervision tree. `host_api` is the versioned foundation contract. It provides the supported Phoenix, Ash, PubSub, data, and cluster-event APIs for plugins. Do not add separate framework capability requirements for APIs that belong to that foundation. Declare `org.tribe-one.caps.ui@1` in `requires` when rendering through `Tribes.Plugin.Layouts.app`, importing `Tribes.UI.Components`, or using `use Tribes.UI`. ## Entry Modules The plugin entry module is: ```elixir defmodule TribeOne.TribesPlugin.Trust.Plugin do use Tribes.Plugin.Base, otp_app: :tribe_one_trust end ``` Keep plugin implementation code under your own namespace. The default generator uses `TribeOne.TribesPlugin.*`; third-party plugins should use their own organization or project namespace. ## Host Dependencies `tribes_plugin_api` is the release-facing `host_api` foundation. It carries the supported plugin behaviours, helpers, Phoenix/Ash data surface, and sync DSL. Do not add the full `:tribes` app as a production dependency. Host services are exposed through public facade modules in `Tribes.Plugin.Services`. Use `Tribes.Plugin.Services.Alliance` for local tribe metadata and tribe users, `Tribes.Plugin.Services.Metrics` for compact metric rollups, and `Tribes.Plugin.Services.Logs` for operational plugin logging. ## Localization Keep plugin-specific copy in this plugin's own Gettext backend and `priv/gettext` catalogs. For shared Tribes UI labels that are documented as public plugin API, import `Tribes.Plugin.Gettext` and call `tgettext/2`: ```elixir import Tribes.Plugin.Gettext tgettext("Cancel") tgettext("Save") ``` Do not call arbitrary internal Tribes Gettext domains from plugin code. The generated plugin intentionally splits the `:tribes` path dependency by environment: - In `:dev`, `:tribes` is compile-only. This lets `mix compile` create the entry-module beam expected by the host plugin manager without starting a nested Tribes application. - In `:test`, `:tribes` is runtime-enabled. Host-backed tests need the real repository, endpoint pipeline, and plugin contract helpers. ## Ash Resources For cluster-synced plugin data, add Ash resources under the plugin namespace and use `extensions: [AshNostrSync]` only for data that should replicate across the cluster. Prefer one UUID primary key per synced resource. Document any local-only tables, retention policies, or side effects in plugin docs. This plugin owns the tribe-to-tribe trust provider for `org.tribes.federation.provider@1` and stores: - `RemoteTribe` — signed or locally observed remote tribe identity metadata. - `TribeRelationship` — local relationship state, trust score, notes, requested capabilities, and granted capabilities. Both resources are cluster-synced because they are tribe-level governance state. They are not internal cluster trust records and must not be used to authorize AshNostrSync node writers.