Events
Use the narrowest event: startup, agent detected, skill changed, prompt before submit, agent response, tool before/after use, session start/end.
OpenLeash features are ordered pipeline plugins. A plugin subscribes to narrow events, declares permissions and settings, uses stable capabilities, and returns typed results.
Agents emit hooks. OpenLeash normalizes them into events. The runtime runs the enabled plugins for that event in manifest order.
agent hook -> desktop local relay -> client-api -> OpenLeash event -> ordered plugin pipeline -> audit, approval, transformed prompt, or allow/deny response
Start with the manifest. It is the plugin's store card, permission request, config contract, and ordering hint.
export const manifest = {
id: "acme.prompt-labeler",
name: "Prompt Labeler",
version: "1.0.0",
publisher: "acme",
runtime: "node",
entrypoint: "src/index.ts",
events: ["prompt.beforeSubmit"],
permissions: ["event:read", "prompt:read", "audit:write"],
effects: ["observe"],
ordering: { priority: 250, after: ["openleash.dlp"] },
configSchema: {
type: "object",
additionalProperties: false,
properties: {
enabled: { type: "boolean" },
label: { type: "string" }
}
},
defaultConfig: { enabled: true, label: "reviewed" }
};Plugins do not import OpenLeash database modules, evaluators, API handlers, or model-key readers. They receive capabilities from the runtime.
export async function run(input, capabilities) {
if (!input.config.enabled) {
return { status: "skipped", summary: "Disabled." };
}
await capabilities.storage.set({
scope: { sessionId: input.event.sessionId },
key: "labels/latest",
value: { label: input.config.label, at: Date.now() },
ttlSeconds: 86400
});
return {
status: "passed",
summary: "Prompt labeled.",
findings: [{
title: "Prompt label",
severity: "info",
summary: input.config.label
}]
};
}Use the narrowest event: startup, agent detected, skill changed, prompt before submit, agent response, tool before/after use, session start/end.
Declare only what the plugin needs: prompt read/write, tool read, model invoke, storage, audit, log, signal, usage, decision, or notification.
Use plugin-scoped JSON storage. OpenLeash injects organization and plugin identity so plugins cannot read each other's state.
Plugins report normalized facts to OpenLeash. They do not write database rows or build their own reporting backend.
await capabilities.signals.emit({
kind: "security.finding",
severity: "high",
title: "Destructive command blocked",
decision: "blocked",
status: "contained",
correlationKeys: ["policy:prod-safety"]
});
await capabilities.usage.record({
kind: "llm.tokens",
provider: "openleash-evaluator",
inputTokens: 4200,
savedTokens: 1600,
estimatedCostUsd: 0.018
});The dashboard reads OpenLeash-owned signal records to show incidents, findings, affected employees, contained actions, and plugin sources.
Usage records power plugin and employee cost summaries without exposing provider keys or raw database access to plugins.
OpenLeash stamps organization, synced user, computer, runtime, and conversation context. Plugins cannot spoof those trusted fields.
General dashboards correlate plugin output through OpenLeash-owned context, not plugin-to-plugin database reads.
Show incidents, usage, and risky actions for one employee.
Connect prompt, tool, data protection, MCP, and rules-enforcer records.
Spot endpoint-specific agent behavior.
Let plugins add safe keys such as policy ids, secret categories, tools, or command classes.
The runtime resolves before/after dependencies first, then priority. This keeps transformations and checks deterministic.
prompt.beforeSubmit: openleash.prompt-compression -> openleash.dlp -> openleash.sensitive-access tool.beforeUse: openleash.sensitive-access -> openleash.blast-radius -> openleash.rules-enforcer -> openleash.mcp-scanner
Every plugin exposes settings through its manifest config schema. Solo users configure their own installed plugins. Organization admins choose installed plugins and defaults from the dashboard.
Plugins can keep private state without owning a database or raw SQL access. Use scoped storage for session memory, caches, heuristics, and notification dedupe.
const scope = {
sessionId: input.event.sessionId,
conversationId: input.event.conversationId
};
const previous = await capabilities.storage.get({
scope,
key: "notifications/customer-data-risk"
});
if (!previous) {
await capabilities.storage.set({
scope,
key: "notifications/customer-data-risk",
value: { shownAt: Date.now() },
ttlSeconds: 5 * 60 * 60
});
}These ship preinstalled today and also serve as reference implementations for plugin builders.
Token-saver rewrites noisy prompts with its own prompt/schema and reports savings.
Data-leakage-prevention owns masking/detection logic and emits secret detection signals.
Catches env-file reads, secret exposure, env dumps, and exfiltration attempts.
Guards destructive tools and broad data operations.
Evaluates natural-language rules with plugin-owned prompts and emits security findings.
Inventories MCP tool calls for audit, review, and dashboard correlation.
Observes agent skills and emits signals for suspicious instructions.
Exports events and plugin logs to configured SIEM targets.
Plugin examples and the preinstalled plugin repos live under the OpenLeash GitHub organization.