Plugin System

The Plugin System

Here is the architectural question that separates systems that survive from systems that calcify: how do you grow without changing what you are?

Obsidian ’s answer is Constitution Principle 11: extend without modifying core. The plugin system is not an afterthought. It is the primary mechanism for growth — capabilities are declared, not hard-coded. The system grows through plugins and hooks, not patches.

Architecture

Plugin Architecture

┌────────────────────────────────────────────────────────┐
│                    OBSIDIAN Core                        │
│  ┌──────────────────────────────────────────────────┐  │
│  │                Plugin Manager                     │  │
│  │  ┌──────────┐  ┌──────────┐  ┌───────────┐      │  │
│  │  │  Loader  │  │ Registry │  │ Lifecycle │      │  │
│  │  │  NPM     │  │  Types   │  │  Install  │      │  │
│  │  │  Local   │  │  Hooks   │  │  Enable   │      │  │
│  │  │  Git     │  │  APIs    │  │  Disable  │      │  │
│  │  └──────────┘  └──────────┘  └───────────┘      │  │
│  └──────────────────────────────────────────────────┘  │
│                         │                               │
│  ┌──────────────────────────────────────────────────┐  │
│  │                 Hook System                       │  │
│  │  agent:* │ task:* │ deploy:* │ config:* │ ...    │  │
│  └──────────────────────────────────────────────────┘  │
│                         │                               │
│  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐          │
│  │Plugin A│ │Plugin B│ │Plugin C│ │Plugin D│ ...      │
│  └────────┘ └────────┘ └────────┘ └────────┘          │
│       │          │          │          │                │
│  ┌────┴──────────┴──────────┴──────────┴────────┐     │
│  │              Plugin Sandbox                    │     │
│  │  Isolated V8 │ Limited FS │ Network Rules     │     │
│  └──────────────────────────────────────────────┘     │
└────────────────────────────────────────────────────────┘

The architecture follows five principles that are, by now, probably familiar:

  1. Isolation — plugins run in sandboxed environments, because extending the system should never compromise it
  2. Declarative — capabilities declared via manifest, not assumed through code
  3. Type-Safe — full TypeScript support with published types
  4. Lifecycle-Aware — proper initialization, activation, and cleanup
  5. Hot-Reloadable — plugins can be updated without restarting the system

Plugin Types

Obsidian supports twelve plugin types, each with specific capabilities and interfaces. This is not arbitrary complexity — each type corresponds to a genuine extension point in the system’s architecture.

Secret Provider Plugins

Add support for new secrets backends. Implement the SecretProvider interface and your custom secrets manager — Bitwarden, 1Password, CyberArk, whatever your organization uses — becomes a first-class citizen in Obsidian’s secrets routing layer.

Channel Plugins

Communication channels: Slack, Discord, email, Teams, PagerDuty. Each channel plugin implements send, receive, and declares its capabilities — threading, reactions, file attachments, rich text. The Agent mail system routes through these channels transparently.

LLM Provider Plugins

Add LLM backends. Ollama for local inference, custom fine-tuned models, proprietary APIs — anything that can complete a prompt becomes available for agent task execution. This is Constitution Principle 6 applied to the model landscape: no vendor lock-in.

Storage Plugins

S3, GCS, Azure Blob, local filesystem, MinIO. Storage backends for the Vault and artifact management. Like all plugin types, the interface is standardized — your agents never know which storage backend is behind the abstraction.

Deployment Plugins

Kubernetes, Vercel, AWS ECS, Fly.io, bare metal. Each deployment plugin implements deploy, rollback, status, logs, and health checks. The obs deploy commands work identically regardless of which plugin provides the actual deployment mechanism.

Monitoring Plugins

Datadog, Prometheus, Grafana, New Relic, custom dashboards. Metrics, traces, logs, and alerts routed through a standard interface. Constitution Principle 2 demands that everything be observable — monitoring plugins make that observation possible.

Command Plugins

Extend the obs CLI with custom commands. Database migrations, project scaffolding, domain-specific workflows — anything that should be a CLI command but does not belong in core.

Hook Plugins

The generic extension point. Register handlers for any system event — file writes, task completions, agent spawns, deployments — without providing a specific service type. Code quality checks, notification workflows, custom audit trails.

Agent Plugins

The most powerful type. Create entirely new agent types or modify existing agent behavior. A memory-enhanced agent plugin can wrap every agent with persistent vector-store memory. A custom agent factory can introduce domain-specific agent types that understand your organization’s workflows.

Theme, Auth, and Search Plugins

UI customization, authentication providers (OAuth, SAML, LDAP), and search backends (Elasticsearch, Meilisearch). Each fills a specific integration point with the same pattern: implement the interface, declare the permissions, register with the system.

The Plugin Manifest

Every plugin requires an obsidian-plugin.json manifest. This is the contract between the plugin and the system — what the plugin is, what it can do, what it needs access to, and when it should activate.

{
  "name": "@acme/obsidian-plugin-example",
  "version": "1.0.0",
  "type": "hook",
  "main": "./dist/index.js",

  "obsidian": {
    "minVersion": "1.0.0",
    "maxVersion": "2.0.0"
  },

  "permissions": [
    "file:read",
    "file:write:./plugin-data/**",
    "network:https://*.acme.com/*",
    "secrets:read:api-keys/plugin-*",
    "agent:message",
    "config:read"
  ],

  "hooks": [
    {
      "event": "task:completed",
      "handler": "onTaskCompleted",
      "priority": 50
    }
  ],

  "activationEvents": [
    "onStartup",
    "onCommand:example:hello"
  ]
}

The permissions model is granular and path-scoped. file:write:./plugin-data/** means the plugin can write — but only within its own data directory. secrets:read:api-keys/plugin-* means it can read secrets — but only those matching the pattern. network:https://*.acme.com/* means it can make HTTP requests — but only to your domain.

This is not arbitrary restriction. This is Constitutional Compliance applied to extensibility. Every plugin declares exactly what it needs. The sandbox enforces exactly that. No more.

Plugin Security

Plugins run inside sandboxes with enforced resource limits. CPU time, memory allocation, filesystem access, and network connectivity are all constrained by the manifest declarations and the sandbox configuration.

plugins:
  sandbox:
    enabled: true
    default_limits:
      max_memory_mb: 256
      max_cpu_percent: 25
      max_execution_ms: 30000
      max_open_files: 50
    filesystem:
      writable_paths:
        - "./plugin-data/${plugin.name}/**"
      readable_paths:
        - "./config/**"
        - "./src/**"
      denied_paths:
        - "./.env*"
        - "./secrets/**"
    network:
      allowed_hosts: []
      denied_hosts: ["169.254.169.254"]
      max_concurrent_connections: 10

The denied hosts list includes 169.254.169.254 — the cloud metadata endpoint — because a plugin that can reach your instance metadata can escalate its privileges beyond anything the manifest declares. This is security through boundaries, not through trust that plugin authors will behave.

Plugin Loading Sequence

The loading process is a nine-step pipeline with validation at every stage:

  1. Load manifest — parse obsidian-plugin.json
  2. Validate manifest — check against schema
  3. Check compatibility — verify Obsidian version constraints
  4. Verify permissions — confirm all declared permissions are acceptable
  5. Create sandbox — set up isolated execution environment
  6. Load code — import the plugin module within the sandbox
  7. Instantiate — create the plugin instance
  8. Inject API — provide the scoped Obsidian API
  9. Activate — register hooks and start the plugin

Any failure at any step aborts the load cleanly. A plugin that cannot load does not break the system. A plugin that loads incorrectly does not get registered. This is Systemic Integrity applied to extensibility.

The Plugin API

Plugins receive an ObsidianAPI instance — scoped to their declared permissions — that provides controlled access to configuration, secrets, the filesystem, the network, agents, tasks, events, logging, storage, and inter-plugin communication.

The API is not Obsidian’s internal API exposed directly. It is a mediated interface where every call passes through permission checks. A plugin with file:read but not file:write gets an fs API that throws on write attempts. A plugin without secrets:read gets a secrets API that returns nothing.

This is the fundamental guarantee: plugins cannot do what they have not declared. The Warden does not need to trust plugins, because the sandbox makes trust irrelevant.

Publishing and Distribution

Plugins are distributed through npm, git repositories, or local paths. The CLI handles installation:

obs plugins install @obsidian/plugin-slack
obs plugins install --git https://github.com/acme/custom-plugin.git
obs plugins install --local ./my-plugin

Published plugins include checksums and signature verification. The registry tracks compatibility reports, download counts, and the Constitutional Compliance status of each plugin version. Because an ecosystem is only as strong as the weakest extension it allows.

Why This Matters

Most plugin systems are afterthoughts — a set of hooks bolted onto a system that was designed to work without them. Obsidian’s plugin system is the opposite. It is designed so that even core functionality could be a plugin. The secret providers are plugins. The deployment targets are plugins. The monitoring integrations are plugins.

This is not theoretical purity. This is operational resilience. When everything is a plugin, nothing is a special case. When nothing is a special case, Fractal Delegation works at every scale. And when fractal delegation works at every scale, you have a system that grows without breaking — which is the only kind of system worth building.