Rename Kobold and Trust plugin identity references to tribe-one-prefixed slugs across runtime API, e2e fixtures, and docs.
Kobold
Distributed dataset and lightweight data-application plugin for Tribes OS.
Getting Started
- Edit
manifest.json- set description, capabilities, requirements - Implement your plugin in
lib/kobold/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-kobold plugins/kobold
# 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-kobold
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.TribeOneTribesPluginKoboldExample = {
mounted() {
console.info("kobold hook mounted");
}
};
Keep the compiled JS file listed in manifest.json assets.global_js so it
loads before the host LiveSocket connects.
Project Structure
kobold/
|-- manifest.json # Plugin metadata (Nix build + runtime)
|-- mix.exs # Dependencies
|-- config/ # Host-backed test config
|-- lib/
| |-- kobold/
| | |-- plugin.ex # Tribes.Plugin entry point
| | `-- application.ex # OTP supervision tree (optional)
| `-- kobold_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.kobold",
"slug": "tribe-one-kobold",
"display_name": "Kobold",
"entry_module": "TribeOne.TribesPlugin.Kobold.Plugin",
"host_api": "1",
"otp_app": "tribe_one_kobold",
"provides": ["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, vendor-prefixed Mix application name
- 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/kobold/plugin_contract_test.exs) - manifest and runtime spec stay aligned - Page tests (
test/kobold/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/kobold
cp -r _build/prod/lib/kobold/ebin dist/kobold/
cp -r priv dist/kobold/
cp manifest.json dist/kobold/
Licence
TODO: Choose a licence.