Introduce the Trust plugin as the federation provider for tribe identity and hello handshakes, with synced Ash resources for remote tribes and tribe relationships plus an admin LiveView for trust management.
Trust
Tribe-to-tribe alliances and trust
Getting Started
- Edit
manifest.json- set description, capabilities, requirements - Implement your plugin in
lib/trust/plugin.ex - Run validation, smoke checks, and tests:
mix deps.get
mix tribes.plugin.validate
scripts/plugin smoke
scripts/plugin test
If you are using the shared tribes devenv, run through the local helper instead:
devenv shell -- plugin validate
devenv shell -- plugin smoke
devenv shell -- plugin test
devenv shell -- plugin precommit
Generate AshPostgres resource migrations through the same wrapper so they
target the host Tribes.Repo and the plugin migration directory:
plugin ash.codegen update_example_resources
Manual Ecto migrations are the rare exception for schema work not derived from Ash resources:
plugin ecto.migration add_example_table
Development
For local development alongside a Tribes checkout:
# Symlink into the host plugins directory once
cd ../tribes
ln -s ../tribes-plugin-trust plugins/trust
# Start Tribes dev server
iex --sname dev -S mix phx.server
Then edit the plugin in its own repo. In development, the host watches symlinked external plugins and automatically:
- runs
mix compilefor Elixir/HEEx or manifest changes - runs
npm run build --prefix assetswhenassets/package.jsonis present and plugin asset files change - reloads the plugin in the running Tribes VM
- triggers a Phoenix browser reload after the rebuild finishes
Browser hooks for external plugins should live in plugin JS assets declared
in manifest.json assets.global_js and register themselves through
window.TribesPluginHooks. Phoenix colocated hooks are not auto-imported
from external plugin OTP apps by the host app.js bundle.
That means the normal edit/compile loop is:
cd /path/to/tribes-plugin-trust
mix deps.get
# in another terminal
cd /path/to/tribes
iex --sname dev -S mix phx.server
Inside the plugin repo's devenv shell, the plugin helper forwards to the host devenv automatically:
plugin validate
plugin smoke
plugin test
plugin precommit
If your plugin does not need a custom frontend pipeline, you can skip
assets/package.json and write browser-ready files directly under assets/js
and assets/css; the host dev watcher will copy them into priv/static for
you in development. The default generator uses TypeScript under assets/ts.
LiveView Hooks
External plugins do not participate in the host asset bundle, so the host
cannot statically import arbitrary plugin phoenix-colocated/<otp_app>
modules. Register browser hooks from your plugin JS instead:
window.TribesPluginHooks = window.TribesPluginHooks ?? {};
window.TribesPluginHooks.TribeOneTribesPluginTrustExample = {
mounted() {
console.info("trust hook mounted");
}
};
Keep the compiled JS file listed in manifest.json assets.global_js so it
loads before the host LiveSocket connects.
Project Structure
trust/
|-- manifest.json # Plugin metadata (Nix build + runtime)
|-- mix.exs # Dependencies
|-- config/ # Host-backed test config
|-- lib/
| |-- trust/
| | |-- plugin.ex # Tribes.Plugin entry point
| | `-- application.ex # OTP supervision tree (optional)
| `-- trust_web/
| `-- live/ # LiveView pages
|-- assets/ # TS/CSS (one bundle per plugin)
| |-- ts/ # TypeScript browser entry points
| |-- package.json # Optional build script used by dev + Guix packaging
| |-- tsconfig.json # TypeScript compiler settings
| `-- package-lock.json # Optional, recommended for reproducible builds
|-- priv/
| |-- static/ # Built assets for release
| `-- repo/migrations/ # Ecto migrations
|-- scripts/
| `-- plugin # Shared devenv/non-devenv test wrapper
`-- test/
Manifest
manifest.json declares your plugin's identity and capabilities:
{
"id": "org.tribe-one.plugins.trust",
"slug": "trust",
"display_name": "Trust",
"entry_module": "TribeOne.TribesPlugin.Trust.Plugin",
"host_api": "1",
"otp_app": "tribe_one_trust",
"provides": ["org.tribe-one.caps.some_capability@1"],
"requires": ["org.tribe-one.caps.ui@1"],
"enhances_with": ["org.tribe-one.caps.inference@1"]
}
- entry_module - must be a valid module ending in
.Plugin - otp_app - required OTP application name; vendor-prefix it to avoid collisions
- provides - capabilities this plugin makes available
- requires - hard plugin/API contracts (build fails without them)
- enhances_with - optional dependencies (plugin degrades gracefully)
The default generator includes org.tribe-one.caps.ui@1 because the generated LiveView renders
inside the host chrome through Tribes.Plugin.Layouts.app. Keep org.tribe-one.caps.ui@1 when a
plugin uses host chrome, imports Tribes.UI.Components, or uses use Tribes.UI.
Plugin Data
If your plugin adds Ash resources that should replicate cluster-wide, use
extensions: [AshNostrSync] on those resources and assign a sync lane per
resource. The host default lane is bulk; latency-sensitive topology or
orchestration resources should opt into control. Keep resource-specific
side effects explicit in actions.
Testing
The generated plugin starts with two host-backed test layers:
- Contract tests (
test/trust/plugin_contract_test.exs) - manifest and runtime spec stay aligned - Page tests (
test/trust/home_page_test.exs) - the plugin renders through the real host page pipeline
Run them with:
mix tribes.plugin.validate
scripts/plugin smoke
scripts/plugin test
Use plugin test / plugin precommit for host-backed tests. The helper invokes
Mix with the host database/services and host plugin-manager paths, including
built-in providers such as tribes_ui. Raw mix test in a plugin checkout is
guarded and prints this guidance; mix raw_test / mix raw_precommit are
available only for unusual manual debugging when you have set the same host
environment yourself.
Building for Release
MIX_ENV=prod mix compile
devenv shell -- npm run build --prefix assets
mkdir -p dist/trust
cp -r _build/prod/lib/tribe_one_trust/ebin dist/trust/
cp -r priv dist/trust/
cp manifest.json dist/trust/
Licence
TODO: Choose a licence.