Plugin Structure

File layout, manifest format, and data isolation for ANIMA plugins.

Directory Layout

A minimal plugin needs two files: plugin.toml and plugin.py. A full plugin looks like this:

my-plugin/
├── plugin.toml              # REQUIRED: manifest
├── plugin.py                # REQUIRED: AnimaPlugin subclass
├── config/
│   └── settings.toml        # Plugin-specific settings
├── corpus/                  # Default corpus documents (optional)
│   └── *.md, *.txt, *.pdf
├── dashboard/               # Web UI (optional)
│   ├── app.py               # Flask/FastAPI app
│   └── templates/
│       └── dashboard.html
├── requirements.txt         # Python dependencies (optional)
└── README.md

Required Files

Plugin Manifest (plugin.toml)

The manifest declares your plugin's identity, permissions, and routing preferences.

Full example

[plugin]
name = "my-plugin"                  # unique identifier (lowercase, hyphens)
version = "1.0.0"                   # semver
description = "What this plugin does"
author = "Author Name"
license = "free"                    # free | proprietary | pro_required
port = 8905                         # default web server port
min_core_version = "1.0.0"         # minimum ANIMA core version
max_core_version = "1.99.99"       # optional: max compatible version

[plugin.hub]                        # optional: for hub-published plugins
repository = "https://github.com/author/my-plugin"
categories = ["analysis", "science"]
screenshots = ["screens/overview.png", "screens/dashboard.png"]
price = "0"                         # "0" = free, "29.99" = one-time

[plugin.permissions]                # optional: declares what the plugin needs
network = ["api.example.com"]       # allowed external endpoints
filesystem = ["read:corpus/"]       # beyond own data dir
subprocess = false                  # can it spawn subprocesses?

[plugin.models]
required_roles = ["extraction"]     # at least one online model must have these
preferred_tier = "large"            # hint: large | medium | small

Task Routing

Define how this plugin's work gets routed to models:

[tasks.extraction]
reasoning = "low"                   # low | medium | high
prefer = "speed"                    # speed | quality
safe_fallback = true                # fall back to another model if busy

[tasks.dreams]
reasoning = "high"
prefer = "quality"

[tasks.chat]
reasoning = "medium"
prefer = "quality"
safe_fallback = true

Routing Modes

Control how models are assigned to this plugin:

[routing]
mode = "shared"                     # shared | scoped | prefer
assigned_models = ["local-primary", "cloud-assist"]
ModeBehavior
sharedUse any available model (default)
scopedOnly use assigned models
preferUse assigned first, fall back to shared pool

Governance

Governance controls what happens after beliefs pass quality gates. Add to your plugin's config/settings.toml:

[governance]
preset = "monarchy"                 # monarchy | llm | auto
PresetBehaviorUse Case
monarchyAll beliefs queued for human approvalResearch, knowledge work (default)
llmAuto-accept beliefs, manual corrections/lessonsCoding, supervised automation
autoAuto-accept everythingGame worlds, consumer plugins

Governance resolves to three capability flags:

allow_auto_accept = false          # auto-accept beliefs that pass quality gates
allow_auto_corrections = false     # auto-accept corrections without approval
allow_auto_lessons = false          # auto-accept lessons without approval

Quality gates always run. Governance only controls what happens after a belief passes all quality checks. A belief that fails triage is rejected regardless of governance preset.

Data Directory

Each plugin gets an isolated data directory at runtime. Plugins must not access other plugins' data.

~/.anima/data/{plugin-name}/
├── sqlite/
│   └── persistence.db       # Belief database (per-plugin instance)
├── chroma/                   # Vector embeddings
└── telemetry.db              # Cycle metrics

Isolation is enforced. Plugins must not access other plugins' data directories. All storage paths are injected by the core — never resolve paths from __file__.

Versioning

The plugin API follows semver:

Plugins declare min_core_version in plugin.toml. The core refuses to load plugins that require a newer version.