Plugin architecture

Shipped in v3-alpha (Beta). The @mnemosyne/plugins interface (9 builtins) lets third parties extend Mnemosyne without forking. Interfaces may still change before 3.0 stable.

The interface

interface MnemoPlugin {
  name: string;
  version: string;
  description: string;
 
  // Lifecycle
  onInit?(ctx: PluginContext): Promise<void>;
  onShutdown?(): Promise<void>;
  onHealthCheck?(): Promise<PluginHealth>;
 
  // Write-path hooks (can modify pipeline)
  onBeforeWrite?(unit: KnowledgeUnit): KnowledgeUnit | null;  // null = reject
  onAfterWrite?(unit: KnowledgeUnit): void;
 
  // Read-path hooks
  onBeforeRecall?(input: RecallInput): RecallInput;
  onAfterRecall?(hits: RecallHit[]): RecallHit[];
 
  // Event hooks (async)
  onFactCreated?(fact: MnemoFact): Promise<void>;
  onTaskCompleted?(task: MnemoTask): Promise<void>;
  onSessionCollapsed?(s: SessionCollapseSummary): Promise<void>;
  onConflictDetected?(c: FactConflict): Promise<void>;
  onWorthChanged?(memoryId: string, newWorth: number): Promise<void>;
 
  // Polling sync
  syncInterval?: number;
  sync?(): Promise<SyncResult>;
 
  // Verification (codebase-aware)
  verify?(facts: MnemoFact[]): Promise<VerificationResult[]>;
}

Built-in plugins shipped with v3

PluginPurposeDirectionTrigger
git-verifierVerify facts against repo staterepo → invalidate stale factsdaily cron
outline-syncImport KB articlesOutline → factswebhook + interval
webhook-notifyPush events to external systemsmemory → HTTPon event
obsidian-exportExport graph as Markdown vaultmemory → .mdon demand
claude-importImport from Claude’s memoryJSON → factson demand
slack-eventsRecord Slack messages as eventsSlack → eventswebhook
github-eventsRecord PR/Issue activityGitHub → events + taskswebhook
calendar-syncImport calendar eventsGoogle/Outlook → episodesinterval
feedback-loopUser feedback → memory worthUI rating → worth updateon feedback

Sandbox

Plugins run in the same process but with constrained access:

interface PluginContext {
  // Read-only memory access (through agent RBAC)
  recall(query: string): Promise<RecallHit[]>;
  getFact(id: string): Promise<MnemoFact | null>;
 
  // Write access — rate-limited, audited
  createFact(input: CreateFactInput): Promise<MnemoFact>;
  createEvent(input: CreateEventInput): Promise<MnemoEvent>;
 
  // NO access to:
  // - Raw database connection
  // - Other workspaces
  // - Admin operations
  // - Other plugins' state
 
  // Private state — persisted in mnemo_plugin_state
  state: PluginStateStore;
  log: PluginLogger;
}

See also