You've already forked tribes-plugin-kobold
4658b76241
CI / Test (push) Failing after 22s
Rename Kobold and Trust plugin identity references to tribe-one-prefixed slugs across runtime API, e2e fixtures, and docs.
124 lines
4.5 KiB
Markdown
124 lines
4.5 KiB
Markdown
# Plugin Contract
|
|
|
|
## Manifest
|
|
|
|
`manifest.json` is the runtime contract consumed by Tribes:
|
|
|
|
- `id` is the globally unique 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.Kobold.Plugin do
|
|
use Tribes.Plugin.Base, otp_app: :tribe_one_kobold
|
|
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 Kobold-specific copy in Kobold'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.
|
|
|
|
## Kobold Dataset Resources
|
|
|
|
Kobold's MVP uses fixed plugin-owned Ash resources as its storage and sync
|
|
contract. User-defined dataset resources are dynamic schema data, not runtime
|
|
Elixir modules, runtime Ash resources, or per-resource database tables.
|
|
|
|
Initial fixed resources:
|
|
|
|
- `Dataset`
|
|
- `ResourceDefinition`
|
|
- `DatasetEvent`
|
|
- `RecordProjection`
|
|
- `MergeProposal`
|
|
|
|
The first shipped foundation includes `Dataset`, `ResourceDefinition`,
|
|
`DatasetEvent`, and local-only `RecordProjection`. Public dataset/resource/event
|
|
mutations use `AshNostrSync.PublishChange`; private mutations deliberately do
|
|
not publish and remain local. `RecordProjection` is rebuildable from
|
|
`DatasetEvent` history. `MergeProposal` remains planned for the fork/merge
|
|
milestone.
|
|
|
|
Do not generate Ash resources or migrations for each user-defined dataset
|
|
resource in the first cut. If a future optimized dataset type needs dedicated
|
|
Ash resources, document that as a specialized plugin compatibility layer rather
|
|
than the generic Kobold storage model.
|
|
|
|
## Local Supertest API
|
|
|
|
Kobold exposes a loopback-only JSON API under `/plugins-api/tribe-one-kobold` for smoke and
|
|
supertest scenarios:
|
|
|
|
- `GET /health`
|
|
- `GET /schema`
|
|
- `POST /reset`
|
|
- `POST /datasets`
|
|
- `POST /datasets/:dataset_id/resources`
|
|
- `POST /datasets/:dataset_id/records`
|
|
- `GET /state?run_id=...`
|
|
- `POST /projections/rebuild`
|
|
|
|
This API is not the durable user-facing federation contract; it exists to prove
|
|
plugin install, migrations, public dataset sync, and private local-only dataset
|
|
behavior in live scenarios.
|