Repository navigation
Plugin Registry
aindy-runtime's plugin registry lets you extend the runtime with domain-specific
routers, flows, jobs, syscalls, capabilities, tools, and startup hooks — all from
an external Python package. This is how the 16 domain apps in aindy-apps-monolith
are mounted at boot time.
Plugins are discovered from aindy_plugins.json at the root of the deployment:
{
"profile": "default-apps",
"plugins": [
{"package": "aindy_sales", "enabled": true},
{"package": "aindy_analytics", "enabled": true}
]
}Set AINDY_BOOT_MODE=runtime-only to skip plugin loading entirely and run the
runtime without any app layer.
A plugin package must expose an aindy_plugin entry point in pyproject.toml:
[project.entry-points."aindy.plugins"]
aindy_sales = "aindy_sales.plugin:register"The register function receives a PluginRegistry and calls the registration APIs.
Mount a FastAPI router at the /apps/ prefix:
from AINDY.platform_layer.registry import register_router
def register(registry):
from aindy_sales.routes import router
register_router(router, prefix="/apps/sales", tags=["sales"])Register a named flow definition:
from AINDY.platform_layer.registry import register_flow
def register(registry):
from aindy_sales.flows import quarterly_report_flow
register_flow("sales.quarterly_report", quarterly_report_flow)Register a named background job (appears in the distributed queue):
from AINDY.platform_layer.registry import register_job
def register(registry):
from aindy_sales.jobs import sync_crm_job
register_job("sales.sync_crm", sync_crm_job, schedule="0 */6 * * *")Register a new syscall handler:
from AINDY.platform_layer.registry import register_syscall
def register(registry):
from aindy_sales.syscalls import get_pipeline_handler
register_syscall(
name="sys.v1.sales.get_pipeline",
handler=get_pipeline_handler,
capabilities=["read_sales"],
idempotency="AT_LEAST_ONCE",
)Run code after the runtime finishes startup:
from AINDY.platform_layer.registry import register_startup_hook
def register(registry):
def on_startup(context):
context["log"].info("Sales plugin ready")
register_startup_hook(on_startup)Plugins can enrich agent runs in four ways:
| Enrichment type | What it does |
|---|---|
planner_context |
Injects domain context into the agent's planning prompt |
suggestions |
Provides suggested next actions based on current state |
tool_catalog |
Adds domain-specific tools to the agent's tool list |
completion_hook |
Runs after the agent completes (for post-run orchestration) |
from AINDY.platform_layer.registry import register_planner_context_provider
def register(registry):
from aindy_sales.enrichment import sales_planner_context
register_planner_context_provider(sales_planner_context)Third-party plugin nodes run through the extension sandbox. In single-instance
mode, the default runner is insecure_dev_subprocess — suitable for first-party
trusted code only. For production deployments with third-party plugins, configure:
AINDY_PLUGIN_SANDBOX_RUNNER=containerized_oci
AINDY_PLUGIN_CONTAINER_IMAGE=your-sandbox-image:latestSee Security for the full sandbox policy.
Plugin code may import from AINDY.* runtime modules (routers, services, syscall
dispatch). The reverse is explicitly blocked — AINDY/ modules must not import
from apps.*. This boundary is enforced at startup via the router boundary validator.
Getting Started
Core Systems
Operations
Extending
Project